2013-04-11 16 views
7

Benim dosyam (126 MB boyutunda, .exe) bana sorun veriyor.Laravel'de neden büyük dosyalar kolayca indirilemiyor?

Standart laravel indirme yöntemini kullanıyorum.

Belleği artırmayı denedim ancak yine de bellek tükendiğimi ya da 0 KB boyutunda bir dosya indirdiğimi söylüyor.

Dokümantasyon, büyük dosya boyutları hakkında bir şey ifade etmiyor.

Kodum ben yanlış yapıyorum

ini_set("memory_limit","-1"); // Trying to see if this works 
return Response::download($full_path); 

şey nedir? Düzenleme - -

Phill Sparks comment Olsam

, bu şimdiye ne var ve o çalışır. Phill'in artı bir kısmı php.net'in bir birleşimi. Eksik bir şey olup olmadığından emin değil misiniz?

public static function big_download($path, $name = null, array $headers = array()) 
{ 
    if (is_null($name)) $name = basename($path); 

    // Prepare the headers 
    $headers = array_merge(array(
     'Content-Description'  => 'File Transfer', 
     'Content-Type'    => File::mime(File::extension($path)), 
     'Content-Transfer-Encoding' => 'binary', 
     'Expires'     => 0, 
     'Cache-Control'    => 'must-revalidate, post-check=0, pre-check=0', 
     'Pragma'     => 'public', 
     'Content-Length'   => File::size($path), 
    ), $headers); 

    $response = new Response('', 200, $headers); 
    $response->header('Content-Disposition', $response->disposition($name)); 

    // If there's a session we should save it now 
    if (Config::get('session.driver') !== '') 
    { 
     Session::save(); 
    } 

    // Below is from http://uk1.php.net/manual/en/function.fpassthru.php comments 
    session_write_close(); 
    ob_end_clean(); 
    $response->send_headers(); 
    if ($file = fopen($path, 'rb')) { 
     while(!feof($file) and (connection_status()==0)) { 
      print(fread($file, 1024*8)); 
      flush(); 
     } 
     fclose($file); 
    } 

    // Finish off, like Laravel would 
    Event::fire('laravel.done', array($response)); 
    $response->foundation->finish(); 

    exit; 
} 

cevap

13

bu olur çünkü Response::download() yükler kullanıcıya servis etmeden önce belleğe dosya. Kuşkusuz bu, çerçevedeki bir kusurdur, ancak çoğu insan çerçeve aracılığıyla büyük dosyalara hizmet etmeye çalışmamaktadır.

Çözüm 1 - İndirmek istediğiniz dosyaları genel klasöre, statik bir etki alanına veya CDvel'i tam bypass edin.

Anlaşılacağı üzere, sen

function sendFile($path, $name = null, array $headers = array()) 
{ 
    if (is_null($name)) $name = basename($path); 

    // Prepare the headers 
    $headers = array_merge(array(
     'Content-Description'  => 'File Transfer', 
     'Content-Type'    => File::mime(File::extension($path)), 
     'Content-Transfer-Encoding' => 'binary', 
     'Expires'     => 0, 
     'Cache-Control'    => 'must-revalidate, post-check=0, pre-check=0', 
     'Pragma'     => 'public', 
     'Content-Length'   => File::size($path), 
    ), $headers); 

    $response = new Response('', 200, $headers); 
    $response->header('Content-Disposition', $response->disposition($name)); 

    // If there's a session we should save it now 
    if (Config::get('session.driver') !== '') 
    { 
     Session::save(); 
    } 

    // Send the headers and the file 
    ob_end_clean(); 
    $response->send_headers(); 

    if ($fp = fread($path, 'rb')) { 
     while(!feof($fp) and (connection_status()==0)) { 
      print(fread($fp, 8192)); 
      flush(); 
     } 
    } 

    // Finish off, like Laravel would 
    Event::fire('laravel.done', array($response)); 
    $response->foundation->finish(); 

    exit; 
} 

Bu fonksiyon ... bu durumda, böyle bir şey çalışması gerekir Kendi indirme yöntemi zanaat gerekir, giriş yaparak yüklemeler erişimi kısıtlamak için çalışıyor olabilir Response::download() ve Laravel'in shutdown process birleşimidir. Kendimi test etme şansım olmadı, işte Laravel 3 yüklü değil. İşi sizin için yaparsa lütfen bana bildirin.

PS: Bu betiğin ilgilenmediği tek şey, çerezlerdir. Maalesef Response::cookies() işlevi korunmaktadır. Bu bir sorun olursa, kodu işlevden kaldırabilir ve sendFile yönteminize koyabilirsiniz.

