2013-08-21 73 views
3

我现在试图设置fineuploader-s3来显示成功上传到aws服务器上的文件的图像,如在此处的示例页面上所做的那样: http://fineuploader.com/#s3-demo无法显示上传到亚马逊s3的图像上传精细上传

我(仍然)使用代码为https://github.com/Widen/fine-uploader-server/blob/master/php/s3/s3demo.php,我已经添加

uploadSuccess: { 
     endpoint: "s3demo.php?success" 
    } 

到细上传比如在我的JavaScript文件,使临时链接应该由该函数生成在s3demo.php文件中。

我意识到我不得不安装AWS SDK才能使其工作。安装的zip方法确实无法正常工作,所以我正在使用phar。 我改变了s3demo.php文件的该部分:

require 'aws.phar'; 
use Aws\S3\S3Client; 

我也注释掉这两条线:

$serverPublicKey = $_SERVER['PARAM1']; 
$serverPrivateKey = $_SERVER['PARAM2']; 

我有在得到这个第一次work.The两个问题是什么我从AWS获得的成功响应出错了,我认为我应该获取该文件的链接。

文件上传完美,但我在控制台中的错误:

[FineUploader 3.8.0] Sending POST request for 0 s3.jquery.fineuploader-3.8.0.js:164 
[FineUploader 3.8.0] Received the following response body to an AWS upload success request for id 0: <br /> 
<b>Fatal error</b>: Uncaught exception 'Guzzle\Http\Exception\CurlException' with message '[curl] 28: Connection timed out after 1001 milliseconds [url] http://169.254.169.254/latest/meta-data/iam/security-credentials/' in phar:///MYSITE/aws.phar/Guzzle/Http/Curl/CurlMulti.php:339 
Stack trace: 
#0 phar:///MYSITE//aws.phar/Guzzle/Http/Curl/CurlMulti.php(280): Guzzle\Http\Curl\CurlMulti-&gt;isCurlException(Object(Guzzle\Http\Message\Request), Object(Guzzle\Http\Curl\CurlHandle), Array) 
#1 phar:///MYSITE//aws.phar/Guzzle/Http/Curl/CurlMulti.php(245): Guzzle\Http\Curl\CurlMulti-&gt;processResponse(Object(Guzzle\Http\Message\Request), Object(Guzzle\Http\Curl\CurlHandle), Array) 
#2 phar:///MYSITE//aws.phar/Guzzle/Http/Curl/CurlMulti.php(228): Guzzle\Http\Curl\CurlMulti-&gt;processMessages() 
#3 phar:///MYSITE//aws.phar/Guzzle/Http/Curl/CurlMulti.php(212): Guzzle\Http\Curl\CurlMulti-&gt;executeHandles() 
#4 phar:///MYSITE/z/aw in <b>phar:///home/nextq2/public_html/lenz/aws.phar/Aws/Common/InstanceMetadata/InstanceMetadataClient.php</b> on line <b>82</b><br /> 
s3.jquery.fineuploader-3.8.0.js:164 
[FineUploader 3.8.0] Upload success was acknowledged by the server. s3.jquery.fineuploader-3.8.0.js:164 

这是否意味着有什么不对我的AWS SDK安装,或者在亚马逊我的权限设置?对于CORS和IAM设置?目前仍在如下:在IAM

<CORSRule> 
     <AllowedOrigin>MY WEBSITE</AllowedOrigin> 
     <AllowedMethod>POST</AllowedMethod> 
     <MaxAgeSeconds>3000</MaxAgeSeconds> 
     <AllowedHeader>*</AllowedHeader> 
    </CORSRule> 

我的组策略:

{ 
     "Version":"2012-10-17", 
     "Statement":[{ 
     "Effect":"Allow", 
     "Action":"s3:PutObject", 
     "Resource":"arn:aws:s3:::MY_BUCKET/*” 
     }] 
} 

