загружается намного медленнее, чем при чтении файла


Я отправляю загрузки с URL-адреса своим пользователям с помощью PHP-скрипта. При использовании readfile() я получаю максимальную скорость загрузки, которую может поддерживать мое соединение (около 2,5 МБ/с), однако при использовании маршрута fopen, fread, fclose скорость загрузки очень, очень низкая (около 1-2 КБ/с).

Вот мой код:

header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename=' . $filename);
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . $filesize);
ob_clean();
flush();

$file = fopen($url, 'rb');

while(!feof($file)) {
    echo fread($file, 2014);
}

И код для чтения файла просто readfile($link);.

Я не могу просто использовать функцию readfile() по двум причинам, одна из которых заключается в том, что я хочу ограничить скорость загрузки пользователей (что я могу сделать с fread только читая так много данных), и я также хочу отслеживать, сколько загружает пользователь (я могу сделать это с помощью readfile(), но это не учитывает частичные загрузки).

Кто-нибудь знает, почему это может происходить или как я могу это исправить? Насколько я знаю, readfile() - это просто оболочка для fopen, fread and fclose, поэтому я не понимаю, что происходит не так.

Редактировать: В итоге для этого пришлось использовать cURL.

$curl = curl_init();
$options = array(
    CURLOPT_URL => $rdLink,
    CURLOPT_FAILONERROR => true,
    CURLOPT_BINARYTRANSFER => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_WRITEFUNCTION => 'readResponse'
);
curl_setopt_array($curl, $options);

if(!curl_exec($curl)) {
    header('Location: http://whatever.com');
    exit;
}
curl_close($curl);

function readResponse($ch, $data) {
    $length = mb_strlen($data, '8bit');

    echo $data;

    return $length;
}
Author: James Dawson, 2013-02-02

3 answers

Используйте stream_context_create() и поток_гет_контенты()

$context = stream_context_create();
$file = fopen($url, 'rb', FALSE, $context);
while(!feof($file))
{
    //usleep(1000000);
    echo stream_get_contents($file, 2014);
}

Вы также можете попробовать увеличить длину чтения файла и включить функцию usleep() для замедления выполнения. В любом случае потоковые функции, похоже, рекомендуются по сравнению с fread для последней версии PHP. Возможно, вам также захочется добавить @ перед fread() или stream_get_contents(), чтобы подавить любые ошибки, по крайней мере, в рабочей среде. Без этого и небольшой неудачи, и у вас есть поврежденный файл.

 2
Author: mr.freshwater, 2013-02-03 08:34:11

Это может быть буферизация (или, возможно, даже ограничение скорости) где-то в PHP или Apache. Попробуйте изменить:

while(!feof($file)) {
   echo fread($file, 2014);
}

Кому:

while(!feof($file)) {
   $s=fread($file, 2014);
   if($s===false)break;  //Crude
   echo $s;
   @ob_flush();@flush();
}

(Префикс @ используется потому, что они могут жаловаться на пустые буферы.)

Как сказал мистер фрешуотер, у вас должна быть проверка ошибок при вашем звонке fread, поэтому я добавил кое-что основное выше.

 0
Author: Darren Cook, 2013-02-03 08:51:39

Причина - 2014 год. ОС получает 4096-байтовую часть данных очень быстро, чем другие. Но если вы пишете 2014, то ОС пытается прочитать данные из файла на один байт, чтобы вычислить их. Вот почему это занимает так много времени. Изменить 2014 на 4096

 0
Author: Elshad Agayev, 2017-07-20 12:59:20