2013-09-24 71 views
0

當前頁:http://www.typhooncloud.com/fineuploader精細上傳無效響應

當試圖上傳一個簡單的JPG文件,我收到錯誤:「無效的政策文件或請求頭」

這裏是我的index.html,s3handler.php,CORS試圖上傳後的政策和控制檯輸出。

已經建議所有已經作了修改。

HTML:

<!DOCTYPE html> 
    <head> 
     <link href="http://typhooncloud.com/fineuploader/fineuploader-3.9.0-3.css" rel="stylesheet"> 
    </head> 
    <body> 

     <!-- The element where Fine Uploader will exist. --> 
     <div id="fine-uploader"> 
     </div> 

     <!-- jQuery version 1.10.x (if you are using the jQuery plugin --> 
     <script src="http://code.jquery.com/jquery-1.10.2.min.js" type="text/javascript"></script> 

     <!-- Fine Uploader-jQuery --> 
     <script src="http://typhooncloud.com/fineuploader/s3.jquery.fineuploader-3.9.0-3.js"></script> 

     <script type="text/javascript"> 
      $(document).ready(function() 
      { 
       $('#fine-uploader').fineUploaderS3({ 
        debug: true, 

        request: { 
         endpoint: "getalink1001.s3.amazonaws.com", 
         accessKey: "MYACCESSKEY" 
        }, 
        signature: { 
         endpoint: "http://typhooncloud.com/fineuploader/s3handler.php" 
        }, 
        uploadSuccess: { 
         endpoint: "http://typhooncloud.com/fineuploader/s3handler.php?success" 
        }, 
        iframeSupport: { 
         localBlankPagePath: "http://typhooncloud.com/fineuploader/success.html" 
        }, 
        validation: { 
         allowedExtensions: ["gif", "jpeg", "jpg", "png"], 
         acceptFiles: "image/gif, image/jpeg, image/png", 
         sizeLimit: 5000000, 
         itemLimit: 3 
        }, 
        retry: { 
         showButton: true 
        }, 
        chunking: { 
         enabled: true 
        }, 
        resume: { 
         enabled: true 
        }, 
        deleteFile: { 
         enabled: true, 
         method: "POST", 
         endpoint: "http://typhooncloud.com/fineuploader/s3handler.php" 
        }, 
        paste: { 
         targetElement: $(document), 
         promptForName: true 
        } 
       }); 
      }); 
     </script> 

    </body> 
    </html> 

SERVER:

<?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 = $_SERVER['MYSECRETKEY']; 
    // 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['MYPRIVATEKEY']; 
    $serverPrivateKey = $_SERVER['MYSECRETKEY']; 

    // The following variables are used when validating the policy document 
    // sent by the uploader: 
    $expectedBucketName = "getalink1001"; 
    // $expectedMaxSize is the value you set the sizeLimit property of the 
    // validation option. We assume it is `null` here. If you are performing 
    // validation, then change this to match the integer value you specified 
    // otherwise your policy document will be invalid. 
    // http://docs.fineuploader.com/branch/develop/api/options.html#validation-option 
    $expectedMaxSize = 15000000; 

    $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") { 
     handleCorsRequest(); // 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') { 
     handleCorsRequest(); 

     // 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 handleCorsRequest() { 
     // If you are relying on CORS, you will need to adjust the allowed domain here. 
     header('Access-Control-Allow-Origin: http://typhoonupload.com'); 
    } 

    // Only needed in cross-origin setups 
    function handlePreflight() { 
     handleCorsRequest(); 
     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 $expectedBucketName; 

     $pattern = "/\/$expectedBucketName\/.+$/"; 
     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, $expectedBucketName; 

     $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 == $expectedBucketName && $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))); 
     } 
    } 

    // 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']; 
    } 
    ?> 

的CORS克埃政策如下:

<?xml version="1.0" encoding="UTF-8"?> 
    <CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/"> 
     <CORSRule> 
      <AllowedOrigin>*</AllowedOrigin> 
      <AllowedMethod>POST</AllowedMethod> 
      <AllowedMethod>PUT</AllowedMethod> 
      <AllowedMethod>DELETE</AllowedMethod> 
      <MaxAgeSeconds>3000</MaxAgeSeconds> 
      <ExposeHeader>ETag</ExposeHeader> 
      <AllowedHeader>*</AllowedHeader> 
     </CORSRule> 
    </CORSConfiguration> 

