当前位置: 首页 > 知识库问答 >
问题:

使用AWS presignedURL放置文件

司空鸿熙
2023-03-14

我正在使用aws sdk php创建预签名URL,用于将文件上载到S3 bucket。GET的URL正在工作。

这是代码

$client = S3Client::factory(array('region' => 'eu-west-1','key' => 'xxx','secret' => 'xxx',));

//option 1
$command = $client->getCommand('PutObject', array(
    'Bucket' => 'myBucket',
    'Key' => 'testing/signedPHP1_'.time(),
    'ContentType' => 'image/jpeg',
    'Body' => 'dump' //it's mandatory
));
$signedUrl = $command->createPresignedUrl('+5 minutes');
$signedUrl .= '&Content-Type=image%2Fjpeg';
echo("\n\nThe URL is: ". $signedUrl . "\n");
echo("Now run from console for upload:\ncurl -v -H \"Content-Type: image/jpeg\" -T /tmp/temp.jpg '" . $signedUrl . "'");

//option 2
$request = $client->put('myBucket/testing/signedPHP2_'.time());
$signedUrl = $client->createPresignedUrl($request, '+5 minutes');
$signedUrl .= '&Content-Type=image%2Fjpeg';
echo("\n\nThe URL is: ". $signedUrl . "\n");
echo("Now run from console for upload:\ncurl -v -H \"Content-Type: image/jpeg\" -T /tmp/temp.jpg '" . $signedUrl . "'");

//GET which works
$request = $client->get('myBucket/testing/existingFile.txt');
$signedUrl = $client->createPresignedUrl($request, '+5 minutes');
echo("\n\nThe URL is: ". $signedUrl . "\n");
echo("Now run:\ncurl '" . $signedUrl . "'");

//GET which works
$command = $client->getCommand('GetObject', array('Bucket' => 'myBucket','Key' => 'upload/data.txt'));
$signedUrl = $command->createPresignedUrl('+5 minutes');
echo("\n\nThe URL is: ". $signedUrl . "\n");
echo("Now run:\ncurl '" . $signedUrl . "'");

当尝试使用curl命令时,我收到错误SignatureDoesNotMatch和消息我们计算的请求签名与您提供的签名不匹配。检查您的密钥和签名方法。

aws sdk for Javascript中的类似代码正在运行

var AWS = require('aws-sdk');
AWS.config.update({ accessKeyId: 'xxx', secretAccessKey: 'xxx', region: 'eu-west-1' });
var s3 = new AWS.S3();
var params = {
    Bucket: 'myBucket',
    Key: 'testing/preSignedURLnodeJS_' + (+new Date),
    ContentType: 'image/jpeg',
    Expires: 60 * 5
};
s3.getSignedUrl('putObject', params, function(err, url) {
    console.log('The URL is: ', url);
    console.log('Now run from console for upload:\n\ncurl -v -H "Content-Type: image/jpeg" -T /tmp/temp.jpg \'' + url + '\'');
});

已经做了很多研究,但没有结果。我做错了什么?

共有3个答案

方坚壁
2023-03-14

如果您正在使用sdk,为什么不使用putObject命令,而不是自己创建put请求。这将为您处理signedUrl。

$result = $client->putObject(array(
    'Bucket'     => $bucket,
    'Key'        => 'data_from_file.txt',
    'SourceFile' => $pathToFile
));

http://docs.aws.amazon.com/aws-sdk-php/latest/class-Aws.S3.S3Client.html#_putObject

如果您不希望这样,您需要查看put命令的主体,这应该是您正在上载的文件的内容,而不仅仅是一个随机字符串“dump”。

在运行该命令的机器上运行wireshark,您将看到curl发出的请求的主体是文件的内容。

邵伟泽
2023-03-14

干得好:

首先,创建预签名的URL

<?php 
/**
 *  getDocumentUploadUrls
 *
 *  creates a list of url so you can upload multiple files per
 *  document. After uploading the files it is requires for you
 *  to confirm the uploads.
 *
 *  @param Int $documentId the document id
 *  @param Int $count the amount of files you want to upload for this document
 *
 *  @return Array list of URLs to use with PUT request to upload files to s3.
 */
