6

私はこれに対して壁に頭を打つことがあり、完全に困惑しています。私はFineUploaderを使用してAmazon S3バケットに直接ファイルをアップロードしようとしています。私は本質的に、AmazonのS3に直接ファイルをアップロードするfineuploader.comのWebページとサーバサイドのPHPからコードをコピーしました。S3アップスケーラーからS3バケットへの取得方法が許可されていないエラー

ファイルをアップロードしようとすると、署名エンドポイントへの投稿が正常に動作しているように見えますが、S3にアップロードしようとすると405の「メソッドが許可されていません」というエラーが表示されます。

HTML

<!DOCTYPE html> 
<html > 
<head > 
    <meta charset = "utf-8" > 
    <link href = "http://fineuploader.com/source/fineuploader-3.9.1.min.css" rel = "stylesheet" > 
</head > 
<body > 
<div id = "fine-uploader" ></div > 

<script src = "http://code.jquery.com/jquery-latest.js" ></script > 
<script src = "js/uploader.js" ></script > 
<script > 
    $(document).ready(function() { 
     $("#fine-uploader").fineUploaderS3({ 
      debug: true, 
      request: { 
       endpoint: 'upload.roughdrag.com', 
       accessKey: 'AKIAJL37USSCV......' 
      }, 

      signature: { 
       endpoint: 'handlers/uploadHandler.php' 
      }, 
      uploadSuccess: { 
       endpoint: 'index.php' 
      }, 
      iframeSupport: { 
       localBlankPagePath: 'blank.html' 
      }, 
      retry: { 
       enableAuto: true // defaults to false 
      }, 

      paste: { 
       targetElement: $(document), 
       promptForName: true 
      }, 

      deleteFile: { 
       enabled: true, 
       endpoint: 'handlers/uploadHandler.php' 
      } 
     }); 
    }); 
</script > 
</body > 
</html > 

PHP署名エンドポイント - uploadHandler.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('../../includes/functions.php'); 
use Aws\S3\S3Client; 

// These assume you have the associated AWS keys stored in 
// the associated system environment variables 
$clientPrivateKey = '{removed}'; 
// 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 = '{removed}'; 
$serverPrivateKey = '{removed}'; 

// The following variables are used when validating the policy document 
// sent by the uploader: 
$expectedBucketName = "upload.roughdrag.com"; 
// $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 = 5000000; 

$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://www.roughdrag.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" => "Your 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']; 
} 

?> 

Amazon S3の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> 

IAMグループのセキュリティポリシー

{ 
    "Version":"2012-10-17", 
    "Statement":[{ 
    "Effect":"Allow", 
    "Action":"s3:PutObject", 
    "Resource":"arn:aws:s3:::upload.roughdrag.com/*" 
    }] 
} 

uploader.jsは、ソフトウェアは素晴らしい見えますが、私はただ過去を取得することはできませんhttp://fineuploader.com/source/all.fineuploader-3.9.1.min.js

コンソール応答

[FineUploader 3.9.0-3] Grabbed 1 dropped files. 

[FineUploader 3.9.0-3] Received 1 files or inputs. 

[FineUploader 3.9.0-3] Submitting S3 signature request for 0 

[FineUploader 3.9.0-3] Sending POST request for 0 

POST http://www.roughdrag.com/handlers/uploadHandler.php 200 OK 195ms 

[FineUploader 3.9.0-3] Sending upload request for 0 

POST http://upload.roughdrag.com/ 405 Method Not Allowed 559ms 

"NetworkError: 405 Method Not Allowed - http://upload.roughdrag.com/" 

[FineUploader 3.9.0-3] Received response status 405 with body: <html> 
<head><title>405 Method Not Allowed</title></head> 
<body> 
<h1>405 Method Not Allowed</h1> 
<ul> 
<li>Code: MethodNotAllowed</li> 
<li>Message: The specified method is not allowed against this resource.</li> 
<li>ResourceType: OBJECT</li> 
<li>Method: POST</li> 
<li>RequestId: 3493FE605B461EAF</li> 
<li>HostId: HDXmtSpHufy6LDIH1Nsp0oYkLDvTC3XKFRRIadw66gmaMsF53Z3WYsCWooOoRcw2</li> 
</ul> 
<hr/> 
</body> 
</html> 

[FineUploader 3.9.0-3] Waiting 5 seconds before retrying breakout.jpg... 

[FineUploader 3.9.0-3] Detected valid cancel, retry, or delete click event on file 'breakout.jpg', ID: 0. 

[FineUploader 3.9.0-3] Cancelling 0 

からキャプチャされましたこの。どんな助けもありがとうございます。

答えて

4

これは、S3バケットにカスタムドメイン名をマップしたときに作成されたDNSの問題だと思います。 upload.roughdrag.comを解決したら、このCNAMEを "upload.roughdrag.com.s3-website-us-east-1.amazonaws.com"にマップしたようです。代わりにCNAMEを "upload.roughdrag.com.s3.amazaonaws.com"にマッピングしてみてください。

アップデート1:

あなたはまだ、この変更後の問題を見ている場合は、私がAWS S3 forumsに投稿します。うまくいけば従業員が答えます。あなたのバケツ/ CNAMEに問題があり、私の最後からは見えません。 upload.roughdrag.com.s3.amazonaws.comへのPOST要求が行われるようですが、upload.roughdrag.comにPOST要求を送信する際に問題があります。私はこれをPostmanと確認しました。

アップデート2:

最新のCNAME変更によりPOSTリクエストはS3で受け入れられているように、それが見えます。

+3

これは問題でした。「静的ウェブサイトホスティング」のバケットプロパティは、upload.roughdrag.com.s3.amazonawsに変更した時点で、エンドポイントをupload.roughdrag.com.s3-website-us-east-1.amazonaws.comとして指定します。 comこれは私のために働き始めた。どうもありがとうございました。 – jjj916

+0

私は元のポスターと非常によく似た状況にあります。私のDNS設定を共有できますか?そして、あなたはDNSのためにAmazonを使っていますか?私はバケツのエンドポイント 'BUCKETNAME.s3-website-us-east-1.amazonaws.com'に' uploads.mydomain.com'をマッピングしています。 – Colin

+0

"upload.roughdrag.comを解決した後、このCNAMEを" upload.roughdrag.com.s3-website-us-east-1.amazonaws.com "にマップしたようです。そのCNAMEを" upload.roughdrag "にマッピングしてみてください.com.s3.amazaonaws.com "代わりに" - 私のために働いた – jaspreet21anand

1

私は同じ問題がありました。以下の関数に領域を追加することで修正しました。

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

    return S3Client::factory(array(
     'key' => $serverPublicKey, 
     'secret' => $serverPrivateKey, 
     'region' => 'ap-southeast-2' //Revomve from non Sydney bucket 
    )); 
} 

プロパティをクリックしてバケットの領域を探します。その後、スタティックウェブサイトのホスティングは、エンドポイントからの詳細をap-xxxxx-xから取得するだけです

関連する問題