4

REST requestWeb で入手可能な例を使用して aをに適切にフォーマットするために何週間も試みてきましたAmazon AWS S3 APIが、正常に接続することさえできませんでした。

署名を生成するコードを見つけ、「エンコードする文字列」をフォーマットする適切な方法を見つけましたhttp headers。メッセージsignatureDoesNotMatchを取得するためだけに、エラーを処理しました。Anonymous users can not perform copy functions, Please authenticate

ファイルを正常にアップロードするアプリケーションの作業コピーがありAdobe Flexますが、「元の」ファイル名が付いています。RESTをとともに使用するポイントは、ファイルの (コピー)Amazon APIを実行することPUTです。そのため、バックエンド システムが使用できる名前に変更できます。

この提出物を機能させる方法、またはアップロード中にREST「新しい」ファイル名を指定する方法を見つけることができれば、この状況全体を一緒に回避できます。FlexREST

誰かがビアで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: public-read Connection: keep-alive Content-Length: 34102 Date: Sat, 26 Mar 2011 00 :43:36 +0000 Authorization: AWS -removed for security-:GmgRObHEFuirWPwaqRgdKiQK/EQ=

HTTP/1.1 403 Forbidden
x-amz-request-id: A7CB0311812CD721
x-amz-id-2: ZUY0mH4Q20Izgt/9BNhpJl9OoOCp59DKxlHsk2JJ6K+コンテンツ
MxFsk2JJ6Kタイプ: application/xml
転送エンコーディング: チャンク
日付: 2011 年 3 月 26 日(土) 00:43:36 GMT
接続: 閉じる
サーバー: AmazonS3
397 SignatureDoesNotMatch計算したリクエストの署名が、提供された署名と一致しません。キーと署名方法を確認してください。 2d 61 63 6c 3a 70 75 62 6c 69 63 2d 72 65 65 61 64 0a 2f 6d 6c 68 2d 70 72 6f 64 75 63 74 69 6f 6e 2f 31 2d 31 33 33 32 2d 31 33 30 30 30 34 37 32 30 30 30 2d 2d 2d 31 2e 6a 70 67A7CB0311812CD721ZUY0mH4Q20Izgt/9BNhpJl9OoOCp59DKxlH2JJ6K+sksyxI8lFtmJrJOk1imxM/AGmgRObHEFuirWPwaqRgdKiQK/EQ=PUT Sat, 26 Mar 2011 00:43:36 +0000 x-amz-acl:public-read /bucket/1-132-1301047200-1.jpg-removedセキュリティ - 0

しかし、適切にフォーマットされたリクエストを送信すると、認証されていないと表示されます:

使用されているクエリ:

PUT /1-132-1301047200-1.jpg HTTP/1.1 ホスト: bucket.s3.amazonaws.com 日付: Sat, 26 Mar 2011 00:41:50 +0000 x-amz-copy-source: /bucket/clock. jpg x-amz-acl: public-read Authorization: AWS -セキュリティのために削除されました-:BMiGhgbFnVAJyiderKjn1cT7cj4=

HTTP/1.1 403 禁止
x-amz-request-id: ABE45FD4DFD19927
x-amz-id-2: CnkMmoF550H1zBlrwwKfN8zoOSt7r/zud8mRuLqzzBrdGguotcvrpZ3aU4HR4RoO
Content-Type: application/xml
Transfer-Encoding: chunked
Date: Sat, 26 Mar 2011:5 00:41
サーバー: AmazonS3

AccessDenied
匿名ユーザーはオブジェクトをコピーできません。認証してください
ABE45FD4DFD19927CnkMmoF550H1zBlrwwKfN8zoOSt7r/zud8mRuLqzzBrdGguotcvrpZ3aU4HR4RoO 0
日付: 2011 年 3 月 26 日 00:41:50 GMT
接続: 閉じる
サーバー: AmazonS3

4

1 に答える 1

9

ウェブで入手可能な例を使用して、Amazon AWS S3 API への REST リクエストを適切にフォーマットするために何週間も試みてきました

Amazon AWS SDK for PHPを試しましたか? これは包括的で完全であり、最も重要なこととして、Amazon によって書かれています。独自のコードが機能しない場合は、何かが本当に間違っている可能性があります。


リンクされた 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 リクエストを送信して、ファイル名を現在の「アップロードされた」名前から、バックエンド (データベース、追跡など) で動作する新しい名前に変更することです。 MyySQL を使用して PHP で個別に処理および表示します)。

     AWS S3 は「コピー」機能を真にサポートしていないため、独自のバケットからソースを読み取り、別の名前の新しいコピーを同じバケットに配置することで、ファイルを再「PUT」する方法を提供しました。私が抱えていた問題は、REST リクエストの処理です。

     Flex アプリケーションを設計する前に機能していた PHP アップロードの作業コピーも持っているので、お時間をいただきありがとうございます。提供された例を理解しています。Flex の理由は、ステータスの更新と動的に更新される進行状況バーを有効にすることでした。これも魅力のように機能しています :)。

私は、Amason zsupport の観点から REST ソリューションを追求し続けます。それが、サポート チームごとにバケットに既に存在するファイルの名前を変更できる唯一の方法です。

いつものように、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 に答える