2016-07-08 3 views
2

사용자가 파일을 업로드 할 수있는 Laravel 웹 앱이 있습니다. 이러한 파일은 민감 할 수 있으며 S3에 저장되어 있지만 웹 서버 (스트리밍 다운로드)를 통해서만 액세스 할 수 있습니다. 업로드 된 사용자는 이러한 파일 중 일부를 다운로드 할 수 있습니다.PHP를 사용하여 S3에 저장된 파일에서 zip 파일 만들기

이전에 사용자가 웹 서버가 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

마지막으로 해결책은 signed S3 url 's와 curl을 사용하여 s3 bucket steam zip php에 의해 입증 된 것처럼 ZipStream에 대한 파일 스트림을 제공하는 것이 었습니다. 다음과 같이 언급 한 소스에서 편집 된 결과 코드는 다음과 같습니다이 컬와 PHP 컬 필요

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

주를 설치하고 서버에 역할을하고있는 것.

+0

안녕하세요 cubiclewar 난 당신의 기능을 시도하고 모든 건 잘 작동하는 것만 제외하고 나는 0 바이트 파일을 Zip 파일에 추가 할 때, 나는 또한 예제 함수를 시도했다 fwrite ($ fp, '빠른 갈색 여우가 게으른 개. '); $ zip-> addFileFromStream ('goodbye.txt', $ fp); fclose ($ fp); 그리고 같은 것을 얻는 것. 어떤 도움이라도 대단히 감사하겠습니다. 고맙습니다 – rbz

+0

fwrite를 시도 할 때 컬 (curl) 호출을 제거하고 있습니까? 파일이 있지만 0 바이트 파일 인 경우 대개 파일 포인터가 지정되지 않습니다. 위에서 작성한 예제 코드에 – cubiclewar

+0

이 있으면 fwrite()가 없습니다. – rbz

관련 문제