PPS:olabilir çıktı arabelleği ile ilgili bir sorun olabilir; Bir sorun varsa, readfile() examples PHP kılavuzunda bir göz var, orada çalışması gereken bir yöntem var.

PPP'ler: ikili dosyalarla çalışıyorsanız beri fpassthru()

DÜZENLEME ile readfile() yerine düşünebilirsiniz: Disregard PPS ve KÖSO'lar ben fread + kullanmak için kod güncelledik Bunun yerine baskı daha kararlı görünüyor.

+0

Neredeyse işe yaradı, hem readfile hem de fpassthru() ile hatalı bulunamadı dosya alıyorum. Ama bağlantılara baktım ve işe yarayan bir şey yapmak için seninle birleştirdim. Ne kadar doğru olduğundan emin değil miyim? Sonuncuyu göstermek için sorumu düzenledim. – Lango

+0

Merhaba @Lango, Çözümünüzle ilgili herhangi bir sorun göremiyorum. Yanıtımı, fread + print yaklaşımını ve 'ob_get_clean()' da dahil etmek için güncelledim. Fpassthru'nun neden aynı dosya tanıtıcısını kullandıklarından, fpassthru'nun neden işe yaramayacağını göremiyorum - ama eğer sizin için çalışıyorsa o zaman onunla yuvarlanın! –

+0

Teşekkürler Phill! Şimdi her şey çalışıyor. – Lango

0

Çok sevdiği memory_limit artırmak gerekir:

Sen ini_set işlevini kullanarak memory_limit artırmak gerekir örneğin ini_set('memory_limit','128M');

Bu umarım için çalışacak!

burada cevap buldu: https://stackoverflow.com/a/12443644/1379394

+1

("memory_limit", "- 1") ini_set etmez; yap bunu? – Lango

+0

Dosyanın büyüklüğü olmalı mı? – Lango

+0

no dosyasının boyutu olmak zorunda değil. ve -1 çalışmıyor. –

3

php.net here numaralı belgede belirtilen şekilde readfile_chunked() özel yöntemini kullanıyorum. Laravel 3 için, böyle tepki yöntemi uzattığımızı:

applications/libraries/response.php

<?php 
class Response extends Laravel\Response { 

    //http://www.php.net/manual/en/function.readfile.php#54295 
    public static function readfile_chunked($filename,$retbytes=true) { 
     $chunksize = 1*(1024*1024); // how many bytes per chunk 
     $buffer = ''; 
     $cnt =0; 
     // $handle = fopen($filename, 'rb'); 
     $handle = fopen($filename, 'rb'); 
     if ($handle === false) { 
      return false; 
     } 
     while (!feof($handle)) { 
      $buffer = fread($handle, $chunksize); 
      echo $buffer; 
      ob_flush(); 
      flush(); 
      if ($retbytes) { 
       $cnt += strlen($buffer); 
      } 
     } 
      $status = fclose($handle); 
     if ($retbytes && $status) { 
      return $cnt; // return num. bytes delivered like readfile() does. 
     } 
     return $status; 

    } 
} 

olarak bu dosyayı ekleyin Sonra application/config/application.php bu satırı yorum:

'Response'  => 'Laravel\\Response', 

Örnek kod:

//return Response::download(Config::get('myconfig.files_folder').$file->upload, $file->title); 

header('Content-Description: File Transfer'); 
header('Content-Type: application/octet-stream'); 
header('Content-Disposition: attachment; filename='.$file->title); 
header('Content-Transfer-Encoding: binary'); 
header('Expires: 0'); 
header('Cache-Control: must-revalidate'); 
header('Pragma: public'); 
header('Content-Length: ' . File::size(Config::get('myconfig.files_folder').$file->upload)); 
ob_clean(); 
flush(); 
Response::readfile_chunked(Config::get('myconfig.files_folder').$file->upload); 
exit; 

Şimdiye kadar yapılmış harika işler.

2

Sen Symfony \ Bileşeni kullanmak \ HttpFoundation \ StreamedResponse böyle edebilirsiniz: Daha fazla bilgi için

$response = new StreamedResponse(
    function() use ($filePath, $fileName) { 
     // Open output stream 
     if ($file = fopen($filePath, 'rb')) { 
      while(!feof($file) and (connection_status()==0)) { 
       print(fread($file, 1024*8)); 
       flush(); 
      } 
      fclose($file); 
     } 
    }, 
    200, 
    [ 
     'Content-Type' => 'application/octet-stream', 
     'Content-Disposition' => 'attachment; filename="' . $fileName . '"', 
    ]); 

return $response; 

kontrol this

İlgili konular