的第二个问题,我敢肯定,我应该能够弄清楚,但不能,是怎么访问由我的JavaScript中的s3demo.php生成的json数组,以便我可以显示上传的图像。我想这不是$ templink [0]。我想知道是否有可能看到示例代码,它的功能http://fineuploader.com/#s3-demo上的视图按钮。如果我在这里提出第二个问题,我很乐意这样做。

非常感谢您的时间。

编辑添加的我的全部代码的要求:

PHP:

<?php 
/** 
* PHP Server-Side Example for Fine Uploader S3. 
* Maintained by Widen Enterprises. 
* 
* Note: This is the exact server-side code used by the S3 example 
* on fineuploader.com. 
* 
* This example: 
* - handles both CORS and non-CORS environments 
* - handles delete file requests for both DELETE and POST methods 
* - Performs basic inspections on the policy documents and REST headers before signing them 
* - Ensures again the file size does not exceed the max (after file is in S3) 
* - signs policy documents (simple uploads) and REST requests 
* (chunked/multipart uploads) 
* 
* Requirements: 
* - PHP 5.3 or newer 
* - Amazon PHP SDK (only if utilizing the AWS SDK for deleting files or otherwise examining them) 
* 
* If you need to install the AWS SDK, see http://docs.aws.amazon.com/aws-sdk-php-2/guide/latest/installation.html. 
*/ 

// You can remove these two lines if you are not using Fine Uploader's 
// delete file feature 

require 'aws/aws-autoloader.php'; 
use Aws\S3\S3Client; 


// These assume you have the associated AWS keys stored in 
// the associated system environment variables 
$clientPrivateKey = ‘I put my private key here; 
// These two keys are only needed if the delete file feature is enabled 
// or if you are, for example, confirming the file size in a successEndpoint 
// handler via S3's SDK, as we are doing in this example. 
$serverPublicKey = $_SERVER['PARAM1']; 
$serverPrivateKey = $_SERVER['PARAM2']; 

$expectedMaxSize = 15000000; 
$expectedBucket = “my bucket name here; 

$method = getRequestMethod(); 

// This first conditional will only ever evaluate to true in a 
// CORS environment 
if ($method == 'OPTIONS') { 
    handlePreflight(); 
} 
// This second conditional will only ever evaluate to true if 
// the delete file feature is enabled 
else if ($method == "DELETE") { 
    // handlePreflightedRequest(); // only needed in a CORS environment 
    deleteObject(); 
} 
// This is all you really need if not using the delete file feature 
// and not working in a CORS environment 
else if ($method == 'POST') { 
    handlePreflightedRequest(); 

    // Assumes the successEndpoint has a parameter of "success" associated with it, 
    // to allow the server to differentiate between a successEndpoint request 
    // and other POST requests (all requests are sent to the same endpoint in this example). 
    // This condition is not needed if you don't require a callback on upload success. 
    if (isset($_REQUEST["success"])) { 
     verifyFileInS3(); 
    } 
    else { 
     signRequest(); 
    } 
} 

// This will retrieve the "intended" request method. Normally, this is the 
// actual method of the request. Sometimes, though, the intended request method 
// must be hidden in the parameters of the request. For example, when attempting to 
// send a DELETE request in a cross-origin environment in IE9 or older, it is not 
// possible to send a DELETE request. So, we send a POST with the intended method, 
// DELETE, in a "_method" parameter. 
function getRequestMethod() { 
    global $HTTP_RAW_POST_DATA; 

    // This should only evaluate to true if the Content-Type is undefined 
    // or unrecognized, such as when XDomainRequest has been used to 
    // send the request. 
    if(isset($HTTP_RAW_POST_DATA)) { 
     parse_str($HTTP_RAW_POST_DATA, $_POST); 
    } 

    if ($_POST['_method'] != null) { 
     return $_POST['_method']; 
    } 

    return $_SERVER['REQUEST_METHOD']; 
} 

