2016-07-08 37 views
2

私はユーザーがファイルをアップロードできるLaravel Webアプリケーションを持っています。これらのファイルは機密性があり、S3に保存されていますが、私のWebサーバー(ストリーム配信されたもの)を介してのみアクセスされます。アップロードされたユーザは、これらのファイルの選択肢をダウンロードしたい場合があります。PHPでS3に保存されたファイルからzipファイルを作成する

以前にユーザーが選択したファイルをダウンロードすると、WebサーバーはS3からファイルをダウンロードし、ローカルで圧縮してからクライアントに送信します。しかし、ファイルサイズのために生産されると、サーバーの応答はしばしばタイムアウトします。

代替方法として、ファイルをフライでZipStream経由で圧縮したいが、私はあまり運がなかった。 zipファイルは、破損したファイルで終わるか、またはそれ自体が壊れており、信じられないほど小さいものです。

S3上のファイルのストリームリソースをZipStreamに渡すことができ、私のタイムアウトの問題を解決する最良の方法は何ですか?

私は次のように私の最も最近の二つがあり、いくつかの方法を試してみました:

// First method using fopen 
// Results in tiny corrupt zip files 
if (!($fp = fopen("s3://{$bucket}/{$key}", 'r'))) 
{ 
    die('Could not open stream for reading'); 
} 

$zip->addFileFromPath($file->orginal_filename, "s3://{$bucket}/{$key}"); 
fclose($fp); 


// Second method tried get download the file from s3 before sipping 
// Results in a reasonable sized zip file that is corrupt 
$contents = file_get_contents("s3://{$bucket}/{$key}"); 

$zip->addFile($file->orginal_filename, $contents); 

は、これらのそれぞれが、それぞれのファイルを経由するループ内で座っています。ループの後、私は$ zip-> finish()を呼び出します。

注ファイルが壊れているだけのPHPエラーはありません。

答えて

3

最終的には、署名されたS3のURLとカールを使用して、s3 bucket steam zip phpで示すようにZipStreamのファイルストリームを提供するというソリューションでした。次のように前述のソースから編集結果のコードは次のとおりです。

public function downloadZip() 
{ 
    // ... 

    $s3 = Storage::disk('s3'); 
    $client = $s3->getDriver()->getAdapter()->getClient(); 
    $client->registerStreamWrapper(); 
    $expiry = "+10 minutes"; 

    // Create a new zipstream object 
    $zip = new ZipStream($zipName . '.zip'); 

    foreach($files as $file) 
    { 
     $filename = $file->original_filename; 

     // We need to use a command to get a request for the S3 object 
     // and then we can get the presigned URL. 
     $command = $client->getCommand('GetObject', [ 
      'Bucket' => config('filesystems.disks.s3.bucket'), 
      'Key' => $file->path() 
     ]); 

     $signedUrl = $request = $client->createPresignedRequest($command, $expiry)->getUri(); 

     // We want to fetch the file to a file pointer so we create it here 
     // and create a curl request and store the response into the file 
     // pointer. 
     // After we've fetched the file we add the file to the zip file using 
     // the file pointer and then we close the curl request and the file 
     // pointer. 
     // Closing the file pointer removes the file. 
     $fp = tmpfile(); 
     $ch = curl_init($signedUrl); 
     curl_setopt($ch, CURLOPT_TIMEOUT, 120); 
     curl_setopt($ch, CURLOPT_FILE, $fp); 
     curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); 
     curl_exec($ch); 
     curl_close($ch); 
     $zip->addFileFromStream($filename, $fp); 
     fclose($fp); 
    } 

    $zip->finish(); 
} 

注これはインストールして、サーバー上で機能しているカールとのphp-カールが必要です。

+0

こんにちはキュービクル私はあなたの関数を試してみましたが、zipファイルに追加するときに0バイトのファイルが得られる以外はすべて正常に動作しているようですが、私はサンプル関数も試しました fwrite($ fp、 'クイックブラウンキツネ怠惰な犬。 '); $ zip-> addFileFromStream( 'goodbye.txt'、$ fp); fclose($ fp); と同じことを得る。どんな助けでも大歓迎です。 thanx – rbz

+0

fwriteを試してみると、カールコールを削除していますか?ファイルが存在するが0バイトのファイルである場合、通常はファイルポインタが割り当てられていないことを意味します。上記のサンプルコードの – cubiclewar

+0

には、fwrite()はありません。 – rbz

関連する問題