public function getDocumentUploadUrls(Int $documentId, Int $count = 1): Array
{
    $awsService = $this->getService('aws');

    $s3Client = $awsService->getSdk()->createS3();

    $urls = array_fill(1, $count, null);

    $bucket = 'yourbucket';

    $result = [];

    $expire = '+20 minutes';

    for ($i = 0; $i < $count; $i++) {
        $fileCount = $i + 1;

        $key = "{$documentId}/{$fileCount}";

        $cmd = $s3Client->getCommand('PutObject', [
            'Bucket' => $bucket,
            'Key'    => $key
        ]);

        $request = $s3Client->createPresignedRequest($cmd, $expire);

        $result[] = [
            'url' => (string) $request->getUri(),
            'reference' => "{$bucket}/{$key}"
        ];
    }

    return $result;
}

结果可能类似于此:

$result = [
    0 => [
        'url' => 'AwsS3://put/uri',
        'reference' => 'docId/count'
    ]
];

现在,要使用php cURL上传:

if ($request->isPost()) {
        $files = $request->getFiles()->toArray();

        $files = reset($files);

        $data = $request->getPost();

        $docId = $data['documentId']; // get this from your frontend POST params

        $docCount = count($files);

        try {
            $endpoints = $this->getDocumentUploadUrls($userId, $docId, $docCount);

            $uploadInfo = $this->uploadDocuments($endpoints, $files);
        } catch (\Exception $e) {
            // handle exception
        }
}

public function uploadDocuments(Array $endpoints, Array $files)
{
    $info = [];

    foreach ($files as $index => $file) {
        $url = $endpoints[$index]['url']; // the no. of files must match the number of endpoints for this to work

        $type = isset($file['type']) ? $file['type'] : 'application/octet-stream';

        $headers = [
            "Content-Type: $type",
            'Access-Control-Allow-Origin: *',
        ];

        $ch = curl_init($url);

        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT");
        curl_setopt($ch, CURLOPT_POSTFIELDS, $file);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);

        $response = curl_exec($ch);

        if (curl_errno($ch)) {
            throw new \Exception(curl_error($ch));
        }

        curl_close($ch);

        $info[] = [
            'headers' => $headers,
            'response' => $response
        ];
    }

    return $info;
}
齐昆
2023-03-14

在Github上,我从SDK开发者那里得到了一个答案,上面说

$command = $client->getCommand('PutObject', array(
    'Bucket' => 'myBucket',
    'Key' => 'testing/signedPHP1_'.time(),
    'ContentType' => 'image/jpeg',
    'Body'        => '',
    'ContentMD5'  => false
));

参考:https://github.com/aws/aws-sdk-php/issues/239

 类似资料:
  • 我正在尝试解决我的配置文件问题。 我有这个结构的Spring MVC应用程序(我当前的结构) (这是相当标准的maven项目目录结构) 所以,我的问题是:< b >我应该把spring配置文件放到resources目录中吗?我不确定它们是否可以被视为资源文件。大多数spring项目都在WEB-INF/目录中有配置。但是单元测试有一个问题,因为当我需要加载servlet配置时,maven需要/tes

  • 当我使用MediaPlayer播放mp3文件时,系统会报告错误日志:。但是RealPlayer是正常的。 我发现它的错误只发生在更高的ROM版本。像4.0版本一样,它有错误。在2.3版中,它没有这个错误。 代码: 日志猫错误:

  • 我刚开始接触docker,我运行以下程序: 我得到了一个拒绝许可的错误。事实证明,docker写入目录,这需要有写入权限。许多其他docker命令也需要类似的内容: 现在,我真的不喜欢为每个docker命令添加根特权的概念。这可能是因为我还不太了解docker,但每个程序都是如此)。这是docker的要求吗? 如果它不是必需的,那么我如何配置它,使它与其他程序非常相似,它们只在需要时向我请求权限,

  • 我正在尝试用配置我的,以便对用户进行身份验证。我已经配置了openldap,它在中运行良好。但是对于,它给出的错误是 以下是配置:

  • 问题内容: 我使用Java 8,并且使用默认的JavaScript引擎(Nashorn)。 我想看看它与“高度宣传”的GRAAL JS相比如何。看到: https://github.com/graalvm/graaljs https://www.graalvm.org/ 特别是因为我听说他们想弃用nashorn: http://openjdk.java.net/jeps/335 有人知道如何(轻松

  • 我想为组件(例如JPanel或JLabel)实现自定义放置位置渲染。我的目标是在用户将可拖放项悬停在组件上时显示蓝色边框,并在离开组件时再次删除边框。 摇摆教程提供了以下内容: 删除位置渲染 这对我一点帮助都没有。我缺少类似和这样的东西,或者这个页面引用的东西与我预期的不同? 所以我通过万维网搜索,找到了一些例子(大部分来自这个博客)。过了一会儿,我可以完成一个我需要的工作示例(来源如下)。但是我