загружается намного медленнее, чем при чтении файла
Я отправляю загрузки с 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;
}
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(), чтобы подавить любые ошибки, по крайней мере, в рабочей среде. Без этого и небольшой неудачи, и у вас есть поврежденный файл.
Это может быть буферизация (или, возможно, даже ограничение скорости) где-то в 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
, поэтому я добавил кое-что основное выше.
Причина - 2014 год. ОС получает 4096-байтовую часть данных очень быстро, чем другие. Но если вы пишете 2014, то ОС пытается прочитать данные из файла на один байт, чтобы вычислить их. Вот почему это занимает так много времени. Изменить 2014 на 4096