Как ускорить файл_get_contents? - программирование
Подтвердить что ты не робот

Как ускорить файл_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.

4b9b3361

Ответ 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 и друзьях.