-1

I have been kicking around trying to implement the S3 uploader into my application and getting closer but no cigar. Here is my setup in a nutshell:

  • Running: 5.2.0 S3 with jQuery
  • Server: PHP 5.6.6 on ArchLinux
  • Max file size 25MB (defined in both s3.php and s3demo-cors.php)
  • Debug enabled: which just pops the Javascript alert with the XHR error code 0 message (can't seem to gain visibility into whats going on behind the scenes with debug or in the apache logs)
  • I specifically want to only use HTTPS for my bucket endpoint for security sake.
  • Testing with Google Chrome Version 42.0.2311.90 m and IE 11.0.9600
  • With Chrome it just fails, with IE it fails BUT it at least shows the progress meter for uploading the file, it hits 65% then fails.

I have followed the blog post here: http://blog.fineuploader.com/2013/08/16/fine-uploader-s3-upload-directly-to-amazon-s3-from-your-browser/ multiple times (hoping I am not missing something).

  • QUESTION: One thing I am curious about is the JSON policy and signing. I am not really seeing the code in the s3demo-cors.php example that creates the json formatted details perhaps I am missing that element?

I know my IAM permissions are valid because other PHP tests allow various PutObject and list commands successfully.

I have verified my CORS config is setup as follows for testing:

<?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>

I have a few files I am using for this:

s3.php = my test page with the fineuploader instance

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">

<!-- jQuery
====================================================================== -->
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>

<!-- Fine Uploader Gallery CSS file
====================================================================== -->
<link href="fine-uploader-gallery.css" rel="stylesheet">

<!-- Fine Uploader S3 jQuery JS file
====================================================================== -->
<script src="s3.jquery.fine-uploader.js"></script>

<!-- Fine Uploader Customized Gallery template
====================================================================== -->
<script type="text/template" id="qq-template-s3">
    <div class="qq-uploader-selector qq-uploader qq-gallery" qq-drop-area-text="Drop files here">
        <div class="qq-total-progress-bar-container-selector qq-total-progress-bar-container">
            <div role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" class="qq-total-progress-bar-selector qq-progress-bar qq-total-progress-bar"></div>
        </div>
        <div class="qq-upload-drop-area-selector qq-upload-drop-area" qq-hide-dropzone>
            <span class="qq-upload-drop-area-text-selector"></span>
        </div>
        <div class="qq-upload-button-selector qq-upload-button">
            <div>Upload a file</div>
        </div>
        <span class="qq-drop-processing-selector qq-drop-processing">
            <span>Processing dropped files...</span>
            <span class="qq-drop-processing-spinner-selector qq-drop-processing-spinner"></span>
        </span>
        <ul class="qq-upload-list-selector qq-upload-list" role="region" aria-live="polite" aria-relevant="additions removals">
            <li>
                <span role="status" class="qq-upload-status-text-selector qq-upload-status-text"></span>
                <div class="qq-progress-bar-container-selector qq-progress-bar-container">
                    <div role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" class="qq-progress-bar-selector qq-progress-bar"></div>
                </div>
                <span class="qq-upload-spinner-selector qq-upload-spinner"></span>
                <div class="qq-thumbnail-wrapper">
                    <a class="preview-link" target="_blank">
                        <img class="qq-thumbnail-selector" qq-max-size="120" qq-server-scale>
                    </a>
                </div>
                <button class="qq-upload-cancel-selector qq-upload-cancel">X</button>
                <button class="qq-upload-retry-selector qq-upload-retry">
                    <span class="qq-btn qq-retry-icon" aria-label="Retry"></span>
                    Retry
                </button>

                <div class="qq-file-info">
                    <div class="qq-file-name">
                        <span class="qq-upload-file-selector qq-upload-file"></span>
                        <span class="qq-edit-filename-icon-selector qq-edit-filename-icon" aria-label="Edit filename"></span>
                    </div>
                    <input class="qq-edit-filename-selector qq-edit-filename" tabindex="0" type="text">
                    <span class="qq-upload-size-selector qq-upload-size"></span>
                    <button class="qq-btn qq-upload-delete-selector qq-upload-delete">
                        <span class="qq-btn qq-delete-icon" aria-label="Delete"></span>
                    </button>
                    <button class="qq-btn qq-upload-pause-selector qq-upload-pause">
                        <span class="qq-btn qq-pause-icon" aria-label="Pause"></span>
                    </button>
                    <button class="qq-btn qq-upload-continue-selector qq-upload-continue">
                        <span class="qq-btn qq-continue-icon" aria-label="Continue"></span>
                    </button>
                </div>
            </li>
        </ul>

        <dialog class="qq-alert-dialog-selector">
            <div class="qq-dialog-message-selector"></div>
            <div class="qq-dialog-buttons">
                <button class="qq-cancel-button-selector">Close</button>
            </div>
        </dialog>

        <dialog class="qq-confirm-dialog-selector">
            <div class="qq-dialog-message-selector"></div>
            <div class="qq-dialog-buttons">
                <button class="qq-cancel-button-selector">No</button>
                <button class="qq-ok-button-selector">Yes</button>
            </div>
        </dialog>

        <dialog class="qq-prompt-dialog-selector">
            <div class="qq-dialog-message-selector"></div>
            <input type="text">
            <div class="qq-dialog-buttons">
                <button class="qq-cancel-button-selector">Cancel</button>
                <button class="qq-ok-button-selector">Ok</button>
            </div>
        </dialog>
    </div>
</script>

<style>
    #fine-uploader-s3 .preview-link {
        display: block;
        height: 100%;
        width: 100%;
    }
