HackWare.ru

Как загрузить файл из URL и сохранить на сервере (как избежать нехватку оперативной памяти при загрузки больших файлов)

В PHP можно несколькими вариантами загрузить файл по ссылке (URL) и сохранить на сервере. Некоторые из них имеют важные отличия, которые могут стать ключевыми при выборе способа скачать и сохранить файл в PHP.

1. file_get_contents и file_put_contents

Первый весьма очевидный вариант — использовать file_get_contents и file_put_contents:

file_put_contents("Tmpfile.zip", file_get_contents("http://someurl/file.zip"));

Реальный пример:

file_put_contents("mial.jpg", file_get_contents("https://suay.ru/wp-content/uploads/2024/03/20231213_151132.jpg"));

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

2. fopen и file_put_contents для немедленной записи данных на диск по мере их поступления

Если для вас важно, чтобы оперативная память не была переполнена при загрузке большого файла, то используйте комбинацию fopen и file_put_contents:

file_put_contents("Tmpfile.zip", fopen("http://someurl/file.zip", 'r'));

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

Реальный пример:

file_put_contents("mial2.jpg", fopen("https://suay.ru/wp-content/uploads/2024/03/20231213_151132.jpg", 'r'));

Но у этого способа есть и недостаток — в настройках PHP значение allow_fopen_url может быть установлено на Off. В данном случае указанная конструкция не будет работать из-за запрета открытия файлов с помощью fopen если файл указан как URL.

3. Пользовательская функция для загрузки файлов с помощью PHP

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

function downloadFile($url, $path)
{
	$newfname = $path;
	$file = fopen ($url, 'rb');
	if ($file) {
		$newf = fopen ($newfname, 'wb');
		if ($newf) {
			while(!feof($file)) {
				fwrite($newf, fread($file, 1024 * 8), 1024 * 8);
			}
		}
	}
	if ($file) {
		fclose($file);
	}
	if ($newf) {
		fclose($newf);
	}
}

Реальный рабочий пример кода:

<?php

function downloadFile($url, $path)
{
	$newfname = $path;
	$file = fopen ($url, 'rb');
	if ($file) {
		$newf = fopen ($newfname, 'wb');
		if ($newf) {
			while(!feof($file)) {
				fwrite($newf, fread($file, 1024 * 8), 1024 * 8);
			}
		}
	}
	if ($file) {
		fclose($file);
	}
	if ($newf) {
		fclose($newf);
	}
}

downloadFile ('https://suay.ru/wp-content/uploads/2024/03/20231213_151132.jpg', 'mial3.jpg');

4. Использование библиотеки curl для загрузки файла в PHP

Библиотека curl поддерживает множество протоколов, также вы можете настроить пользовательский User Agent, вы можете использовать аутентификацию и кукиз.

Смотрите также: PHP cURL как установить значение User Agent ИЛИ как сделать так, чтобы сервера не блокировали запросы cURL

Пример скачивания файла с помощью PHP библиотеки curl:

function downloadUrlToFile($url, $outFileName) {
	if(is_file($url)) {
	copy($url, $outFileName); 
	} 
	else {
	$options = array(
		CURLOPT_FILE    => fopen($outFileName, 'w'),
		CURLOPT_TIMEOUT =>  28800, // set this to 8 hours so we dont timeout on big files
		CURLOPT_URL     => $url
	);

	$ch = curl_init();
	curl_setopt_array($ch, $options);
	curl_exec($ch);
	$httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
	curl_close($ch);
	return $httpcode;
	}
}

Реальный рабочий пример кода:

function downloadUrlToFile($url, $outFileName) {
	if(is_file($url)) {
	copy($url, $outFileName); 
	} 
	else {
	$options = array(
		CURLOPT_FILE    => fopen($outFileName, 'w'),
		CURLOPT_TIMEOUT =>  28800, // set this to 8 hours so we dont timeout on big files
		CURLOPT_URL     => $url
	);

	$ch = curl_init();
	curl_setopt_array($ch, $options);
	curl_exec($ch);
	$httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
	curl_close($ch);
	return $httpcode;
	}
}

downloadUrlToFile ('https://suay.ru/wp-content/uploads/2024/03/20231213_151132.jpg', 'mial4.jpg');

5. Загрузка файлов в PHP с использованием wget

exec ('wget http://someurl/file.zip');

Реальный рабочий пример кода:

exec ('wget https://suay.ru/wp-content/uploads/2024/03/20231213_151132.jpg');

Вам необходимо убедиться, что утилита wget установлена на сервере и доступна для запуска из PHP скрипта.

При использовании данного варианта файл сохраняется на диск по мере загрузки и не переполняет оперативную память.

Во время работы скрипта выводится информация wget, в том числе прогресс загрузки файла.

Необязательно указывать имя файла — по умолчанию будет использоваться исходное имя. При желании, вы можете явно указать имя файла с помощью опции «-O»:

exec ('wget -O mial5.jpg https://suay.ru/wp-content/uploads/2024/03/20231213_151132.jpg');

6. Загрузка файлов в PHP с использованием утилиты cURL

Вы можете использовать утилиту Linux cURL — по аналогии, как мы использовали утилиту wget в предыдущем примере.

Возможности PHP библиотеки curl и Linux утилиты cURL весьма схожи. Но этот метод следует выделить в отдельную группу, поскольку многим намного удобнее синтаксис командной строки cURL чем замысловатый синтаксис PHP библиотеки curl.

К примеру, вместо всех замысловатых конструкций рассмотренных выше для PHP библиотеки curl аналогичного результата можно добиться с помощью следующей строки кода:

exec ('curl -o Tmpfile.zip http://someurl/file.zip');

Вы по-прежнему можете использовать различные протоколы, аутентификацию, POST запросы, изменение реферера и User Agent, кукиз и все прочие многочисленные возможности cURL. Но при этом вам не нужно заново осваивать синтаксис PHP библиотеки curl — вы можете использовать привычный синтаксис командной строки.

Реальный рабочий пример кода:

exec ('curl -o mial6.jpg https://suay.ru/wp-content/uploads/2024/03/20231213_151132.jpg');

Обратите внимание, опция «-o» с указанием имени файла является обязательной для бинарных файлов (да и для текстовых тоже, поскольку без указания этой опции содержимое файла будет выведено в стандартный вывод без сохранения на диске).

История обновлений

No update history yet.

Рекомендуется:
↑