简体   繁体   English

使用 PHP 从浏览器直接将多个文件上传到 AWS S3 存储桶

[英]Upload multiple files directly to AWS S3 bucket from browser with PHP

I need to make a web form capable of uploading multiple files directly to my AWS S3 bucket from browser with PHP.我需要制作一个能够使用 PHP 从浏览器直接将多个文件上传到我的 AWS S3 存储桶的 Web 表单。

I came across this nice solution for single file uploads ( https://www.sanwebe.com/2015/09/direct-upload-to-amazon-aws-s3-using-php-html ):我遇到了这个很好的单文件上传解决方案( https://www.sanwebe.com/2015/09/direct-upload-to-amazon-aws-s3-using-php-html ):

<?php
$access_key         = "iam-user-access-key"; //Access Key
$secret_key         = "iam-user-secret-key"; //Secret Key
$my_bucket          = "mybucket"; //bucket name
$region             = "us-east-1"; //bucket region
$success_redirect   = 'http://'. $_SERVER['SERVER_NAME'] . $_SERVER['REQUEST_URI']; //URL to which the client is redirected upon success (currently self) 
$allowd_file_size   = "1048579"; //1 MB allowed Size

//dates
$short_date         = gmdate('Ymd'); //short date
$iso_date           = gmdate("Ymd\THis\Z"); //iso format date
$expiration_date    = gmdate('Y-m-d\TG:i:s\Z', strtotime('+1 hours')); //policy expiration 1 hour from now

//POST Policy required in order to control what is allowed in the request
//For more info http://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-HTTPPOSTConstructPolicy.html
$policy = utf8_encode(json_encode(array(
                    'expiration' => $expiration_date,  
                    'conditions' => array(
                        array('acl' => 'public-read'),  
                        array('bucket' => $my_bucket), 
                        array('success_action_redirect' => $success_redirect),
                        array('starts-with', '$key', ''),
                        array('content-length-range', '1', $allowd_file_size), 
                        array('x-amz-credential' => $access_key.'/'.$short_date.'/'.$region.'/s3/aws4_request'),
                        array('x-amz-algorithm' => 'AWS4-HMAC-SHA256'),
                        array('X-amz-date' => $iso_date)
                        )))); 

//Signature calculation (AWS Signature Version 4)   
//For more info http://docs.aws.amazon.com/AmazonS3/latest/API/sig-v4-authenticating-requests.html  
$kDate = hash_hmac('sha256', $short_date, 'AWS4' . $secret_key, true);
$kRegion = hash_hmac('sha256', $region, $kDate, true);
$kService = hash_hmac('sha256', "s3", $kRegion, true);
$kSigning = hash_hmac('sha256', "aws4_request", $kService, true);
$signature = hash_hmac('sha256', base64_encode($policy), $kSigning);
?>
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Aws S3 Direct File Uploader</title>
</head>
<body>
<form action="http://<?= $my_bucket ?>.s3.amazonaws.com/" method="post" enctype="multipart/form-data">
<input type="hidden" name="key" value="${filename}" />
<input type="hidden" name="acl" value="public-read" />
<input type="hidden" name="X-Amz-Credential" value="<?= $access_key; ?>/<?= $short_date; ?>/<?= $region; ?>/s3/aws4_request" />
<input type="hidden" name="X-Amz-Algorithm" value="AWS4-HMAC-SHA256" />
<input type="hidden" name="X-Amz-Date" value="<?=$iso_date ; ?>" />
<input type="hidden" name="Policy" value="<?=base64_encode($policy); ?>" />
<input type="hidden" name="X-Amz-Signature" value="<?=$signature ?>" />
<input type="hidden" name="success_action_redirect" value="<?= $success_redirect ?>" /> 
<input type="file" name="file" />
<input type="submit" value="Upload File" />
</form>
<?php
//After success redirection from AWS S3
if(isset($_GET["key"]))
{
    $filename = $_GET["key"];
    $ext = pathinfo($filename, PATHINFO_EXTENSION);
    if(in_array($ext, array("jpg", "png", "gif", "jpeg"))){
        echo '<hr />Image File Uploaded : <br /><img src="//'.$my_bucket.'.s3.amazonaws.com/'.$_GET["key"].'" style="width:100%;" />';
    }else{
        echo '<hr />File Uploaded : <br /><a href="http://'.$my_bucket.'.s3.amazonaws.com/'.$_GET["key"].'">'.$filename.'</a>';
    }
}
?>
</body>
</html>

It works great for it purpose, but I need a solution that will be able to upload multiple uploads at once.它非常适合它,但我需要一个能够一次上传多个上传的解决方案。

One of the comments on page specifies an approach:页面上的评论之一指定了一种方法:

AWS only allows you to upload one file at a time if uploading directly to S3.如果直接上传到 S3,AWS 只允许您一次上传一个文件。 You can do multi file uploads by setting the file input to “multiple” and looping through each of the files, making mulitple submissions via AJAX.您可以通过将文件输入设置为“multiple”并循环遍历每个文件,通过 AJAX 进行多次提交来进行多文件上传。 To do this you need to set up CORS on the bucket you want to upload to, otherwise you'll be denied on the grounds of it being a cross-site script.为此,您需要在要上传到的存储桶上设置 CORS,否则您将被拒绝,因为它是跨站点脚本。 It can be accomplished, as I've just got it working on my own project.它可以完成,因为我刚刚让它在我自己的项目中工作。

I am trying to follow, but not sure how exactly he proposes to use an AJAX to make it work.我正在尝试遵循,但不确定他究竟打算如何使用 AJAX 使其工作。 Does the form will be on AJAx request page and I just feed file names to it?表单是否会出现在 AJAx 请求页面上,而我只是向它提供文件名?

Can someone familiar with an issue can please explain it to me more thoroughly or direct me to the alternative solution(s)?熟悉某个问题的人能否更彻底地向我解释或指导我找到替代解决方案?

You should use multiple="multiple" and also use name="file[]" .您应该使用multiple="multiple"并使用name="file[]"

Try using:尝试使用:

<form action="http://<?= $my_bucket ?>.s3.amazonaws.com/" method="post" enctype="multipart/form-data">
    <input type="hidden" name="key" value="${filename}" />
    <input type="hidden" name="acl" value="public-read" />
    <input type="hidden" name="X-Amz-Credential" value="<?= $access_key; ?>/<?= $short_date; ?>/<?= $region; ?>/s3/aws4_request" />
    <input type="hidden" name="X-Amz-Algorithm" value="AWS4-HMAC-SHA256" />
    <input type="hidden" name="X-Amz-Date" value="<?=$iso_date ; ?>" />
    <input type="hidden" name="Policy" value="<?=base64_encode($policy); ?>" />
    <input type="hidden" name="X-Amz-Signature" value="<?=$signature ?>" />
    <input type="hidden" name="success_action_redirect" value="<?= $success_redirect; ?>" /> 
    <input type="file" name="file[]" multiple="multiple" />
    <input type="submit" value="Upload File" />
</form>

you can encode files to base64 string formats using btoa() and send it to your server as an array [{"base64encodedFile 1",....,"base64encodedFile n"}] in one ajax request.您可以使用 btoa() 将文件编码为 base64 字符串格式,并在一个 ajax 请求[{"base64encodedFile 1",....,"base64encodedFile n"}]其作为数组[{"base64encodedFile 1",....,"base64encodedFile n"}]发送到您的服务器。 on your server you can loop through the array, decode them back and send it to s3 one by one as an input stream.在您的服务器上,您可以循环遍历数组,将它们解码回来并将其作为输入流一一发送到 s3。 I have done this in java, and it worked fine.我在java中完成了这个,它工作得很好。

ajax :阿贾克斯:

$.ajax({
    type: "POST",
    url: "/upload",
    data: [{"base64encodedFile 1",....,"base64encodedFile n"}],
    dataType: "json",
    success: function( data, textStatus, jqXHR) {
      // uploaded
    },
    error: function(jqXHR, textStatus, errorThrown){
      // error
    }
});

server side pseudo code:服务器端伪代码:

foreach(item in array) {
    decodedFile = base64Decode(item)
    InputStream fis = new ByteArrayInputStream(decodedFile)
    setMetaData() // such as content length, max-age , ...
    PutObjectRequest pro = new PutObjectRequest(getBUCKET_NAME(), 
    fileName, fis, metadata)
    por.setCannedAcl(CannedAccessControlList.PublicRead)
    s3Client.putObject(por)
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM