ugrás a tartalomhoz

Nagy fájlok kiszolgálása PHP-vel

mahoo · 2012. Jún. 28. (Cs), 18.17
Jelenleg egy 56M-ás fájlt szeretnék letöltésre kiszolgálni, de a "Fájl nem található" üzenetet kapom a böngészőtől.

Amit eddig próbáltam: http://php.net/manual/en/function.readfile.php#48683
Illetve a memória limit 128M-án van.

A 3xM-os fájlt vagy kisebbel nincs gond.

Merre induljak, milyen beállítással lehet esetleg gond?
 
1

Megoldás

Hidvégi Gábor · 2012. Jún. 28. (Cs), 19.15
Olyan parancsot használj a fájl beolvasására, ami nem az egészet veszi, hanem darabokban végzi el egy pointer segítségével. Közben ideiglenesen altathatod a script futását, így gyakorlatilag szabályozod a letöltési sebességet.
2

Szerintem a php.net-es példa

mahoo · 2012. Jún. 28. (Cs), 22.20
Szerintem a php.net-es példa is darabokban olvassa be a fájlt, vagy másfajta megoldásra gondolsz. Bár az tény, hogy altatás nincs benne.
3

Nem jó

janoszen · 2012. Jún. 28. (Cs), 22.27
Alapvetően a statikus fájlok kiszolgálása PHP-val nagyon rossz ötlet, mert agyonvered az operációs rendszer saját cache-selését. Ha már muszáj a letöltést lassítanod, akkor ezt inkább az operációs rendszer szintjén oldd meg.

Ezt elmondva az a megoldás, hogy darabonként olvasol és nyomod ki a böngészőnek a tartalmat, tehát valahogy így:
  1. if (($fp = fopen('nagyfile.bin''rb')) !== false) {  
  2.     while (!feof($fp)) {  
  3.         echo(fread($fp, 4096));  
  4.         flush();  
  5.     }  
  6.     fclose($fp);  
  7. }  
Természetesen arra figyelni kell, hogy ha az output buffering aktív, akkor előbb abból ki kell lépni, különben a PHP gyűjtögeti memóriában a tartalmat:
  1. while (ob_get_level()) {  
  2.     ob_end_flush();  
  3. }  
4

Sajnos, sehogy sem megy...

mahoo · 2012. Jún. 29. (P), 06.47
Sajnos, sehogy sem megy... egyelőre... kutatok tovább.
5

Debug

janoszen · 2012. Jún. 29. (P), 09.18
Akkor allj neki debuggolni. xdebuggal tudod nezni, hogy mit csinal a PHP, hol szall el. Wiresharkkal tudod nezni a halozati forgalmat. A hibalogban pedig megtalalod, ha volt valami kohoges. Kulonosen ha az error_reporting opcioban bekapcsolod a notice-okat.

Egyebkent egy kitakaritott valtozatot felmasolhatnal valahova, had nezzem meg. Nem letezik, hogy ez ne mukodjon.

Egyebkent mi az uzleti motivacio emogott a megoldas mogott? Ha elmondod, lehet hogy tudok sokkal jobb megoldast mondani, mert ez igy elegge hackeles szagu.
6

Darabokban

joed · 2012. Jún. 29. (P), 15.30
Darabokban told ki kliensnek a fájlt, ha már nagyon PHP-ban kell megoldanod.

Pl.:
  1. [...]  
  2.   
  3. const CHUNK_SIZE = 1024;  
  4.   
  5. /** 
  6.  * @param $filename string Path to file that is going to be sent 
  7.  */  
  8. public static function readfile_chunked($filename) {  
  9.     global $sentCounter;  
  10.     $buffer = '';  
  11.     $handle = fopen($filename'rb');  
  12.     if ($handle === false) {  
  13.         throw new Exception("Unknown file.");  
  14.     }  
  15.     while (!feof($handle)) {  
  16.         $buffer = fread($handle, self::CHUNK_SIZE);  
  17.         echo $buffer;         
  18.         $sentCounter += strlen($buffer);  
  19.         ob_flush();  
  20.     }     
  21.     fclose($handle);  
  22. }  
  23.   
  24. [...]  
  25.   
  26. $fd = {Fájl részletei};  
  27.   
  28. set_time_limit(0);  
  29. ob_clean();  
  30. header('Content-Description: File Transfer');  
  31. header("Pragma: public");  
  32. header("Expires: 0");  
  33. header("Cache-Control: must-revalidate, post-check=0, pre-check=0");  
  34. header("Cache-Control: private", false);  
  35. header("Content-Type: {$fd->mimetype}");  
  36. header("Content-Disposition: attachment; filename=\"{$fd->filename}\"");  
  37. header("Content-Transfer-Encoding: binary");  
  38. header("Content-Length: " . $fd->size);  
  39. {OSZTALYOD}::readfile_chunked($fd->path);  
  40. ob_end_flush();  
  41. exit;  
De ahogy Janoszenszej is mondta, nem tanácsos ilyen feladattal szívatni a szervert, inkább bízd valamilyen célszoftverre, mint pl. a Zend Download Server.
7

Nem voltam időm ma

mahoo · 2012. Jún. 29. (P), 22.40
Nem voltam időm ma próbálkozni csak most, és ezzel a kódrészlettel megy :) köszönöm joed!

De ami a legjobb, hogy most megint megpróbáltam janoszen I proclub példájával és azzal is megy... igen én voltam béna, a file pointer-t nem (jól) állítottam be. Szóval neked is nagyon köszönöm a segítséget janoszen I proclub és elnézést, hogy a bénaságommal félrevezettelek!

Egyébként én erősen a kezdő kategóriába tartozom, és semmiféle hack-elési szándék nincs a feladat mögött csak nem voltam tisztában azzal, hogy az ilyen típusú feladatot más módszerrel illik megoldani.

Szóval nagyon hasznosak voltak a tanácsok!!!