2013-08-21 75 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(客戶端密鑰)。現在,我可以在上傳後實際查看這些文件,謝謝! –