Недостаточно памяти с Fread

Я использую Backblaze B2 для хранения файлов и использую их код документации для загрузки через их API. Однако их код использует fread для чтения файла, что вызывает проблемы для файлов размером более 100 МБ, так как он пытается загрузить весь файл в память. Есть ли лучший способ для этого, который не пытается загрузить весь файл в оперативную память?

$file_name = "file.txt";
$my_file = "<path-to-file>" . $file_name;
$handle = fopen($my_file, 'r');
$read_file = fread($handle,filesize($my_file));

$upload_url = ""; // Provided by b2_get_upload_url
$upload_auth_token = ""; // Provided by b2_get_upload_url
$bucket_id = "";  // The ID of the bucket
$content_type = "text/plain";
$sha1_of_file_data = sha1_file($my_file);

$session = curl_init($upload_url);

// Add read file as post field
curl_setopt($session, CURLOPT_POSTFIELDS, $read_file);

// Add headers
$headers = array();
$headers[] = "Authorization: " . $upload_auth_token;
$headers[] = "X-Bz-File-Name: " . $file_name;
$headers[] = "Content-Type: " . $content_type;
$headers[] = "X-Bz-Content-Sha1: " . $sha1_of_file_data;
curl_setopt($session, CURLOPT_HTTPHEADER, $headers);

curl_setopt($session, CURLOPT_POST, true); // HTTP POST
curl_setopt($session, CURLOPT_RETURNTRANSFER, true);  // Receive server response
$server_output = curl_exec($session); // Let's do this!
curl_close ($session); // Clean up
echo ($server_output); // Tell me about the rabbits, George!

Я пытался с помощью:

curl_setopt($session, CURLOPT_POSTFIELDS, array('file' => '@'.realpath('file.txt')));

Однако я получаю сообщение об ошибке: Ошибка чтения загруженных данных: SocketTimeoutException (Тайм-аут чтения)

Редактировать: потоковое имя файла с CURL также, похоже, не работает.

1

Решение

Проблема, с которой вы столкнулись, связана с этим.

fread($handle,filesize($my_file));

С размером файла вы можете просто сделать file_get_contents, намного лучше память, чтобы прочитать 1 строку за раз с fget

$handle = fopen($myfile, 'r');

while(!feof($handle)){
$line = fgets($handle);
}

Таким образом, вы читаете только одну строку в память, но если вам нужно полное содержимое файла, вы все равно попадете в узкое место.

Единственный реальный способ — загрузить видео.

Я сделал быстрый поиск, и кажется, что по умолчанию для CURL является потоковая передача файла, если вы даете ему имя файла

 $post_data['file'] = 'myfile.csv';

curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);

Вы можете увидеть предыдущий ответ для более подробной информации

Можно ли использовать cURL для потоковой передачи файла с помощью POST?

Так что, пока вы можете пройти sha1_file Похоже, вы можете просто передать файл, что должно избежать проблем с памятью. Там могут быть проблемы с ограничением по времени, хотя. Также я не могу придумать, как получить хеш, если это не удастся.

Просто к вашему сведению, лично я никогда не пробовал это, обычно я просто использую sFTP для передачи больших файлов. Так что я не знаю, должно ли это быть специально post_data['file'] Я просто скопировал это из другого ответа.

Удачи…

ОБНОВИТЬ

Видя, что потоковая передача, похоже, не удалась (см. Комментарии).

Вы можете проверить потоковую передачу, чтобы убедиться, что она работает. Я не знаю, что все это может включать в себя, может быть, поток файла на ваш собственный сервер? Также я не уверен, почему это не сработает «как рекламируется», и вы, возможно, уже проверили это. Но никогда не повредит что-то проверить, никогда не думайте, что что-то работает, пока вы точно не знаете. Очень легко попробовать что-то новое в качестве решения, только пропустить настройку или указать неверный путь, а затем вернуться к мысли, что все основано на исходной проблеме.

Я провел много времени, разбивая вещи на части, только чтобы понять, что у меня была орфографическая ошибка. Я довольно хорошо разбираюсь в программировании, так что обычно я тоже задумываюсь над ошибками. Суть в том, что перед тем, как идти дальше, убедитесь, что это не простая ошибка.

Предполагая, что все настроено правильно, я бы попробовал file_get_contents, Я не знаю, будет ли это лучше, но это больше предназначено для открытия целых файлов. Это также может показаться более читабельным в коде, потому что тогда ясно, что нужен весь файл. Это просто кажется более семантически правильным, если не сказать ничего другого.

Вы также можете увеличить объем оперативной памяти, к которой PHP имеет доступ, используя

ini_set('memory_limit', '512M')

Вы даже можете пойти выше, в зависимости от вашего сервера. Наивысшее, что я получил раньше 3G, но сервер, который я использую, имеет 54GB и это было единовременно (мы перенесли 130 миллионов строк из MySql в MongoDB, индекс innodb съел более 30 ГБ). Обычно я бегу с 512M и есть несколько сценариев, которые обычно нужны 1G, Но я бы просто не вспомнил «Память». Обычно это последнее средство для меня после оптимизации и тестирования. Мы выполняем много тяжелой обработки, поэтому у нас такой большой сервер, у нас также есть 2 подчиненных сервера (среди прочего), которые работают по 16 ГБ каждый.

Что касается размера, как правило, я увеличиваю его на 128M скажи, что это работает, затем добавь 128M просто чтобы быть уверенным, но вы можете пойти по более мелким шагам. Обычно люди всегда используют кратные 8, но я не знаю, имеет ли это большое значение в наши дни.

Снова, удачи.

2

Другие решения

Других решений пока нет …