Как заставить загружать большие файлы, не используя слишком много памяти?

Я пытаюсь обслуживать большие файлы zip для пользователей. При наличии двух одновременных подключений на сервере заканчивается память (ОЗУ). Я увеличил объем памяти с 300 МБ до 4 ГБ (Dreamhost VPS), а затем он работал нормально.

Мне нужно разрешить намного больше двух одновременных подключений. Фактический 4 ГБ позволит что-то вроде 20 одновременных подключений (слишком плохо).

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

Следующий код – тот, который я использую в CodeIgniter (PHP framework):

ini_set('memory_limit', '300M'); // it was the maximum amount of memory from my server set_time_limit(0); // to avoid the connection being terminated by the server when serving bad connection downloads force_download("download.zip", file_get_contents("../downloads/big_file_80M.zip"));exit; 

Функция force_download следующая (вспомогательная функция по умолчанию Codeingiter):

 function force_download($filename = '', $data = '') { if ($filename == '' OR $data == '') { return FALSE; } // Try to determine if the filename includes a file extension. // We need it in order to set the MIME type if (FALSE === strpos($filename, '.')) { return FALSE; } // Grab the file extension $x = explode('.', $filename); $extension = end($x); // Load the mime types @include(APPPATH.'config/mimes'.EXT); // Set a default mime if we can't find it if ( ! isset($mimes[$extension])) { $mime = 'application/octet-stream'; } else { $mime = (is_array($mimes[$extension])) ? $mimes[$extension][0] : $mimes[$extension]; } // Generate the server headers if (strpos($_SERVER['HTTP_USER_AGENT'], "MSIE") !== FALSE) { header('Content-Type: "'.$mime.'"'); header('Content-Disposition: attachment; filename="'.$filename.'"'); header('Expires: 0'); header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); header("Content-Transfer-Encoding: binary"); header('Pragma: public'); header("Content-Length: ".strlen($data)); } else { header('Content-Type: "'.$mime.'"'); header('Content-Disposition: attachment; filename="'.$filename.'"'); header("Content-Transfer-Encoding: binary"); header('Expires: 0'); header('Pragma: no-cache'); header("Content-Length: ".strlen($data)); } exit($data); } 

Я пробовал некоторые кодовые коды, которые я нашел в Google, но файл всегда был доставлен поврежденным. Наверное, из-за плохого кода.

Может ли кто-нибудь мне помочь?

Solutions Collecting From Web of "Как заставить загружать большие файлы, не используя слишком много памяти?"

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

Вы отправляете содержимое ($ data) этого файла через PHP?

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

Ваше единственное решение – не отправлять содержимое файла / данные через PHP и просто перенаправлять пользователя на URL-адрес загрузки в файловой системе.

Используйте сгенерированную и уникальную символическую ссылку или скрытое местоположение.

Вы не можете использовать $ data со всеми файлами в нем. Попробуйте перейти к этой функции, а не только к содержимому файла. Затем отправьте все заголовки один раз и после этого прочитайте часть этого файла, используя fread (), эхо, что кусок, вызов flush () и повтор. Если какой-либо другой заголовок будет отправлен тем временем, тогда, наконец, передача будет повреждена.

Symlink – большой файл для вашего корня документа (если он не является авторизованным только файлом), а затем пусть Apache обрабатывает его. (Таким образом, вы также можете принимать диапазоны байтов)

Добавьте свой ini_set до SESSION_START();