2016-12-13 54 views
1

我正在接收文件(最多4 GB):文件內容在POST請求的主體中流式傳輸給我。 我想直接將此流上傳到s3存儲桶,而無需先在本地保存。 已經嘗試了不同的方法,失敗的原因不同。S3:putObject()通過POST接收的流

我目前的做法:

use GuzzleHttp\Psr7\Stream; 
use Aws\S3\S3Client; 

$s3 = new \Aws\S3\S3Client([ 
    'version' => 'latest', 
    'region' => 'eu-west-1', 
    'credentials' => [ 
     'key' => 'abc', 
     'secret' => '123' 
    ] 
]); 

$stream = new \GuzzleHttp\Psr7\Stream(fopen('php://input', 'r')); 

$result = $s3->putObject(array(
    'Bucket' => $bucket, 
    'Key' => $keyname, 
    'ContentLength' => (int)$_SERVER['CONTENT_LENGTH'], 
    'Body' => $stream->getContents(), 
    'ACL' => 'private', 
    'StorageClass' => 'STANDARD_IA', 
)); 

試圖流80 MB的文件時出現以下錯誤:

PHP message: PHP Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 78847383 bytes) in /var/www/slimapi/vendor/slim/slim/Slim/Http/Stream.php on line 403 
Stream.php的

線403:

if (!$this->isReadable() || ($contents = stream_get_contents($this->stream)) === false) { 

所以這個錯誤可能是由於triying將整個流的內容加載到一個字符串中而導致的,該字符串超過了內存限制。 (有刺激性的,爲什麼錯誤修身/流中存在的,因爲我想用狂飲\流)

所以我的問題是: 我怎麼能流直接進入POST數據到S3鬥而不緩衝問題導致內存問題?

我已經嘗試:

  • $流= PSR7 \ stream_for(的fopen( 'PHP://輸入', 'R'));
  • $ stream = fopen('php:// input','r');
  • 內putObject(): '體'=>流::工廠(的fopen( 'PHP://輸入', 'R')),
+0

它總是可以幫助您展示嘗試了各種方法,這有助於消除我們會爲您提供任何無益或已經失敗了建議。 –

回答

0

即PHP SDK呼叫不支持直接讀取一流。所以看起來發生在我身上的是PHP在耗盡內存,因爲它在將流中的整個對象加載到變量之前,實際上調用SDK將該數據串放入對象。你可以考慮使用S3 Stream Wrapper

這個例子看起來最合適,但你需要在兩個流之間傳遞數據。雖然S3 Stream Wrapper似乎支持通過本地文件創建流,但我沒有看到將現有流傳遞給它的直接示例。

在這個例子中,如果可用的話,我們從源代碼讀取4096個字節(如果4096不可用,或者如果返回值不是空的,那麼我們將它寫入S3對象。源達到EOF(在這個例子中源必須支持和EOF)。

$client = new Aws\S3\S3Client([/** options **/]); 

// Register the stream wrapper from an S3Client object 
$client->registerStreamWrapper(); 

$stream = fopen('s3://bucket/key', 'w'); 
while (!$stream_source->stream_eof()) { 
    $string = $stream_source->stream_read (4096) 
    if (!empty($string)) { 
     fwrite($stream, $string); 
    } 
} 
fclose($stream);