2016-02-02 11 views
6

Pracuję nad projektem obejmującym generowanie adresów URL S3, które ktoś inny może użyć do przesłania plików do mojego zasobnika S3. Oto minimalne przykład praca:AWS PHP SDK: Limit rozmiaru wysyłanego pliku S3 w adresie URL oznaczonym

<?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(); 

?> 

Teraz, jeśli mogę umieścić ten plik w miejscu dostępnym przez internet, mój serwer WWW może być wykorzystywane do pobierania nowych podpisane URL Dodano:

$ 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... 
$ 

Ten pomyślnie przesyła lokalny plik do mojego zasobnika, dzięki czemu mogę grać z nim w S3.

Załóżmy, że nie martwię się zbytnio o ludzi generujących wiele adresów URL i przesyłanie wielu plików do mojego zasobnika w krótkim czasie, ale chciałbym ograniczyć rozmiar przesyłanych plików. Wiele zasobów proponujemy dołączenie politykę podpisanego URL:

<?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(); 

?> 

Ta wersja generuje adresy URL (bez wskazania błędów), które mogą być używane w ten sam sposób. Nie jestem pewien, czy potrzebuję niektórych z tych warunków w polityce (acl, bucket, starts-with), ale nie sądzę, że włączenie ich złamałoby zasady.

Teoretycznie próba użycia tego podpisanego adresu URL do przesłania pliku większego niż 8 KiB powinna spowodować przerwanie przesyłania przez S3. Jednak badanie to z większego pliku pokazuje, że curl nadal szczęśliwie przesyła plik:

$ 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... 
$ 

Sprawdzanie wiadro pokazuje, że rzeczywiście duży plik został przesłany, a wielkość pliku jest większa niż polityka rzekomo wskazuje.

Ponieważ różne strony pokazują różne sposoby mocowania politykę, Próbowałem również następujących wersjach:

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

Jednak adresy generowane z dowolnego z tych wersji pozwalają pliki większe niż określony rozmiar, aby być przesłany.

Czy niepoprawnie załączyłem politykę, czy też istnieje zasadnicze ograniczenie w ograniczaniu przesyłania do S3 w ten sposób?

Dla mojego serwera WWW używam HHVM 3.11.1 z wersją 3.14.1 pakietu SDK AWS dla PHP.

Odpowiedz

3

Zasady przesyłania S3 nie można używać z wcześniej podpisanymi adresami URL.

Dokument zasad może być używany z browser uploads to S3 using HTML POST Forms.

Pre-podpisane URL i HTML POST tworzy są dwie różne metody przesyłania do S3. Ten pierwszy jest prawdopodobnie prostszy, ale mniej elastyczny niż ten drugi.

UPDATE

Jeśli trzeba przesłać pliki bez użycia przeglądarki, prośba HTML POST formularza może być powielana używając PHP curl funkcje biblioteki takie jak Guzzle, lub za pomocą wiersza polecenia w następujący sposób :

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

wiem, że formularze HTML POST są możliwe, ale nie jestem wyłącznie kierowania przeglądarek, tak że nie jest to rozwiązanie w moim przypadku. Dzieki za sugestie! – millinon

+0

Pola POST są nieco bardziej złożone niż to, do czego dążę - naprawdę chcę wygenerować pojedynczy adres URL, który można skopiować/wkleić do dowolnego klienta obsługującego protokół HTTP PUT. Bardzo lubię to rozwiązanie - klienci obsługujący HTTP PUT prawdopodobnie będą również obsługiwać pola POST, więc postaram się zapewnić to jako metodę przesyłania. – millinon

2

można spróbować dodać konkretną politykę do wiadra

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

i po tym, wystarczy użyć zwykłego polecenia putObject

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

Myślę, że to jest właściwy kierunek - muszę załączyć politykę do samego kubełka, a nie samego żądania PutObject. Wygląda jednak na to, że "zasięg treści o zakresie" jest obsługiwany tylko jako warunek zasady przesyłania za pomocą przeglądarki, więc nie jestem pewien, czy możliwe jest uwzględnienie ograniczenia rozmiaru pliku w adresie URL lub jako atrybut samego zasobnika. – millinon

+0

Czy ktoś może potwierdzić, czy to działa, czy nie? – CamHart