Мой файл (размер 126 МБ, .exe) дает мне проблемы.
Я использую стандартный метод загрузки laravel.
Я пытался увеличить объем памяти, но он все еще либо говорит, что у меня закончилась нехватка памяти, либо я загружаю файл размера 0 КБ.
В документации ничего не говорится о больших размерах файлов.
Мой код
ini_set("memory_limit","-1"); // Trying to see if this works return Response::download($full_path);
Все, что я делаю неправильно?
— Редактировать —
Продолжая комментарий Филла Спаркса, это то, что у меня есть, и оно работает . Это комбинация Phill's плюс некоторые из php.net. Не уверен, что там что-то отсутствует?
public static function big_download($path, $name = null, array $headers = array()) { if (is_null($name)) $name = basename($path); // Prepare the headers $headers = array_merge(array( 'Content-Description' => 'File Transfer', 'Content-Type' => File::mime(File::extension($path)), 'Content-Transfer-Encoding' => 'binary', 'Expires' => 0, 'Cache-Control' => 'must-revalidate, post-check=0, pre-check=0', 'Pragma' => 'public', 'Content-Length' => File::size($path), ), $headers); $response = new Response('', 200, $headers); $response->header('Content-Disposition', $response->disposition($name)); // If there's a session we should save it now if (Config::get('session.driver') !== '') { Session::save(); } // Below is from http://uk1.php.net/manual/en/function.fpassthru.php comments session_write_close(); ob_end_clean(); $response->send_headers(); if ($file = fopen($path, 'rb')) { while(!feof($file) and (connection_status()==0)) { print(fread($file, 1024*8)); flush(); } fclose($file); } // Finish off, like Laravel would Event::fire('laravel.done', array($response)); $response->foundation->finish(); exit; }
Это происходит потому, что Response::download()
загружает файл в память перед его службой пользователю. По общему признанию, это недостаток в структуре, но большинство людей не пытаются обслуживать большие файлы через фреймворк.
Решение 1. Поместите файлы, которые вы хотите загрузить в общей папке, в статическом домене или cdn – полностью обходите Laravel.
Понятно, что вы, возможно, пытаетесь ограничить доступ к вашим загрузкам по логину, и в этом случае вам нужно будет создать собственный метод загрузки, что-то вроде этого должно работать …
function sendFile($path, $name = null, array $headers = array()) { if (is_null($name)) $name = basename($path); // Prepare the headers $headers = array_merge(array( 'Content-Description' => 'File Transfer', 'Content-Type' => File::mime(File::extension($path)), 'Content-Transfer-Encoding' => 'binary', 'Expires' => 0, 'Cache-Control' => 'must-revalidate, post-check=0, pre-check=0', 'Pragma' => 'public', 'Content-Length' => File::size($path), ), $headers); $response = new Response('', 200, $headers); $response->header('Content-Disposition', $response->disposition($name)); // If there's a session we should save it now if (Config::get('session.driver') !== '') { Session::save(); } // Send the headers and the file ob_end_clean(); $response->send_headers(); if ($fp = fread($path, 'rb')) { while(!feof($fp) and (connection_status()==0)) { print(fread($fp, 8192)); flush(); } } // Finish off, like Laravel would Event::fire('laravel.done', array($response)); $response->foundation->finish(); exit; }
Эта функция представляет собой комбинацию Response :: download () и процесса останова Laravel. У меня не было возможности проверить его сам, у меня нет Laravel 3, установленного на работе. Пожалуйста, дайте мне знать, если это сработает для вас.
PS: Единственное, что этот сценарий не заботится, это файлы cookie. К сожалению, функция Response :: cookie () защищена. Если это становится проблемой, вы можете снять код с функции и поместить ее в свой метод sendFile.
PPS: может возникнуть проблема с буферизацией вывода; если это проблема, посмотрите в руководстве PHP на примерах readfile () , есть метод, который должен там работать.
PPPS: поскольку вы работаете с двоичными файлами, вы можете рассмотреть возможность замены readfile()
на fpassthru ()
EDIT: игнорировать PPS и PPPS, я обновил код, чтобы использовать fread + print, поскольку это кажется более стабильным.
Я использую пользовательский метод readfile_chunked()
как указано в php.net здесь . Для Laravel 3 я расширил метод ответа следующим образом:
Добавьте этот файл в качестве applications/libraries/response.php
<?php class Response extends Laravel\Response { //http://www.php.net/manual/en/function.readfile.php#54295 public static function readfile_chunked($filename,$retbytes=true) { $chunksize = 1*(1024*1024); // how many bytes per chunk $buffer = ''; $cnt =0; // $handle = fopen($filename, 'rb'); $handle = fopen($filename, 'rb'); if ($handle === false) { return false; } while (!feof($handle)) { $buffer = fread($handle, $chunksize); echo $buffer; ob_flush(); flush(); if ($retbytes) { $cnt += strlen($buffer); } } $status = fclose($handle); if ($retbytes && $status) { return $cnt; // return num. bytes delivered like readfile() does. } return $status; } }
Затем закомментируйте эту строку в application / config / application.php:
'Response' => 'Laravel\\Response',
Пример кода:
//return Response::download(Config::get('myconfig.files_folder').$file->upload, $file->title); header('Content-Description: File Transfer'); header('Content-Type: application/octet-stream'); header('Content-Disposition: attachment; filename='.$file->title); header('Content-Transfer-Encoding: binary'); header('Expires: 0'); header('Cache-Control: must-revalidate'); header('Pragma: public'); header('Content-Length: ' . File::size(Config::get('myconfig.files_folder').$file->upload)); ob_clean(); flush(); Response::readfile_chunked(Config::get('myconfig.files_folder').$file->upload); exit;
До сих пор отлично работает.
Вы можете использовать Symfony \ Component \ HttpFoundation \ StreamedResponse следующим образом:
$response = new StreamedResponse( function() use ($filePath, $fileName) { // Open output stream if ($file = fopen($filePath, 'rb')) { while(!feof($file) and (connection_status()==0)) { print(fread($file, 1024*8)); flush(); } fclose($file); } }, 200, [ 'Content-Type' => 'application/octet-stream', 'Content-Disposition' => 'attachment; filename="' . $fileName . '"', ]); return $response;
для получения дополнительной информации проверьте это
Вам нужно увеличить свой memory_limit так:
Вам нужно увеличить memory_limit с помощью функции ini_set, например ini_set('memory_limit','128M');
Это будет работать для вас, я надеюсь!
Я нашел ответ здесь: https://stackoverflow.com/a/12443644/1379394