【问题标题】:Upload multiple files directly to AWS S3 bucket from browser with PHP使用 PHP 从浏览器将多个文件直接上传到 AWS S3 存储桶
【发布时间】:2018-09-19 03:15:28
【问题描述】:

我需要制作一个能够使用 PHP 从浏览器将多个文件直接上传到我的 AWS S3 存储桶的 Web 表单。

我遇到了一个很好的单文件上传解决方案 (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>

它非常适合它,但我需要一个能够一次上传多个上传的解决方案。

页面上的其中一个 cmets 指定了一种方法:

如果直接上传到 S3,AWS 只允许您一次上传一个文件。您可以通过将文件输入设置为“多个”并循环遍历每个文件来进行多文件上传,通过 AJAX 进行多次提交。为此,您需要在要上传到的存储桶上设置 CORS,否则您将被拒绝,因为它是跨站点脚本。它可以完成,因为我刚刚在我自己的项目中工作。

我正在尝试关注,但不确定他建议如何使用 AJAX 来使其工作。表单是否会出现在 AJAx 请求页面上,而我只是将文件名提供给它?

能否请熟悉某个问题的人更彻底地向我解释或指导我寻找替代解决方案?

【问题讨论】:

  • 如果运行PHP的Web服务器是EC2实例,请不要在源代码中包含key和secret key。您可以简单地为 EC2 实例分配一个 IAM 角色,然后您可以在不提供任何凭证的情况下调用 SDK。
  • 这个原型只是为了得到想要的功能,最终版本肯定会得到保障。现在,您对问题本身有什么要宣传的吗? :)
  • 我花了一整天的时间来完成这项工作。我为自己的参考和演示做了一个 PHP 脚本。希望对您有所帮助:github.com/jinjie/s3-client-upload-demo

标签: php ajax amazon-web-services amazon-s3


【解决方案1】:

你应该使用multiple="multiple",也应该使用name="file[]"

尝试使用:

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

【讨论】:

  • 我有最新的 sdk 并尝试对其进行测试并遇到“未找到 Class 'AmazonS3'”,此代码适用于什么版本的 aws sdk?另外,根据 sdk 说明,我的凭据在 ini 文件中,我需要将它们放入 sdk.class.php 吗?我是否还需要单独加载 sdk.class.php - 虽然加载自动加载就足够了?
  • 另外,提交时不会将文件移动到服务器上的临时文件夹吗?我需要它直接上传到 S3,而不向我的服务器上传任何内容。
  • @Acidon 临时文件在上传后被删除,这就是 php 与上传的工作方式,没有其他方法可以做到这一点,您可以将文件上传两次,但我们不想这样做,所以我们必须使用临时文件....
  • @Acidon 确保您必须作曲家 sdk,以及您从网站下载的常规 sdk!
  • 我的问题的重点是让它直接上传到 S3,绕过完全上传到服务器。据我了解,我原来的帖子中的代码是一个可行的解决方案,仅针对单个文件。我的问题是如何为该解决方案启用多重上传或将直接上传到 S3 的替代方法...
【解决方案2】:

您可以使用 btoa() 将文件编码为 base64 字符串格式并将其作为数组发送到您的服务器 [{"base64encodedFile 1",....,"base64encodedFile n"}] 在一个ajax请求中。在您的服务器上,您可以循环遍历数组,将它们解码回来并将其作为输入流一一发送到 s3。 我在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
    }
});

服务器端伪代码:

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)
}

【讨论】:

    猜你喜欢
    • 2020-10-10
    • 2019-10-23
    • 2018-04-25
    • 1970-01-01
    • 2012-05-28
    • 1970-01-01
    • 2013-03-18
    • 2018-08-13
    • 1970-01-01
    相关资源
    最近更新 更多