PHP Stop Удаленный файл Загрузить, если он превышает 5 МБ

Как остановить удаленный файл от загрузки файла, если он превышает 5 МБ? Если я остановлю его при передаче, будет ли файл храниться где-нибудь в другом временном каталоге или в памяти? Как я узнаю? Вот мой текущий код:

$url = 'http://img.ruphp.com/php/heic0601a.jpg'; $file = '../temp/test.jpg'; file_put_contents($file, file_get_contents($url)); 

Есть несколько способов, которыми вы могли бы это сделать, но поскольку в настоящее время вы используете file_get_contents() , вот что я сделал бы:

  • Откройте удаленный файл, используя fopen()
  • Прочитайте файл и сохраните его с помощью fread() – это позволит вам отслеживать текущий размер и бросать и ошибочно при прохождении порога.

Что-то вроде этого:

 $url = 'http://img.ruphp.com/php/heic0601a.jpg'; $file = '../temp/test.jpg'; $limit = 5 * 1024 * 1024; // 5MB if (!$rfp = fopen($url, 'r')) { // error, could not open remote file } if (!$lfp = fopen($file, 'w')) { // error, could not open local file } // Check the content-length for exceeding the limit foreach ($http_response_header as $header) { if (preg_match('/^\s*content-length\s*:\s*(\d+)\s*$/', $header, $matches)) { if ($matches[1] > $limit) { // error, file too large } } } $downloaded = 0; while (!feof($rfp) && $downloaded < $limit) { $chunk = fread($rfp, 8192); fwrite($lfp, $chunk); $downloaded += strlen($chunk); } if ($downloaded > $limit) { // error, file too large unlink($file); // delete local data } else { // success } 

NB: возникает соблазн проверить заголовок Content-Length: прежде чем вы получите какой-либо файл, чтобы проверить, слишком ли большой файл – вы все равно можете сделать это, если хотите, но не доверяете этому значению! Заголовок является, по существу, произвольным значением, и, хотя было бы нарушением протокола использовать длину содержимого, которая не соответствует размеру файла, его можно использовать для обмана системы при загрузке файла, который нарушает правила. Вам нужно будет подсчитать байты, даже если вы проверите это значение.

Вы также можете сделать это с помощью curl с помощью обратного вызова данных, но я рассматривал бы это как менее удовлетворительное решение, главным образом из-за того, что curl требует имя строковой функции, а не стандартный общий callable тип, что означает, что вам нужно будет либо использовать глобальную переменную или static переменную, чтобы отслеживать загруженную длину контента, ни одна из которых не является приемлемой (IMHO) для этого.

Что касается выбора URL-адреса и ограничения размера, это не слишком сложно … но file_get_contents этого не сделает. Вы можете fopen URL-адрес и использовать stream_get_meta_data в потоке, чтобы получить массив информации о потоке. Если я правильно читаю пример (и если кодировка передачи не «разделяется»), вы найдете там заголовок Content-Length в котором будет указан размер файла. Если значение установлено и превышает ваш лимит, залог.

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

Вот вариант решения DaveRandom в тех же строках, но без записи файла, пока он не будет полностью загружен.

 <?php define('MAXMB', 5); define('BYTESPERMB', 1048576); $maxsize = MAXMB * BYTESPERMB; $handle = fopen("http://www.example.com/", "rb"); $contents = ''; $completed = true; while (!feof($handle)) { $chunk = fread($handle, 8192); $size += strlen($chunk); if ($size > $maxsize) { $completed = false; break; } $contents .= $chunk; } fclose($handle); if ($completed) { // File appears to be completely downloaded so write it -- file_put_contents('path/to/localfile', $contents); } else { // It was too big } 

Это невозможно с помощью file_get_contents – вам нужно будет использовать расширение PHP cURL для захвата размера файла.

 <?php $max_length = 5 * 1024 * 1024; $url = 'http://img.ruphp.com/php/heic0601a.jpg'; $ch = curl_init($url); curl_setopt($ch, CURLOPT_NOBODY, true); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_HEADER, true); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); $data = curl_exec($ch); curl_close($ch); if ($data === false) { echo 'cURL failed'; exit; } $contentLength = 'unknown'; if (preg_match('/Content-Length: (\d+)/', $data, $matches)) { $contentLength = (int)$matches[1]; } echo "Content-Length: $contentLength\n"; if ($contentLength > $max_length) { echo "File is too large\n"; } else { echo "File size is ok\n"; } 

Оберните это в функцию и используйте ее для проверки URL-адреса – что-либо слишком большое может быть пропущено.

Даунсайд:

Этот метод работает, только если заголовок Content-Length возвращается сервером – не все серверы хорошо себя ведут, а не все вернут правильную длину.

Потенциал роста:

Нет необходимости загружать и записывать до байтов $max_length . Этот метод будет быстрее и менее ресурсоемким.

Изменено:

http://php.net/filesize#92462