Как ускорить файл_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;
Но я обнаружил, что это работает очень медленно.
Существуют ли какие-либо возможные методы оптимизации?
Примечание. $url
- удаленный URL.
Ответы
Ответ 1
Это медленно, потому что file_get_contents()
читает весь файл в $page
, PHP ждет, пока файл будет получен до вывода содержимого. Итак, что вы делаете: загрузка всего файла на стороне сервера, а затем вывод его как одна огромная строка.
file_get_contents()
не поддерживает потоковые или захватывающие смещения удаленного файла. Опция состоит в том, чтобы создать сырой сокет с fsockopen()
, выполнить HTTP-запрос и прочитать ответ в цикле, когда вы читаете каждый фрагмент, выведите его в браузер. Это будет быстрее, потому что файл будет передан.
Пример из руководства:
$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);
}
Вышеописанный цикл, пока имеется доступный контент, на каждой итерации он считывает 128 байт, а затем выводит его в браузер. Тот же принцип будет работать для того, что вы делаете. Вам нужно убедиться, что вы не выведете HTTP-заголовки ответов, которые будут первыми несколькими строками, потому что, поскольку вы делаете необработанный запрос, вы получите исходный ответ с включенными заголовками. Если вы выведете заголовки ответов, вы получите поврежденный файл.
Ответ 2
Как объясняется @MrCode, сначала загружая файл на ваш сервер, то передача его клиенту, конечно же, приведет к удвоенному времени загрузки. Если вы хотите передать файл непосредственно клиенту, используйте readfile
.
В качестве альтернативы подумайте, не можете ли вы просто перенаправить клиента на URL-адрес файла с помощью header("Location: $url")
, чтобы клиент мог получить файл непосредственно из источника.
Ответ 3
Вместо того, чтобы загружать весь файл перед его выходом, рассмотрите возможность его потоковой передачи следующим образом:
$in = fopen($url, 'rb', false, $context);
$out = fopen('php://output', 'wb');
header('Content-Type: video/mpeg');
stream_copy_to_stream($in, $out);
Если вы смел, вы даже можете попробовать (но это определенно экспериментально):
header('Content-Type: video/mpeg');
copy($url, 'php://output');
Другой вариант - использование внутренних переадресаций и предоставление прокси-сервера веб-сервера для вас. Это освободит PHP, чтобы сделать что-то еще. См. Также мое сообщение о X-Sendfile и друзьях.