2016-02-02 4 views
6

Ich arbeite an einem Projekt, bei dem S3-URLs generiert werden, die ein anderer Benutzer zum Hochladen von Dateien in meinen S3-Bucket verwenden kann. Hier ist ein minimales Arbeitsbeispiel:AWS PHP SDK: Dateigröße für S3-Datei in vordefinierter URL begrenzen

<?php 

    require('aws.phar'); 
    use Aws\S3\S3Client; 

    $s3client = new S3Client(...); // credentials go here 

    $id = uniqid(); // generate some kind of key 

    $command = $s3client->getCommand('PutObject', [ 
     'ACL' => 'private', 
     'Body' => '', 
     'Bucket' => 'mybucket', 
     'Key' => 'tmp/' . $id]); 

    echo (string) $s3client->createPresignedRequest($command, '+5 minutes')->getURI(); 

?> 

Nun, wenn ich diese Datei an einer Stelle gebracht werden, zugänglich durch das Internet, kann mein Web-Server verwendet werden, um neuen signierten Upload-URLs zu holen:

$ curl http://my.domain.com/some/page.php 
https://s3.amazonaws.com/mybucket/tmp/someID?x-amz-acl=private&lots-of-aws-params... 
$ curl -X PUT -d "@someFile" https://s3.amazonaws.com/mybucket/tmp/someID?x-amz-acl=private&lots-of-aws-params... 
$ 

Diese erfolgreich lädt eine lokale Datei in meinen Bucket, damit ich in S3 damit spielen kann.

Nehmen wir an, ich mache mir keine Gedanken darüber, dass viele Leute in kurzer Zeit viele URLs generieren und viele Dateien in meinen Bucket hochladen, aber ich möchte die Größe der hochgeladenen Dateien begrenzen. Viele Ressourcen empfehlen, eine Politik zu der signierten URL Befestigung:

<?php 

    require('aws.phar'); 
    use Aws\S3\S3Client; 

    $s3client = new S3Client(...); // credentials go here 

    $id = uniqid(); // generate some kind of key 

    $policy = [ 
     'conditions' => [ 
      ['acl' => 'private'], 
      ['bucket' => 'mybucket'], 
      ['content-length-range', 0, 8*1024], // 8 KiB 
      ['starts-with', '$key', 'tmp/'] 
     ], 'expiration' => 
      (new DateTime())->modify('+5 minutes')->format(DateTime::ATOM)]; 

    $command = $s3client->getCommand('PutObject', [ 
     'ACL' => 'private', 
     'Body' => '', 
     'Bucket' => 'mybucket', 
     'Key' => 'tmp/' . $id, 
     'Policy' => $policy]); 

    echo (string) $s3client->createPresignedRequest($command, '+5 minutes')->getURI(); 

?> 

Diese Version erzeugt URLS (ohne Angabe von Fehlern), die in gleicher Weise verwendet werden können. Ich bin nicht sicher, ob ich einige dieser Bedingungen in der Richtlinie (, bucket, starts-with) brauche, aber ich denke nicht, dass die Einbeziehung dieser Richtlinien die Richtlinie brechen würde.

Theoretisch sollte der Versuch, diese signierte URL zum Hochladen einer Datei größer als 8 KiB zu verwenden, dazu führen, dass S3 den Upload abbricht. Jedoch mit einer größeren Datei dieser Prüfung zeigt, dass curl immer noch glücklich die Datei hochgeladen:

$ ls -lh file.txt 
-rw-rw-r-- 1 millinon millinon 210K Jan 2 00:41 file.txt 
$ curl http://my.domain.com/some/page.php 
https://s3.amazonaws.com/mybucket/tmp/someOtherID?x-amz-acl=private&lots-of-aws-params... 
$ curl -X PUT -d "@file.txt" https://s3.amazonaws.com/mybucket/tmp/someOtherID?x-amz-acl=private&lots-of-aws-params... 
$ 

