Длина фрагмента PHP fread() не учитывается правильно

Я хочу отправить пользователю внешний файл MP4 кусками по 1 МБ каждый. С каждым фрагментом я обновляю запись в базе данных, чтобы отслеживать процесс загрузки. Я использую fread() для чтения файла по частям. Вот урезанный код:

$filehandle = fopen($file, 'r');

while(!feof($filehandle)){
  $buffer = fread($filehandle, 1024*1024);

  //do some database stuff

  echo $buffer;
  ob_flush();
  flush(); 
}

Однако, когда я проверяю размер фрагмента на некоторой итерации внутри цикла while, с помощью

$chunk_length = strlen($buffer);
die("$chunk_length");

Я никогда не получаю желаемый размер куска. Он колеблется где-то в районе 7000 - 8000 байт. Далеко не 1024*1024 байта. Когда я уменьшаю размер фрагмента до меньшего числа, например 1024 байта, он работает, как и ожидалось.


person Au.Merci    schedule 04.05.2014    source источник
comment
Вы открывали в бинарном режиме? Не уверен, что это было причиной, но кто знает.   -  person Jeroen    schedule 04.05.2014
comment
Да, пробовал открывать в бинарном режиме, но это не изменило поведения.   -  person Au.Merci    schedule 04.05.2014
comment
Раздел описания здесь описывает сценарии, в которых фактическая длина чтения не будет соответствовать запрошенной длине: php.net/manual/en/function.fread.php - я предполагаю, что происходит условие 4?   -  person Jeroen    schedule 04.05.2014
comment
Согласно 4-му условию: при чтении из чего-либо, кроме обычного локального файла, чтение будет остановлено после того, как пакет станет доступным. Итак, из этого я понимаю, что никогда невозможно прочитать более 1 пакета, если файл удален?   -  person Au.Merci    schedule 04.05.2014
comment
Зачем тебе это вообще? Не вижу смысла разделять загрузку.   -  person Jeroen    schedule 04.05.2014
comment
Чтобы отслеживать статус загрузки. Другими словами: сколько процентов загружено/было загружено. Иногда загрузка завершается с ошибкой или прерывается пользователями. Я хочу отслеживать это, сохраняя, сколько было загружено.   -  person Au.Merci    schedule 11.05.2014
comment
Но пользователь получит кучу файлов. Как они будут объединены в один?   -  person Jeroen    schedule 11.05.2014


Ответы (1)


Согласно руководству PHP fread():

«При чтении из чего-либо, кроме обычного локального файла, например из потоков, возвращаемых при чтении удаленных файлов, или из popen() и fsockopen(), чтение останавливается после того, как пакет становится доступным».

В этом случае я открыл удаленный файл. Видимо, это заставляет fread() останавливаться не на заданной длине, а при приходе первой посылки.

Я хотел отслеживать загрузку внешнего файла. Если вы делаете это (или отслеживаете загрузку), используйте вместо этого CURL:

curl_setopt($curl_handle, CURLOPT_NOPROGRESS, false);
curl_setopt($curl_handle, CURLOPT_PROGRESSFUNCTION, 'callbackFunction');

function callbackFunction($download_size, $downloaded, $upload_size, $uploaded){
  //do stuff with the parameters
}
person Au.Merci    schedule 06.01.2015