php – 精简上传到S3存储桶获取405方法不允许错误

前端之家收集整理的这篇文章主要介绍了php – 精简上传到S3存储桶获取405方法不允许错误前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我一直在撞墙撞墙,完全被难倒了.我正在尝试使用FineUploader将文件直接上传到我的Amazon S3存储桶.我基本上已经从fineuploader.com网页(直接上传文件到Amazon S3)和服务器端 PHP复制了代码.

当我尝试上传文件时,我看到签名端点的帖子似乎成功运行但是当它尝试上传到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

该软件看起来很神奇,但我无法超越这个.任何帮助表示赞赏.

我猜这是将您的自定义域名映射到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更改,看起来S3正在接受POST请求.

原文链接:https://www.f2er.com/php/134435.html

猜你在找的PHP相关文章