Вот мой код:
$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-адрес.
Это медленно, потому что 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-заголовки ответов, которые будут первыми несколькими строками, потому что, поскольку вы делаете необработанный запрос, вы получите исходный ответ с включенными заголовками. Если вы выведете заголовки ответов, вы получите поврежденный файл.
Как объяснил @MrCode, сначала загрузить файл на ваш сервер, а затем передать его клиенту, конечно же, придется удвоить время загрузки. Если вы хотите напрямую передать файл клиенту, используйте readfile
.
В качестве альтернативы подумайте, не можете ли вы просто перенаправить клиента на URL-адрес файла с помощью header("Location: $url")
чтобы клиент мог получить файл непосредственно из источника.
Вместо того, чтобы загружать весь файл перед его выпуском, рассмотрите возможность его потоковой передачи следующим образом:
$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 и друзьях .