// Only needed in cross-origin setups 
function handlePreflightedRequest() { 
    // If you are relying on CORS, you will need to adjust the allowed domain here. 
    //header('Access-Control-Allow-Origin: http://nextquestion.org'); 
} 

// Only needed in cross-origin setups 
function handlePreflight() { 
    handlePreflightedRequest(); 
    header('Access-Control-Allow-Methods: POST'); 
    header('Access-Control-Allow-Headers: Content-Type'); 
} 

function getS3Client() { 
    global $serverPublicKey, $serverPrivateKey; 

    return S3Client::factory(array(
     'key' => $serverPublicKey, 
     'secret' => $serverPrivateKey 
    )); 
} 

// Only needed if the delete file feature is enabled 
function deleteObject() { 
    getS3Client()->deleteObject(array(
     'Bucket' => $_POST['bucket'], 
     'Key' => $_POST['key'] 
    )); 
} 

function signRequest() { 
    header('Content-Type: application/json'); 

    $responseBody = file_get_contents('php://input'); 
    $contentAsObject = json_decode($responseBody, true); 
    $jsonContent = json_encode($contentAsObject); 

    $headersStr = $contentAsObject["headers"]; 
    if ($headersStr) { 
     signRestRequest($headersStr); 
    } 
    else { 
     signPolicy($jsonContent); 
    } 
} 

function signRestRequest($headersStr) { 
    if (isValidRestRequest($headersStr)) { 
     $response = array('signature' => sign($headersStr)); 
     echo json_encode($response); 
    } 
    else { 
     echo json_encode(array("invalid" => true)); 
    } 
} 

function isValidRestRequest($headersStr) { 
    global $expectedBucket; 

    $pattern = "/\/$expectedBucket\/.+$/"; 
    preg_match($pattern, $headersStr, $matches); 

    return count($matches) > 0; 
} 

function signPolicy($policyStr) { 
    $policyObj = json_decode($policyStr, true); 

    if (isPolicyValid($policyObj)) { 
     $encodedPolicy = base64_encode($policyStr); 
     $response = array('policy' => $encodedPolicy, 'signature' => sign($encodedPolicy)); 
     echo json_encode($response); 
    } 
    else { 
     echo json_encode(array("invalid" => true)); 
    } 
} 

function isPolicyValid($policy) { 
    global $expectedMaxSize, $expectedBucket; 

    $conditions = $policy["conditions"]; 
    $bucket = null; 
    $parsedMaxSize = null; 

    for ($i = 0; $i < count($conditions); ++$i) { 
     $condition = $conditions[$i]; 

     if (isset($condition["bucket"])) { 
      $bucket = $condition["bucket"]; 
     } 
     else if (isset($condition[0]) && $condition[0] == "content-length-range") { 
      $parsedMaxSize = $condition[2]; 
     } 
    } 

    return $bucket == $expectedBucket && $parsedMaxSize == (string)$expectedMaxSize; 
} 

function sign($stringToSign) { 
    global $clientPrivateKey; 

    return base64_encode(hash_hmac(
      'sha1', 
      $stringToSign, 
      $clientPrivateKey, 
      true 
     )); 
} 

// This is not needed if you don't require a callback on upload success. 
function verifyFileInS3() { 
    global $expectedMaxSize; 

    $bucket = $_POST["bucket"]; 
    $key = $_POST["key"]; 

    // If utilizing CORS, we return a 200 response with the error message in the body 
    // to ensure Fine Uploader can parse the error message in IE9 and IE8, 
    // since XDomainRequest is used on those browsers for CORS requests. XDomainRequest 
    // does not allow access to the response body for non-success responses. 
    if (getObjectSize($bucket, $key) > $expectedMaxSize) { 
     // You can safely uncomment this next line if you are not depending on CORS 
     //header("HTTP/1.0 500 Internal Server Error"); 
     deleteObject(); 
     echo json_encode(array("error" => "File is too big!")); 
    } 
    else { 
     echo json_encode(array("tempLink" => getTempLink($bucket, $key))); 
    } 
} 
function testfunction(){ 
    alert('whatever'); 
} 
// Provide a time-bombed public link to the file. 
function getTempLink($bucket, $key) { 
    $client = getS3Client(); 
    $url = "{$bucket}/{$key}"; 
    $request = $client->get($url); 

    return $client->createPresignedUrl($request, '+15 minutes'); 
} 

function getObjectSize($bucket, $key) { 
    $objInfo = getS3Client()->headObject(array(
      'Bucket' => $bucket, 
      'Key' => $key 
     )); 
    return $objInfo['ContentLength']; 
} 
?> 

我的HTML。我用另一个例子,马克曾在计算器上进行这个测试,因为最终我要同时提交其他一些数据:

<!DOCTYPE html> 
<html> 
<head> 

    <title>test of fine uploader</title> 
    <meta charset="utf-8" /> 
    <meta name="viewport" content="width=device-width, initial-scale=1"> 


    <link href="fineuploader-3.8.0.css" rel="stylesheet"> 
    <style> 
    .button { 
     display: block; 
     height: 30px; 
     width: 100px; 
     border: 1px solid #000; 
    } 
    </style> 
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script> 
<script src="s3.jquery.fineuploader-3.8.0.js"></script> 
<script type="text/javascript" src="lenz_javascript4.js"></script> 

</head> 
<body> 

<!-- Generated Image Thumbnail --> 
<a href="#" id="thumbnail">view image</a> 

<form action="fineuploadertest.php" method="post" id="uploader"> 
<input type="text" name="textbox" value="Test data"> 
    <div id="manual-fine-uploader"></div> 
    <div id="triggerUpload" class="button" style="margin-top: 10px;">click here 
    </div> 
</form> 

</body> 
</html> 

我的javascript:

$(document).ready(function() { 

    $("#triggerUpload").click(function() { 
     $("#manual-fine-uploader").fineUploaderS3('uploadStoredFiles'); 
    }); 

    function submitForm() { 
     if ($(this).fineUploader('getInProgress') == 0) { 
      var failedUploads = $(this).fineUploaderS3('getUploads', 
       { status: qq.status.UPLOAD_FAILED }); 
      if (failedUploads.length == 0) {  
       // do any other form processing here 
       $("#uploader").submit(); 
      } 
     } 
    }; 


    $("#manual-fine-uploader").fineUploaderS3({ 
     autoUpload: false, 
     debug: true, 

       request: { 

        endpoint: "http://my bucket name.s3.amazonaws.com", 

        accessKey: “I put my access key here” 
       }, 
       validation: { 
        allowedExtensions: ['jpeg', 'jpg', 'gif', 'png'], 
        sizeLimit: 15000000, 
        itemLimit: 3 
       }, 

       signature: { 

        endpoint: "s3demo.php" 
       }, 
      camera: { 
       ios: true 
      }, 
       iframeSupport: { 
        localBlankPagePath: "/success.html" 
       }, 
       uploadSuccess: { 
     endpoint: "s3demo.php?success" 

    } 
    }); 
}); 
+0

看起来像是安装了AWS SDK和/或其依赖项的东西。我敢打赌,每次运行PHP脚本时(即每次它在这种情况下收到HTTP请求时)都会尝试在[第25和26行](https://github.com)上“要求”和“使用”SDK /Widen/fine-uploader-server/blob/master/php/s3/s3demo.php#L25)。你能否仅仅注释这些行,并关闭删除文件功能以缩小问题的范围? –

+0

我遇到了其他PHP安装程序的问题,但使用zip最适合我。我刚刚在's3demo.php'脚本的同一个文件夹中有一个'aws'目录。 –

+0

我其实已经有删除文件已关闭。然后,在我将第25行和第26行注释掉之前,然后我在控制台中收到此错误(取出标签以便在此处可读): [FineUploader 3.8.0]将以下响应正文接收到了AWS上传成功请求ID 0: 致命错误:在第112行的s3demo.php中找不到类'S3Client'。 因此,我决定取消注释第25行和第26行,然后收到上面显示的错误。 –

回答

4

这听起来像你只是想反映FineUploader.com上S3演示的行为。所以,你显然遇到麻烦的部分是演示的一部分,它允许你查看/下载你上传的文件。我的猜测是你没有设置PARAM1PARAM2环境变量。您应该仔细看看PHP文档中的超级全局工作方式。现在,这个代码希望您拥有一个名为PARAM1的系统环境变量,该变量保存与您应该为您的服务器(而不是您的客户端)创建的IAM用户关联的公用AWS密钥以供使用。系统环境变量PARAM2应该设置为该用户的密钥。您可以设置这些环境变量,也可以分别将关联的$serverPublicKey$serverPrivateKey PHP全局变量设置为服务器端IAM用户的公共密钥和密钥。

注意,对于服务器的AWS公钥和密钥(PARAM1PARAM2)相关联的系统环境变量可怜的名字的选择是由于这样的事实,对于fineuploader.com S3演示服务器上创建一个AWS EC2 instance运行由Amazon's Elastic Beanstalk service。 Elastic Beanstalk不提供(至少它不明显提供)通过Elastic Beanstalk UI为PHP应用程序命名系​​统环境变量的方法。它的名字他们PARAM1PARAM2

$serverPublicKey$serverPrivateKey变量不应该与你的客户端任务创建的IAM用户相关联的相同的密钥。您应该创建了一个具有适合于服务器端任务的权限的不同IAM用户。例如,如果您要支持删除文件功能,您将希望拥有具有“S3:DeleteObject”权限的IAM用户。此用户应仅限于服务器端任务,仅出于安全原因。

对于您的情况,您的服务器端IAM用户必须在您的存储桶上具有“S3:GetObject”权限。此权限是必需的,才能从您的存储桶中获取对象。最安全的方法是仅将此权限授予您的服务器端IAM用户。您可能会问:“如果我的客户端用户无法从我的存储桶中读取对象,我该如何允许将该文件下载到客户端?”那么,一种选择是将Fine Uploader中的acl选项设置为“public-read”,然后使用以下约定构造一个URL客户端:“http://mybucket.s3.amazonaws.com/objectkey”。这不是fineuploader.com上的S3演示的工作方式。阅读详细信息...

我不想让用户无限制地访问他们上传到Fine Uploader的S3存储桶的文件,因此我将acl保留为“private”(默认值),我只给了我的服务器端IAM用户对Fine Uploader S3存储桶的“S3:GetObject”权限,并且我让服务器向存储桶中的关联对象返回“定时炸弹”签名的URL。服务器返回的URL包含仅允许在15分钟内使用的过期参数。任何尝试在查询字符串中更改该过期参数都将使签名无效,并且请求将失败。 PHP示例中的getTempLink函数将生成一个定时炸弹的签名URL,它将在对Fine Uploader的uploadSucess.endpoint POST请求的响应中返回。您可以通过提供complete event handler来访问此值。传递到回调中的responseJSON对象参数将包含一个tempLink属性,该属性将包含签名的URL。然后,您可以生成一个将src属性设置为此属性值的锚点。

+1

谢谢,我在想它一定是PARAM1和PARAM2变量,但我不知道它们应该是什么。现在我明白了,谢谢你非常清楚的解释。 –

+0

很高兴我能帮到你。为了帮助未来的集成商,@MarkFeltner和我可能会在与这些变量相关的服务器端示例中添加更多注释,以确保明确他们的角色。 –

+0

阅读完本文后,我终于明白,您需要拥有一组2个密钥对。一个基于账户(服务器密钥)和一个基于IAM(客户端密钥)。现在,我可以在上传后实际查看这些文件,谢谢! –