Perché readfile() esaurisce la memoria PHP?




memory (4)

Bene, è una funzione intensiva della memoria. Conducevo gli utenti a un server statico che dispone di un set di regole specifico per controllare i download anziché utilizzare readfile ().

Se questa non è un'opzione, aggiungere più RAM per soddisfare il carico o introdurre il sistema di accodamento che controlla con garbo l'utilizzo del server.

Ho visto molte domande su come utilizzare in modo efficiente PHP per scaricare file piuttosto che consentire richieste dirette HTTP (per mantenere i file sicuri, per tenere traccia dei download, ecc.).

La risposta è quasi sempre PHP readfile () .

MA, anche se funziona alla grande durante i test con file enormi, quando si trova su un sito live con centinaia di utenti, i download iniziano a bloccarsi ei limiti di memoria PHP sono esauriti.

Quindi, di cosa parla il funzionamento di readfile() che fa sì che la memoria readfile() così male quando il traffico è alto? Pensavo che avrebbe dovuto aggirare l'uso pesante della memoria PHP scrivendo direttamente sul buffer di output?

EDIT: (Per chiarire, sto cercando un "perché", non "cosa posso fare". Penso che mod_xsendfile di Apache sia il modo migliore per aggirare)


Description
int readfile ( string $filename [, bool $use_include_path = false [, resource $context ]] )
Reads a file and writes it to the output buffer*.

PHP deve leggere il file e scrive nel buffer di output. Quindi, per il file 300Mb, non importa quale sia l'implementazione che hai scritto (da molti piccoli segmenti, o da 1 grosso pezzo), PHP deve leggere fino a 300Mb di file alla fine.

Se più utenti devono scaricare il file, ci sarà un problema. (In un server, i provider di hosting limiteranno la memoria fornita a ciascun utente ospitante, con una memoria così limitata, l'utilizzo del buffer non sarà una buona idea.)

Penso che usare il collegamento diretto per scaricare un file sia un approccio molto migliore per i file di grandi dimensioni.


Se hai attivato il buffering dell'output di usare ob_end_flush () subito prima della chiamata a readfile ()

header(...);
ob_end_flush();
@readfile($file);

È venuta in mente questa idea in passato (come parte della mia libreria) per evitare un utilizzo elevato della memoria:

function suTunnelStream( $sUrl, $sMimeType, $sCharType = null )
{
  $f = @fopen( $sUrl, 'rb' );
  if( $f === false )
   { return false; }

  $b = false;
  $u = true;

  while( $u !== false && !feof($f ))
  { 
    $u = @fread( $f, 1024 );
    if( $u !== false )
    {  
      if( !$b )
       { $b = true;
         suClearOutputBuffers();
         suCachedHeader( 0, $sMimeType, $sCharType, null, !suIsValidString($sCharType)?('content-disposition: attachment; filename="'.suUniqueId($sUrl).'"'):null );
       } 
      echo $u; 
    }
 } 

  @fclose( $f );
  return ( $b && $u !== false );
}

Forse questo può darti un po 'd'ispirazione.





readfile