</style>

<title>Fine Uploader S3 Demo</title>
</head>
<body>
<!-- Fine Uploader DOM Element
====================================================================== -->
<div id="fine-uploader-s3"></div>

<!-- Your code to create an instance of Fine Uploader and bind to the     DOM/template
====================================================================== -->
<script>
$('#fine-uploader-s3').fineUploaderS3({
    debug: true,
    template: 'qq-template-s3',
    request: {
        endpoint: "https://s3.amazonaws.com/<HIDDEN>",
        accessKey: "<HIDDEN>"
    },
    signature: {
        endpoint: "s3demo-cors.php"
    },
    uploadSuccess: {
        endpoint: "s3demo-cors.php?success",
        params: {
            isBrowserPreviewCapable: qq.supportedFeatures.imagePreviews
        }
    },
    iframeSupport: {
        localBlankPagePath: "success.php"
    },
    cors: {
        expected: true
    },
    chunking: {
        enabled: true
    },
    resume: {
        enabled: true
    },
    retry: {
        enableAuto: true // defaults to false
    },
    deleteFile: {
        enabled: true,
        method: "POST",
        endpoint: "s3demo-cors.php"
    },
    validation: {
        itemLimit: 100,
        sizeLimit: 25000000
    },
    thumbnails: {
        placeholders: {
            notAvailablePath: "not_available-generic.png",
            waitingPath: "waiting-generic.png"
        }
    },
    callbacks: {
        onComplete: function(id, name, response) {
            var previewLink = qq(this.getItemByFileId(id)).getByClass('preview-link')[0];

            if (response.success) {
                previewLink.setAttribute("href", response.tempLink)
            }
        },
        onError: function(id, name, errorReason, xhrOrXdr) {
            alert(qq.format("Error on file number {} - {}.  Reason: {}", id, name, errorReason));
        }
    }
});
</script>
</body>
</html>

My PHP server side code is from your examples s3demo-cors.php (sorry code formatting got a little garbled when pasting in here)

    <?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)
