2012-12-03 22 views
14

Ecco il mio codice:Come velocizzare i file_get_contents?

$language = $_GET['soundtype']; 
$word = $_GET['sound']; 
$word = urlencode($word); 
if ($language == 'english') { 
    $url = "<the first url>"; 
} else if ($language == 'chinese') { 
    $url = "<the second url>"; 
} 
$opts = array(
    'http'=>array(
    'method'=>"GET", 
    'header'=>"User-Agent: <my user agent>" 
) 
); 
$context = stream_context_create($opts); 
$page = file_get_contents($url, false, $context); 
header('Content-Type: audio/mpeg'); 
echo $page; 

ma ho trovato che questo viene eseguito terribilmente lento.

Esistono metodi di ottimizzazione?

Nota:$url è un URL remoto.

+2

$ url è un percorso locale o un URL http: //? – Intrepidd

+0

@Intrepidd Sì, mi dispiace, un URL remoto. – think123

+1

Qual è la dimensione del file e molti secondi necessari per il recupero? Dividi uno per l'altro e troverai la larghezza di banda. Se è inaspettatamente lento, tu o il lato remoto avete bisogno di più! –

risposta

8

È lento perché file_get_contents() legge l'intero file in $page, PHP attende il file da ricevere prima di emettere il contenuto. Quindi quello che stai facendo è: scaricare l'intero file sul lato server, quindi emetterlo come una singola stringa enorme.

file_get_contents() non supporta lo streaming o l'acquisizione di offset del file remoto. Un'opzione è di creare un socket raw con fsockopen(), fare la richiesta HTTP e leggere la risposta in un ciclo, mentre leggi ogni chunk, inviarlo al browser. Questo sarà più veloce perché il file verrà trasmesso in streaming.

Esempio dal manuale:

$fp = fsockopen("www.example.com", 80, $errno, $errstr, 30); 
if (!$fp) { 
    echo "$errstr ($errno)<br />\n"; 
} else { 

    header('Content-Type: audio/mpeg'); 

    $out = "GET/HTTP/1.1\r\n"; 
    $out .= "Host: www.example.com\r\n"; 
    $out .= "Connection: Close\r\n\r\n"; 
    fwrite($fp, $out); 
    while (!feof($fp)) { 
     echo fgets($fp, 128); 
    } 
    fclose($fp); 
} 

che questo è un loop mentre c'è ancora disponibili contenuti, ad ogni iterazione legge 128 byte e quindi lo emette al browser. Lo stesso principio funzionerà per quello che stai facendo. Dovrai assicurarti di non generare le intestazioni HTTP di risposta che saranno le prime poche righe, perché poiché stai facendo una richiesta non elaborata, otterrai la risposta non elaborata con le intestazioni incluse. Se si generano le intestazioni di risposta si finisce con un file corrotto.

+1

Potresti fornire un esempio? 'fsockopen()' è greco per me. – think123

+0

@ think123 ha aggiunto un esempio – MrCode

+0

Ottima spiegazione! – jan267

2

Come spiegato da @MrCode, per prima cosa il download del file sul server, quindi il trasferimento sul client comporta naturalmente un tempo di download raddoppiato. Se si desidera passare direttamente il file al client, utilizzare readfile.

In alternativa, pensare se non si può semplicemente reindirizzare il client per l'URL del file utilizzando un header("Location: $url") modo che il cliente può ottenere il file direttamente dalla fonte.

+0

è possibile modificare l'agente utente della richiesta quando si utilizza 'readfile'? – think123

+0

Supporta anche una risorsa '$ context', quindi sì. – deceze

2

Invece di scaricare l'intero file prima di emetterlo, considerano lo streaming fuori in questo modo:

$in = fopen($url, 'rb', false, $context); 
$out = fopen('php://output', 'wb'); 

header('Content-Type: video/mpeg'); 
stream_copy_to_stream($in, $out); 

Se siete audaci, si potrebbe anche provare (ma questo è sicuramente sperimentale):

header('Content-Type: video/mpeg'); 
copy($url, 'php://output'); 

Un'altra opzione è l'uso di reindirizzamenti interni e la richiesta del proxy del server web. Quello libererebbe PHP per fare qualcos'altro. Vedi anche my post regarding X-Sendfile and friends.