den Eimers Überprüfung zeigt, dass in der Tat, die große Datei hochgeladen wurde, und die Größe der Datei größer als die Politik angeblich anzeigt.

Da verschiedene Seiten zeigen verschiedene Möglichkeiten, die Politik anbringen, habe ich versucht, auch die folgenden Versionen:

'Policy' => json_encode($policy) 
'Policy' => base64_encode(json_encode($policy)) 

jedoch URLs erzeugt mit jeder dieser Versionen von Dateien größer als die angegebene Größe erlauben hochgeladen werden.

Füge ich die Richtlinie falsch an, oder gibt es eine grundlegende Einschränkung, um Uploads auf S3 auf diese Weise zu beschränken?

Für meinen Webserver verwende ich HHVM 3.11.1 mit Version 3.14.1 des AWS SDK für PHP.

Antwort

3

Eine S3-Upload-Richtlinie kann nicht mit vor-signierten URLs verwendet werden.

Ein Richtliniendokument kann mit browser uploads to S3 using HTML POST Forms verwendet werden.

Pre-signierten URLs und HTML POST bildet sind zwei verschiedene Methoden der bis S3 hochladen. Ersteres ist wohl einfacher, aber weniger flexibel als letzteres.

UPDATE

Wenn Sie die Dateien ohne die Verwendung eines Browsers kann die HTML-POST-Formular Antrag curl Funktionen von PHP reproduziert werden hochladen müssen, eine Bibliothek wie Guzzle, oder über die Befehlszeile wie folgt :

curl 'https://s3-bucket.s3.amazonaws.com/' \ 
    -F 'key=uploads/${filename}' \ 
    -F 'AWSAccessKeyId=YOUR_AWS_ACCESS_KEY' \ 
    -F 'acl=private' \ 
    -F 'success_action_redirect=http://localhost/' \ 
    -F 'policy=YOUR_POLICY_DOCUMENT_BASE64_ENCODED' \ 
    -F 'signature=YOUR_CALCULATED_SIGNATURE' \ 
    -F 'Content-Type=image/jpeg' \ 
    -F '[email protected]' 
+0

Ich weiß, dass HTML-POST bildet eine Option, aber ich bin nicht ausschließlich Browser-Targeting, das ist so keine Lösung in meinem Fall. Danke für den Vorschlag! – millinon

+0

POST-Felder sind ein bisschen komplexer als das, was ich anstrebe - ich möchte wirklich nur eine einzige URL erzeugen, die kopiert/eingefügt werden kann in jeden Client, der HTTP PUT unterstützt. Ich mag diese Lösung jedoch sehr - Clients, die HTTP PUT unterstützen, werden wahrscheinlich auch POST-Felder unterstützen, daher werde ich mich bemühen, dies als eine Methode zum Hochladen bereitzustellen. – millinon

2

können Sie versuchen, die spezifische Politik zu Ihrem Eimer

$s3client->putBucketPolicy(array(
    'Bucket' => $bucket, 
    'Policy' => json_encode(array(
     'conditions' => array(
      array(
       'content-length-range', 0, 8*1024, 
       'starts-with', '$key', 'tmp/' 
       ... 
hinzufügen

und danach, benutzen Sie einfach den normalen putObject Befehl

$command = $s3client->getCommand('PutObject', [ 
    'ACL' => 'private', 
    'Body' => '', 
    'Bucket' => 'mybucket', 
    'Key' => 'tmp/' . $id]); 
+0

Ich denke, das ist die richtige Richtung - ich muss die Richtlinie an den Bucket selbst anfügen, nicht die PutObject-Anfrage selbst. Es scheint jedoch so zu sein, dass 'content-length-range' nur als Bedingung für den Upload von Browser-Informationen unterstützt wird. Daher bin ich mir nicht sicher, ob es möglich ist, eine Dateigrößenbeschränkung in eine vordefinierte URL oder als Attribut des Buckets selbst aufzunehmen. – millinon

+0

Kann jemand bestätigen, ob das funktioniert oder nicht? – CamHart