Chrome的控制檯:

 [FineUploader 3.9.0-3] Received 1 files or inputs. s3.jquery.fineuploader-3.9.0-3.js:164 
     [FineUploader 3.9.0-3] Submitting S3 signature request for 0 s3.jquery.fineuploader-3.9.0-3.js:164 
     [FineUploader 3.9.0-3] Sending POST request for 0 s3.jquery.fineuploader-3.9.0-3.js:164 
     [FineUploader 3.9.0-3] Invalid policy document or request headers! s3.jquery.fineuploader-3.9.0-3.js:169 
     [FineUploader 3.9.0-3] Policy signing failed. Invalid policy document or request headers! s3.jquery.fineuploader-3.9.0-3.js:169 
     [FineUploader 3.9.0-3] Received response status 0 with body: s3.jquery.fineuploader-3.9.0-3.js:164 
     [FineUploader 3.9.0-3] Upload attempt for file ID 0 to S3 is complete s3.jquery.fineuploader-3.9.0-3.js:164 

提琴手輸出:

 POST http://typhooncloud.com/fineuploader/s3handler.php HTTP/1.1 
     Host: typhooncloud.com 
     Connection: keep-alive 
     Content-Length: 287 
     Origin: http://typhooncloud.com 
     User-Agent: Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.76 Safari/537.36 
     Content-Type: application/json; charset=UTF-8 
     Accept: */* 
     Referer: http://typhooncloud.com/fineuploader/ 
     Accept-Encoding: gzip,deflate,sdch 
     Accept-Language: en-US,en;q=0.8 
     Cookie: __utma=33700260.900109978.1379619256.1379708113.1380038992.6; __utmb=33700260.1.10.1380038992; __utmc=33700260; __utmz=33700260.1380038992.6.2.utmcsr=stackoverflow.com|utmccn=(referral)|utmcmd=referral|utmcct=/questions/18971119/fine-uploader-invalid-response 
     AlexaToolbar-ALX_NS_PH: AlexaToolbar/alxg-3.2 

     {"expiration":"2013-09-24T16:26:35.948Z","conditions":[{"acl":"private"},{"bucket":"getalink1001"},{"Content-Type":"image/gif"},{"success_action_status":"200"},{"key":"f7e280c4-8cae-4bd7-82c4-d19e71186def.gif"},{"x-amz-meta-qqfilename":"319.gif"},["content-length-range","0","5000000"]]} 


     HTTP/1.1 200 OK 
     Date: Tue, 24 Sep 2013 16:21:49 GMT 
     Server: Apache 
     Access-Control-Allow-Origin: http://typhoonupload.com 
     Keep-Alive: timeout=5, max=100 
     Connection: Keep-Alive 
     Transfer-Encoding: chunked 
     Content-Type: application/json 

     10 
     {"invalid":true} 
     0 
+0

你必須提供比這更多的信息。看起來你只需複製並粘貼其中一個提供的服務器端示例。你甚至在跨越原點的環境中工作嗎?讓我們從啓用了debug選項的瀏覽器開發者控制檯的內容開始。 –

+0

我在上面的'控制檯輸出'中包含了,如果你願意的話,你當然可以自己試試,謝謝你。 – sthede

+0

編輯您的問題,包括從上面可以看出,仍然相同的結果設置爲true –

回答

2

它看起來就像當你複製並粘貼PHP示例服務器代碼,你忽略了一些調整值的。在這種情況下,handlePreflightedRequest方法未修改以反映您的域。

它應該閱讀:

function handlePreflightedRequest() { 
    // If you are relying on CORS, you will need to adjust the allowed domain here. 
    header('Access-Control-Allow-Origin: http://typhooncloud.com'); 
} 

此外,handlePreflightedRequest方法或許應該改名handleCorsRequest以避免混淆。我剛纔在服務器回購中已經完成了這項工作。你不需要這樣做,因爲它不會影響代碼的行爲。

+0

所做的更改調試選項控制檯輸出。 – sthede

+0

您也錯誤地修改了'handlePreflight'方法。刪除'Access-Control-Allow-Methods:PUT'和'Access-Control-Allow-Methods:DELETE'行。它不僅是不正確寫這個標題超過每一次迴應,精細上傳僅會發送POST請求到您的簽名服務器,假設你是以下的fineuploader.com示例代碼(這似乎是如此)。 –

+0

好吧,我只有在試圖增加這些額外的標題來得到它的工作,因爲沒有他們,這不是......請參見新的響應控制檯輸出,以及新文件本身...感謝你的幫助 – sthede

1

旁註。讓我指出一個關鍵的區別。在JavaScript代碼編寫sizeLimit: 5000000,但在PHP編寫$expectedMaxSize = 15000000。這些值必須完全匹配。