使用AWS presignedURL的PUT文件

时间:2014-02-17 16:08:28

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

我正在使用aws-sdk-php创建预先签名的URL,以便将文件上传到S3存储桶。 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 ,邮件我们计算的请求签名与您提供的签名不匹配。检查您的密钥和签名方法

用于Javascript的aws-sdk中的类似代码正在运行

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 个答案:

答案 0 :(得分:8)

在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

答案 1 :(得分:0)

你走了:

首先,创建预先签名的网址

$activationCode = $request->activation_code;                                   

$rules = [                                                                     
    'mc' => [                                                                  
        'required',                                                            
        Rule::exists('email_verifications', 'machineCode')                     
        ->where(function ($query) use ($activationCode) {                      
            $query->where('activationCode', $activationCode);                  
        }),                                                                    
    ],                                                                         
    'activation_code' => 'required|integer|min:5',                             
    'operating_system' => 'required|alpha_num|max:45'                          
];

结果可能与此类似:

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

现在,使用php cURL上传:

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

答案 2 :(得分:-1)

如果您正在使用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正在生成的请求正文是文件的内容。