*  - returns a thumbnailUrl in the response for older browsers so thumbnails can be displayed next to the file
*
* 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-autoloader.php';
require 'vendor/autoload.php';
use Aws\S3\S3Client;
// These assume you have the associated AWS keys stored in
// the associated system environment variables
$clientPrivateKey = '<HIDDEN>';
// 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'];
// The following variables are used when validating the policy document
// sent by the uploader: 
$expectedBucketName = "<HIDDEN>";
// $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 = 25000000;
$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(shouldIncludeThumbnail());
}
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 (isset($_POST['_method'])) {
    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: *');
}
// 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);
if (!empty($contentAsObject["headers"])) {
    signRestRequest($contentAsObject["headers"]);
}
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($includeThumbnail) {
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 (isset($expectedMaxSize) && 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!", "preventRetry" => true));
}
else {
    $link = getTempLink($bucket, $key);
    $response = array("tempLink" => $link);
    if ($includeThumbnail) {
        $response["thumbnailUrl"] = $link;
    }
    echo json_encode($response);
}
}
// 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'];
}
// Return true if it's likely that the associate file is natively
// viewable in a browser.  For simplicity, just uses the file extension
// to make this determination, along with an array of extensions that one
// would expect all supported browsers are able to render natively.
function isFileViewableImage($filename) {
$ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
$viewableExtensions = array("jpeg", "jpg", "gif", "png");
return in_array($ext, $viewableExtensions);
}
// Returns true if we should attempt to include a link
// to a thumbnail in the uploadSuccess response.  In it's simplest form
// (which is our goal here - keep it simple) we only include a link to
// a viewable image and only if the browser is not capable of generating a         client-side preview.
function shouldIncludeThumbnail() {
$filename = $_POST["name"];
$isPreviewCapable = $_POST["isBrowserPreviewCapable"] == "true";
$isFileViewableImage = isFileViewableImage($filename);
return !$isPreviewCapable && $isFileViewableImage;
}
?>
ipyakuza
  • 21
  • 5
  • What _specific_ request is failing? – Ray Nicholus Apr 21 '15 at 18:19
  • Sorry I am not sure exactly what you are asking for but: whenever I drag and drop a JPG file on the browser it generates the thumbnail but fails to upload. it just returns the error message: Reason: XHR returned response code 0 and fails to upload the image to my S3 bucket. I am not sure what part is failing, if there is a way to review my JSON policy and signed data or failing CORS configs/values somewhere that is what I am looking for advice on. – ipyakuza Apr 21 '15 at 23:16
  • I guess whenever I have something partially working/failing I can enable verbose logging somewhere to figure out whats broken (or at least google error messages). For this, the only error I see the javascript alert with UPLOAD FAILED Reason: XHR returned response code 0. Just trying to figure out what else I can test/inspect/review. – ipyakuza Apr 21 '15 at 23:24
  • The first step is to figure out which specific request is failing. If you look at the network tab of your browser's dev tools, you will be able to make this determination. You will also see more useful information in the console. – Ray Nicholus Apr 22 '15 at 00:14
  • Gotcha thanks. So digging around I see the following error: XMLHttpRequest cannot load https://s3.amazonaws.com/dev-pre-content. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'https://192.168.1.215' is therefore not allowed access. The test box I am running this off is a VM guest on my laptop. Its a full mirror of my production server. From this laptop IP 192.168.1.215 it goes directly to my S3 bucket named 'dev-pre-content' which is on US-WEST-2 AWS. – ipyakuza Apr 22 '15 at 00:36
  • Sounds like you have CORSs issues. – Ray Nicholus Apr 22 '15 at 12:49

2 Answers2

0

Based on your follow-up comment explaining the specific issue:

So digging around I see the following error: XMLHttpRequest cannot load s3.amazonaws.com/dev-pre-content. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin '192.168.1.215'; is therefore not allowed access.

The problem is with your bucket's CORS configuration. You'll need to be sure you have appropriate CORS rules associated with the specific bucket you are uploading to.

