Skip to content

Instantly share code, notes, and snippets.

@FerraBraiZ
Forked from zxbodya/S3-CORS-config.xml
Last active August 21, 2019 00:21
Show Gist options
  • Save FerraBraiZ/9f89001ba39111811f0815dd825fd5c7 to your computer and use it in GitHub Desktop.
Save FerraBraiZ/9f89001ba39111811f0815dd825fd5c7 to your computer and use it in GitHub Desktop.
Client side uploads to s3, with pre-signed upload form (PHP/JS)
<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
<AllowedOrigin>*</AllowedOrigin>
<AllowedMethod>PUT</AllowedMethod>
<AllowedMethod>POST</AllowedMethod>
<AllowedMethod>GET</AllowedMethod>
<AllowedMethod>HEAD</AllowedMethod>
<MaxAgeSeconds>3000</MaxAgeSeconds>
<AllowedHeader>*</AllowedHeader>
</CORSRule>
</CORSConfiguration>
<?php
require_once('../../vendor/autoload.php');
ini_set('ignore_repeated_errors', 'On');
ini_set('html_errors', 'On');
ini_set('display_errors', 'On');
error_reporting(E_ALL);
date_default_timezone_set('America/Sao_Paulo');
use Aws\S3\S3Client;
use Aws\S3\PostObjectV4;
use Aws\Exception\AwsException;
try {
if( isset( $_SERVER['HTTP_ORIGIN'] ) && $_SERVER['HTTP_ORIGIN'] != '' )
{
header("Access-Control-Allow-Origin: {$_SERVER['HTTP_ORIGIN']}");
header('Access-Control-Allow-Credentials: true');
header('Access-Control-Max-Age: 0'); // cache for 0 day
}
// Access-Control headers are received during OPTIONS requests
if( $_SERVER['REQUEST_METHOD'] == 'OPTIONS')
{
if( isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_METHOD']))
header("Access-Control-Allow-Methods: GET, PUT, POST, DELETE, OPTIONS");
if( isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']))
header("Access-Control-Allow-Headers: {$_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']}");
exit;
}
$filename = ((object)$_REQUEST)->filename ?? false;
if( !$filename ){
throw new Error('a file name is mandatory');
}
define('AWS_KEY','XXXXXXXXXXXXXXXXX');
define('AWS_SECRET','XXXXXXXXXXXXXXXXXXXX');
define('AWS_BUCKET','XXXXXXXXXXXXXXXXXXXXXXX');
$client = new S3Client([
'version' => 'latest',
'region' => 'sa-east-1',
// 'profile' => 'default', it would read credentials from /home/${USER}/.aws/credentials
'credentials' => [
'key' => AWS_KEY,
'secret' => AWS_SECRET,
],
]);
// Set some defaults for form input fields
$formInputs = ['acl' => 'private'];
// Construct an array of conditions for policy
$options = [
["acl" => "private"],
["bucket" => AWS_BUCKET],
["content-type"=>""],
["key"=>"${filename}"],
["success_action_status"=>"201"]
];
// Optional: configure expiration time string
$expires = '+6 hours';
$postObject = new PostObjectV4(
$client,
AWS_BUCKET,
$formInputs,
$options,
$expires
);
// Get attributes to set on an HTML form, e.g., action, method, enctype
$formAttributes = $postObject->getFormAttributes();
// Get form input fields. This will include anything set as a form input in
// the constructor, the provided JSON policy, your AWS access key ID, and an
// auth signature.
$formInputs = $postObject->getFormInputs();
header('Content-Type:application/json');
http_response_code(200);
die(json_encode( [
"signature"=>[
"content-type"=>"",
"acl"=>"private",
"success_action_status"=>"201",
"policy"=>$formInputs["Policy"],
"x-amz-credential"=>$formInputs["X-Amz-Credential"],
"x-amz-algorithm"=>$formInputs["X-Amz-Algorithm"],
"x-amz-date"=>$formInputs["X-Amz-Date"],
"x-amz-signature"=>$formInputs["X-Amz-Signature"],
"key"=>"${filename}"
],
"postEndpoint"=>"https://ferrabraiz-test-bucket.s3.amazonaws.com/"
]));
} catch (AwsException $e) {
header('Content-Type:application/json');
http_response_code(200);
die(json_encode(["AwsException" => $e->getMessage()]));
} catch (\Throwable $e) {
header('Content-Type:application/json');
http_response_code(200);
die(json_encode(["error" => $e->getMessage()]));
}
// url from getUploadUrl in file above
// data presigned upload form data getImageUploadForm in file above
// file - File or Blob to be uploaded
// fileName - filename which would be passed with upload form (does not matter in case of s3)
function upload(url, data, file, fileName){
var xhr = new XMLHttpRequest();
xhr.onerror = function (e) {
// handle failture
};
xhr.upload.addEventListener('progress', function (e) {
// handle notifications about upload progress: e.loaded / e.total
}, false);
xhr.onreadystatechange = function () {
if (xhr.readyState === XMLHttpRequest.DONE) {
if (xhr.status >= 200 && xhr.status <= 299) {
// upload completed
} else {
// failed with error messge from server
}
}
};
function formData(data, file, fileName) {
var res = new FormData();
for (var k in data) {
res.append(k, data[k]);
}
res.append('file', file, fileName);
return res;
}
xhr.open('POST', url, true);
xhr.send(formData(data, file, fileName));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment