4

几周以来,我一直在尝试使用网络上可用的示例正确格式化 a REST requestAmazon AWS S3 API但甚至无法成功连接。

我找到了生成签名的代码,找到了格式化“要编码的字符串”的正确方法,以及http headers. 我已经通过signatureDoesNotMatch错误的方式来获取Anonymous users can not perform copy functions, Please authenticate消息。

我有一个成功上传文件的应用程序的工作副本Adobe Flex,但使用它们的“原始”文件名。REST与 the一起使用的Amazon API目的是执行PUT文件的(复制),这样我就可以将它重命名为我的后端系统可以使用的东西。

如果我能找到一种方法让这个REST提交工作,或者Flex在上传时指定一个“新”文件名,我可以一起避免这种REST情况。

如果有人成功地在via上执行了PUT/Copy命令,我会对这是如何完成的非常感兴趣 - 或者 - 如果有人能够使用该方法更改目标文件名,我也将永远感激任何指针。Amazon APIRESTFlex fileReference.browse()


用于此的 PHP 代码如下:

$aws_key = 'removed_for_security';
$aws_secret = 'removed_for_security';
$source_file = $uploaded_s3_file; // file to upload to S3 (defined in above script)
$aws_bucket = 'bucket'; // AWS bucket
$aws_object = $event_file_name; // AWS object name (file name)
if (strlen($aws_secret) != 40) die("$aws_secret should be exactly 40 bytes long");
$file_data = file_get_contents($source_file);
if ($file_data == false) die("Failed to read file " . $source_file);

// opening HTTP connection to Amazon S3
$fp = fsockopen("s3.amazonaws.com", 80, $errno, $errstr, 30);
if (!$fp) die("$errstr ($errno)\n");

// Uploading object
$file_length = strlen($file_data); // for Content-Length HTTP field
$dt = gmdate('r'); // GMT based timestamp

// preparing String to Sign (see AWS S3 Developer Guide)
// preparing string to sign
$string2sign = "PUT


{$dt}
/{$aws_bucket}/{$aws_object}";

// preparing HTTP query 
// $query = "PUT /".$aws_bucket."/".$event_file_name." HTTP/1.1
$query = "PUT /" . $event_file_name . " HTTP/1.1
Host: {$aws_bucket}.s3.amazonaws.com
Date: {$dt}
x-amz-copy-source: /{$aws_bucket}/{$current_s3_filename}
x-amz-acl: public-read

Authorization: AWS {$aws_key}:" . amazon_hmac($string2sign) . "\n\n";

$query .= $file_data;
$resp = sendREST($fp, $query);
if (strpos($resp, '') !== false) {
     die($resp);
}
echo "FILE uploaded\n";

// done
echo "Your file's URL is: http://s3.amazonaws.com/{$aws_bucket}/{$aws_object}\n";
fclose($fp);

// Sending HTTP query and receiving, with trivial keep-alive support
function sendREST($fp, $q, $debug = true){
     if ($debug) echo "\nQUERY<<{$q}>>\n";
     fwrite($fp, $q);
     $r = '';
     $check_header = true;
     while (!feof($fp)) {
          $tr = fgets($fp, 256);
          if ($debug) echo "\nRESPONSE<<{$tr}>>";
          $r .= $tr;
          if (($check_header) && (strpos($r, "\r\n\r\n") !== false)) {

               // if content-length == 0, return query result
               if (strpos($r, 'Content-Length: 0') !== false) {
                    return $r;
               }
          }

          // Keep-alive responses does not return EOF
          // they end with \r\n0\r\n\r\n string
          if (substr($r, -7) == "\r\n0\r\n\r\n") {
               return $r;
          }
     }
     return $r;
}

// hmac-sha1 code START
// hmac-sha1 function: assuming key is global $aws_secret 40 bytes long
// read more at http://en.wikipedia.org/wiki/HMAC
// warning: key($aws_secret) is padded to 64 bytes with 0x0 after first function call
function amazon_hmac($stringToSign) {

     // helper function binsha1 for amazon_hmac (returns binary value of sha1 hash)
     if (!function_exists('binsha1')) {
          if (version_compare(phpversion(), "5.0.0", ">=")) {
               function binsha1($d) { return sha1($d, true); }
          } else {
               function binsha1($d) { return pack('H*', sha1($d)); }
          }
     }
     global $aws_secret;
     if (strlen($aws_secret) == 40) {
          $aws_secret = $aws_secret . str_repeat(chr(0), 24);
     }
     $ipad = str_repeat(chr(0x36), 64);
     $opad = str_repeat(chr(0x5c), 64);
     $hmac = binsha1(($aws_secret ^ $opad) . binsha1(($aws_secret ^ $ipad) . $stringToSign));
     return base64_encode($hmac);
}
// hmac-sha1 code END

当我提交格式错误或不正确的标头时,我会按预期收到相​​应的错误消息:

询问:

PUT /bucket/1-132-1301047200-1.jpg HTTP/1.1 主机:s3.amazonaws.com x-amz-acl:公共读取连接:keep-alive 内容长度:34102 日期:星期六,2011 年 3 月 26 日 00 :43:36 +0000 授权:AWS -出于安全考虑已删除-:GmgRObHEFuirWPwaqRgdKiQK/EQ=

HTTP/1.1 403 禁止
x-amz-request-id: A7CB0311812CD721
x-amz-id-2: ZUY0mH4Q20Izgt/9BNhpJl9OoOCp59DKxlH2JJrJOksksyKxl8/HtmJrJOk6K
+类型:application/xml
传输编码:chunked
日期:星期六,2011 年 3 月 26 日 00:43:36 GMT
连接:关闭
服务器:AmazonS3
397 SignatureDoesNotMatch我们计算的请求签名与您提供的签名不匹配。检查您的密钥和签名方法。50 55 54 0a 0a 0a 53 61 74 2c 20 32 36 20 4d 61 72 20 32 30 31 31 20 30 30 3a 34 33 3a 33 36 20 2b 30 30 30 30 16 0a 78 2d 2d 61 63 6c 3a 70 75 62 6c 69 69 69 63 2d 72 65 65 61 64 0a 2f 6d 6d 6d 6c 6c 68 2d 70 72 72 6f 64 75 63 74 63 74 69 6f 6e 6 e 2f 6e 2f 6e 2f 31 2d 31 2d 31 33 33 33 32 33 33 33 33 31 33 31 31 31 31 31 31 31 31 31 31 31 31 33 32 30 32 30 32 30 32 30 32 30 32 30 32 30 2DDD 31 2E 70 6A 67A7CB0311812CD721ZUY0mH4Q20Izgt / 9BNhpJl9OoOCp59DKxlH2JJ6K + sksyxI8lFtmJrJOk1imxM / AGmgRObHEFuirWPwaqRgdKiQK / EQ = PUT星期六,2011年3月26日00:43:36 0000的x AMZ-ACL:公共读/bucket/1-132-1301047200-1.jpg-removed为了安全- 0

但是在发送格式正确的请求时,它说我没有经过身份验证:

正在使用的查询:

PUT /1-132-1301047200-1.jpg HTTP/1.1 主机:bucket.s3.amazonaws.com 日期:星期六,2011 年 3 月 26 日 00:41:50 +0000 x-amz-copy-source:/bucket/clock。 jpg x-amz-acl:公开读取授权:AWS -出于安全考虑已删除-:BMiGhgbFnVAJyiderKjn1cT7cj4=

HTTP/1.1 403 禁止
x-amz-request-id:ABE45FD4DFD19927
x-amz-id-2:CnkMmoF550H1zBlrwwKfN8zoOSt7r/zud8mRuLqzzBrdGguotcvrpZ3aU4HR4RoO
内容类型:应用程序/xml
传输编码:分块
日期:星期六,2011 年 3 月 26 日 00:4
服务器:AmazonS3

AccessDenied
匿名用户无法复制对象。请验证
ABE45FD4DFD19927CnkMmoF550H1zBlrwwKfN8zoOSt7r/zud8mRuLqzzBrdGguotcvrpZ3aU4HR4RoO 0
日期:星期六,2011 年 3 月 26 日 00:41:50 GMT
连接:关闭
服务器:AmazonS3

4

1 回答 1

9

几周以来,我一直在尝试使用网络上的可用示例正确格式化对 Amazon AWS S3 API 的 REST 请求

您是否尝试过适用于 PHP 的 Amazon AWS 开发工具包?它全面、完整,最重要的是,由亚马逊编写。如果他们自己的代码对你不起作用,那肯定会出问题。


以下是使用链接 SDK 将example.txt当前目录中上传到名为“my_very_first_bucket”的存储桶的示例代码。

<?php
// Complain wildly.
    ini_set('display_errors', true);
    error_reporting(-1);
// Set these yourself.
    define('AWS_KEY', '');
    define('AWS_SECRET_KEY', '');
// We'll assume that the SDK is in our current directory
    include_once 'sdk-1.3.1/sdk.class.php';
    include_once 'sdk-1.3.1/services/s3.class.php';
// Set the bucket and name of the file we're sending.
// It happens that we're actually uploading the file and 
// keeping the name, so we're re-using the variable
// below.
    $bucket_name = 'my_very_first_bucket';
    $file_to_upload = 'example.txt';
// Fire up the object
    $s3 = new AmazonS3(AWS_KEY, AWS_SECRET_KEY);
// This returns a "CFResponse"
    $r = $s3->create_object(
        $bucket_name,
        $file_to_upload,
        array(
        // Filename of the thing we're uploading
            'fileUpload' => (__DIR__ . '/' . $file_to_upload),
        // ACL'd public.
            'acl' => AmazonS3::ACL_PUBLIC,
        // No wai.
            'contentType' => 'text/plain',
        // The docs say it'll guess this, but may as well.
            'length' => filesize(__DIR__ . '/' . $file_to_upload)
        )
    );
// Did it work?
    echo "Worked: ";
    var_dump($r->isOK());
// Status as in HTTP.
    echo "\nStatus: ";
    var_dump($r->status);
// The public URL by which we can reach this object.
    echo "\nURL: ";
    echo $s3->get_object_url($bucket_name, $file_to_upload);
// Tada!
    echo "\n";

适当的 API 文档:

您可以在左侧菜单中浏览其余方法。它非常全面,包括新桶的创建、管理、删除、对象相同等。

您应该能够基本上将其放入您的代码中并使其正常工作。PHP 5.2 安全。


银虎编辑:

Charles -

     您提供的方法是使用 API SDK 函数将文件从本地文件系统上传到我选择的存储桶。我的那部分已经通过 Flex 工作了,上传工作就像一个魅力。有问题的问题是能够向 AWS S3 提交 REST 请求,以将文件名从当前的“上传”名称更改为更适合我的后端的新名称(数据库、跟踪等,我使用 MySQL 在 PHP 中单独处理和显示)。

     AWS S3 并不真正支持“复制”功能,因此他们提供了一种方法来重新“PUT”文件,方法是从您自己的存储桶中读取源文件并将具有不同名称的新副本放在同一个存储桶中。我遇到的困难是处理 REST 请求,

     我非常感谢您的时间并理解您提供的示例,因为在我设计 Flex 应用程序之前,我还有一个 PHP 上传的工作副本。Flex 的原因是启用状态更新和动态更新的进度条,这也很有魅力:)。

我将继续追求 REST 解决方案,因为从 Amason zupport 的角度来看,这将是我可以根据他们的支持团队重命名我的存储桶中已经存在的文件的唯一方法。

与往常一样,如果您对 REST 提交有意见或建议,我将非常感谢您提供任何反馈。

谢谢,

银虎


证明复制/删除作品:

    $r = $s3->copy_object(
        array( 'bucket' => $bucket_name, 'filename' => $file_to_upload ),
        array( 'bucket' => $bucket_name, 'filename' => 'foo.txt' )
    );
// Did it work?
    echo "Worked: ";
    var_dump($r->isOK());
// Status as in HTTP.
    echo "\nStatus: ";
    var_dump($r->status);

// The public URL by which we can reach this object.
    echo "\nURL: ";
    echo $s3->get_object_url($bucket_name, 'foo.txt');

    echo "\nDelete: ";
// Nuke?
    $r = $s3->delete_object($bucket_name, $file_to_upload);
// Did it work?
    echo "Worked: ";
    var_dump($r->isOK());
// Status as in HTTP.
    echo "\nStatus: ";
    var_dump($r->status);

银虎编辑:

Charles -

     无需 REST,无需麻烦... SDK 1.3.1 和您的帮助解决了这个问题。我用来测试的代码看起来很像你的:

// Complain wildly.
    ini_set('display_errors', true);
    error_reporting(-1);
// Set these yourself.
    define('AWS_KEY', 'removed for security');
    define('AWS_SECRET_KEY', 'removed for security');
// We'll assume that the SDK is in our current directory
    include_once 'includes/sdk-1.3.1/sdk.class.php';
    include_once 'includes/sdk-1.3.1/services/s3.class.php';
// Set the bucket and name of the file we're sending.
// It happens that we're actually uploading the file and 
// keeping the name, so we're re-using the variable
// below.
    $bucket = 'bucket';
    $file_to_upload = 'example.txt';
    $Source_file_to_copy = 'Album.jpg';
    $Destination_file = 'Album2.jpg';
// Fire up the object
// Instantiate the class
$s3 = new AmazonS3();
$response = $s3->copy_object(
    array( // Source
        'bucket' => $bucket,
        'filename' => $Source_file_to_copy
    ),
    array( // Destination
        'bucket' => $bucket,
        'filename' => $Destination_file
    )
);
// Success?
var_dump($response->isOK());

现在我将在复制后实现删除,我们是黄金。感谢先生的洞察力和帮助。

银虎

于 2011-03-25T22:50:39.677 回答