Ray Nicholus
  • 19,538
  • 14
  • 59
  • 82
  • Editing the server side code s3demo-cors.php and changing header('Access-Control-Allow-Origin: {$_SERVER['SERVER_NAME']}'); rather than * seemed to move me a step further. Now Im hitting the following errors: [Fine Uploader 5.2.0] Error attempting to parse signature response: SyntaxError: Unexpected token < [Fine Uploader 5.2.0] Received an empty or invalid response from the server! [Fine Uploader 5.2.0] Policy signing failed. Received an empty or invalid response from the server!. – ipyakuza Apr 23 '15 at 16:47
  • Im stepping through the policy signing code for POST method and not sure what exactly is required. It has my AWS credentials already, looks like it constructs the JSON policy (in code) but cant seem to gain visibility into what the JSON output looks like or how to validate what is being generated by the s3demo-cors.php example you provide. – ipyakuza Apr 23 '15 at 16:50
  • I see this documentation here: http://blog.fineuploader.com/2013/08/16/fine-uploader-s3-upload-directly-to-amazon-s3-from-your-browser/#sign-policy which explains the json policy values but not sure if this is to be posted to s3demo-cors.php OR where/how this is supposed to be implemented. – ipyakuza Apr 23 '15 at 17:03
  • The PHP example handles the signing for you. – Ray Nicholus Apr 23 '15 at 17:08
  • If I open a paid support incident would you be willing to work with me to pinpoint whats missing and help me get a working instance? If so I don't mind paying for support. I just keep reviewing the documentation over and over and stepping through the code + trying to search for the browser dev console errors and coming up blank. I understand how it all "should" work in theory but clearly I am missing something. – ipyakuza Apr 23 '15 at 17:11
  • More tinkering I now can see in the dev tools within Chrome the POST to s3demo-cors.php is generating a policy and signature however I am still getting these errors: [Fine Uploader 5.2.0] Error attempting to parse signature response: SyntaxError: Unexpected token I [Fine Uploader 5.2.0] Received an empty or invalid response from the server! [Fine Uploader 5.2.0] Policy signing failed. Received an empty or invalid response from the server! However on the NETWORK tab I can see a valid policy and signature response. Feel like I am very close. – ipyakuza Apr 24 '15 at 02:25
  • Could be a non-JSON response, or it could be that you are not returning the correct response based on the type of upload. The [S3 sever section in the docs covers this](http://docs.fineuploader.com/branch/master/endpoint_handlers/amazon-s3.html), but in short the response and signature process is different for chunked vs non-chunked uploads. – Ray Nicholus Apr 24 '15 at 02:50
  • This is the response I am getting back with response 200: policy: "eyJleHBpcmF0aW9uIjoiMjAxNS0wNC0yNFQxNTozMToxMy4zNDJaIiwiY29uZGl0aW9ucyI6W3siYWNsIjoicHJpdmF0ZSJ9LHsiYnVja2V0IjoiZGV2LXByZS1jb250ZW50In0seyJDb250ZW50LVR5cGUiOiJpbWFnZVwvanBlZyJ9LHsic3VjY2Vzc19hY3Rpb25fc3RhdHVzIjoiMjAwIn0seyJrZXkiOiI1NDIxMDc4MC1mODU3LTRkNGYtOGUyZi05ZDI5NzlhYzVkZGUuanBnIn0seyJ4LWFtei1tZXRhLXFxZmlsZW5hbWUiOiJtYXAzLmpwZyJ9LFsiY29udGVudC1sZW5ndGgtcmFuZ2UiLCIwIiwiMjUwMDAwMDAiXV19" signature: "pzwW56PO/xX2OaYqb4Gzrbt0DyM=" and it looks like the valid 2 fields I am expecting. – ipyakuza Apr 24 '15 at 15:28
  • I also tried with chunking and non-chunking but still same results. As i step through the Chrome dev tools console and drill down to the js lines that are failing, is there a way I can see exactly what the JSON response is thats given? I need to know if its a botched JSON response (which i doubt since this is a drop in of your PHP example) or need to identify exactly what script/step in the workflow is failing to send the JSON response. – ipyakuza Apr 24 '15 at 15:29
  • Could be a non-JSON response. What you pasted is certainly not valid JSON. – Ray Nicholus Apr 24 '15 at 15:34
  • I understand thats not a valid JSON format its what your PHP demo script is returning as a response to my POST for the signature endpoint. The problem I am having is trying to identify exactly WHERE the JSON policy is constructed in the code. For example this: http://docs.aws.amazon.com/AmazonS3/latest/dev/HTTPPOSTForms.html#HTTPPOSTConstructPolicy I dont see where that is created in your PHP examples. – ipyakuza Apr 24 '15 at 15:47
  • Have a look, starting at [the `signRequest` method](https://github.com/FineUploader/server-examples/blob/master/php/s3/s3demo.php#L103). The example PHP server returns valid JSON. – Ray Nicholus Apr 24 '15 at 15:50
  • In PHP I dumped the $jsonContent to file: {"expiration":"2015-04-24T16:07:26.263Z","conditions":[{"acl":"private"},{"bucket":"dev-pre-content"},{"Content-Type":"image\/jpeg"},{"success_action_status":"200"},{"key":"d81ca7c4-a965-457d-ac91-0a0f2c8d5362.jpg"},{"x-amz-meta-qqfilename":"map1.jpg"},["content-length-range","0","25000000"]]} so it looks valid – ipyakuza Apr 24 '15 at 16:03
  • I started completely over with fresh copies of the S3 demo jquery code and s3demo-cors.php example. Everything is functioning properly (JSON, policy, signatures, etc) and it trying to reach my S3 bucket BUT the CORS policy seems to be hanging up again (as was my initial problem). XMLHttpRequest cannot load https://s3.amazonaws.com/dev-pre-content. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'https://192.168.1.215' is therefore not allowed access. I verified that I DO have the header: header('Access-Control-Allow-Origin: https://192.168.1.215'); – ipyakuza Apr 24 '15 at 18:45
  • You need to set the CORS policy on your bucket, not the signature server. – Ray Nicholus Apr 24 '15 at 18:52
  • But I have already done that (since the very beginning when I created my S3 bucket in the AWS console). At the top of this post you see my CORS definition: * POST PUT DELETE 3000 ETag * – ipyakuza Apr 24 '15 at 19:04
  • There is most definitely some issue with your CORS config on the bucket. Otherwise the request would not be rejected with a CORS error. You'll need to take a closer look and find the issue in your bucket's CORS config. – Ray Nicholus Apr 24 '15 at 19:10
  • 1
    SUCCESS: Verdict was my request endpoint. Originally it was: "https://s3.amazonaws.com/dev-pre-content" which I thought I read was supposed to be a valid format. I had to change it to "https://dev-pre-content.s3.amazonaws.com" in order for it to work over HTTPS and recognize it. – ipyakuza Apr 24 '15 at 20:07
-1

It was exactly what you said, I believe that should implement the policy signature. When you send the file directly to the S3 server, you must first inform the política assignature, so your javascript will pass the credentials that will be on your php file, so that after you send the files you want. Here is a working example of política signature

$AWSbucket = 'yout burcket';
$AWSkey = 'your key';
$AWSsecret = 'your secret';
$acl = 'public-read';

// Get the file extension
$file = $_POST['name'];
$extension = substr($_POST['name'], strrpos($_POST['name'], '.')+1);

// Prepare the filename
$fileName = 'c' . sha1(uniqid(mt_rand(), true));
$key = 'arquivos/'.$fileName . '.' . $extension;

// Set the expiration time of the policy
$policyExpiration = gmdate('Y-m-d\TH:i:s\Z', strtotime('+24 hour'));

// Set the policy
$policy = str_replace("\n", "", '
{"expiration": "' . $policyExpiration . '",
 "conditions": [
   {"acl": "' . $acl . '"},
   {"bucket": "' . $AWSbucket . '"},
   {"success_action_status": "201"},
   ["starts-with", "$key", "' . $key . '"],
 ]
}');

// 1 - Encode the policy using UTF-8.
// 2 - Encode those UTF-8 bytes using Base64.
// 3 - Sign the policy with your Secret Access Key using HMAC SHA-1.
// 4 - Encode the SHA-1 signature using Base64.

// Prepare the signature
$b64 = base64_encode(utf8_encode($policy));
$signature = base64_encode(hash_hmac('sha1', $b64, $AWSsecret, true));

// Return the post information
echo json_encode(array(
    'key' => $key,
    'acl' => $acl,
    'MinPartSize' => 25 * 1024 * 1024,
    'policy' => $b64,
    'signature' => $signature,
    'AWSAccessKeyId' => $AWSkey,
    'success_action_status' => 201,
    'bucket' => $AWSbucket
));
Lucas Romano
  • 111
  • 4
  • Nothing in your answer relates to CORS. Perhaps you are confusing terms? – Ray Nicholus Jun 18 '15 at 15:07
  • so I ended up putting corsag to what I meant is the policy, – Lucas Romano Jun 18 '15 at 16:15
  • The issue, as described by the question poster, was an invalid S3 bucket endpoint over HTTPS. Not CORS or policy-related. http://stackoverflow.com/questions/29779346/fine-uploader-s3-jquery-php-failed-upload-reason-xhr-returned-response/30917687?noredirect=1#comment47838922_29801132 – Ray Nicholus Jun 18 '15 at 16:32