Мне нужно доставлять клиентам большие файлы, такие как file.zip
(~ 2 ГБ), с уникальным URL для каждого клиента. Затем я перенаправлю (с .htaccess
) ссылку на скачивание клиента example.com/download/f6zDaq/file.zip
на что-то вроде
example.com/download.php?id=f6zDaq&file=file.zip
Но так как файлы большие, я не хочу, чтобы факт, что PHP обрабатывает загрузку (вместо того, чтобы просто Apache обрабатывал это), был проблемой производительности ЦП / ОЗУ для моего сервера. В конце концов, запрос PHP делает это с использованием нового слоя, поэтому он может вызвать такую проблему, если не будет выполнен должным образом.
Вопрос: какие из следующих решений являются наилучшими? (в частности, с точки зрения ЦП / ОЗУ)?
1: решение PHP с
application/download
header('Content-Type: application/download'); header('Content-Disposition: attachment; filename=file.zip'); readfile("/path/to/file.zip");
Загрузка ЦП, измеренная при загрузке: 13,6%.
1bis: решение PHP с
application/octet-stream
(из примера № 1 этой страницы а> )header('Content-Description: File Transfer'); header('Content-Type: application/octet-stream'); header('Content-Disposition: attachment; filename=file.zip'); header('Expires: 0'); header('Cache-Control: must-revalidate'); header('Pragma: public'); header('Content-Length: ' . filesize('file.zip')); readfile("/path/to/file.zip");
1ter: решение PHP с
application/octet-stream
(из здесь):header('Content-Description: File Transfer'); header('Content-Type: application/octet-stream'); header('Content-Disposition: attachment; filename=file.zip'); header('Content-Transfer-Encoding: binary'); // additional line header('Connection: Keep-Alive'); header('Expires: 0'); header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); // additional line header('Pragma: public'); header('Content-Length: ' . filesize('file.zip')); readfile("/path/to/file.zip");
1-й квартал: еще один вариант PHP с
application/force-download
(отредактировано; поступает из здесь):header("Content-Disposition: attachment; filename=file.zip"); header("Content-Type: application/force-download"); header("Content-Length: " . filesize($file)); header("Connection: close");
2: решение Apache, без участия PHP: пусть Apache обслуживает файл и использует
.htaccess
для предоставления разных URL для одного и того же файла (можно написать множество способов сделать это). С точки зрения производительности это похоже на то, чтобы клиент мог загрузитьexample.com/file.zip
, обслуживаемый сервером Apache.3: другое решение PHP. Это, вероятно, будет работать:
$myfile = file_get_contents("file.zip"); echo $myfile;
но разве это не попросит PHP загрузить весь контент в память? (что было бы плохо с точки зрения производительности!)
4: Просто выполните перенаправление
header("Location: /abcd/file.zip");
, как описано в Файл с коротким URL-адресом, загруженный с оригинальным именем файла.Проблема с этим решением: это раскрывает фактическое местоположение файла
example.com/abcd/file.zip
конечному пользователю (который может затем использовать или поделиться этим URL без аутентификации), который не нужен ...
Но с другой стороны, он намного легче для процессора, так как PHP просто перенаправляет запрос и не доставляет сам файл.
Загрузка ЦП, измеренная при загрузке: 10,6%.
Примечание. файл чтения сообщает:
readfile () сам по себе не создает проблем с памятью, даже при отправке больших файлов. Если вы столкнулись с ошибкой нехватки памяти, убедитесь, что выходная буферизация отключена с помощью ob_get_level ().
но я хотел быть на 100% уверенным, что он не будет медленнее / потреблять больше ресурсов ЦП и ОЗУ, чем чистое решение Apache.
5 ответов
Как упомянуто в Самый быстрый способ обслуживания файла с помощью PHP < Я наконец сделал это:
apt-get install libapache2-mod-xsendfile
a2enmod xsendfile # (should be already done by previous line)
Затем я добавил это в apache2.conf
:
<Directory />
AllowOverride All
Require all granted
XSendFile on
XSendFilePath /home/www/example.com/files/
</Directory>
Затем я сделал service apache2 restart
и включил это в .htaccess
:
RewriteRule ^(.*)$ download.php?file=$1 [L,QSA]
И это в download.php
:
header("X-Sendfile: /home/www/example.com/files/hiddenfolder_w33vbr0upk80/" . $file);
header("Content-type: application/octet-stream");
header('Content-Disposition: attachment; filename="' . $file . '"');
NB: странно, даже у меня AllowOverride All
включен в apache2.conf
VirtualHost, делая это:
XSendFile on
XSendFilePath /home/www/example.com/files/
Просто в файле /home/www/example.com/.htaccess
или /home/www/example.com/files/.htaccess
не работал (он не работает с xsendFilePath not allowed here
).
Ориентир :
- 10,6% CPU при загрузке, точно так же, как если бы я выполнял прямую загрузку файла с помощью Apache (и вообще без PHP), так что все хорошо!
Вы можете использовать X-Accel-Redirect
когда ваш веб-сервер Nginx. Для Apache это mod_xsendfile с заголовком X-Sendfile
.
<?php
header('X-Accel-Redirect: /download/f6zDaq/file.zip');
Это дешевле, а также имеет лучшую производительность, потому что веб-сервер обрабатывает файл.
Я бы пошел с readfile
. Я использовал его годами, и у меня никогда не было проблем с памятью, даже при работе на 128 МБ VPS.
Использование PHP означает, что вы можете легко обрабатывать аутентификацию, авторизацию, регистрацию, добавление и удаление пользователей, URL с истекающим сроком действия и так далее. Вы можете использовать .htaccess
для этого, но для этого вам придется написать довольно большую структуру.
Самые большие проблемы, с которыми вы столкнетесь с файлами этих размеров, следующие:
- люди скачивают его с помощью менеджера загрузок
- прерванные соединения
Как правило, поддержание активности может быть плохой идеей, поскольку оно выделяет соединение для загрузки, которое может блокировать ваши сетевые подключения, а не просто освобождать их. Однако, если вы ожидаете, что все ваши файлы будут большими, это ваш друг, потому что вы не хотите, чтобы люди перезапускали эти загрузки. И эти загрузки обеспечат надежные соединения с поддержкой активности, и клиенту будет проще возобновить их, что поможет уменьшить количество людей, пытающихся повторно загружать массивные файлы.
Таким образом, из ваших представленных вариантов, я рекомендую
1ter
Однако, как и другие здесь, я все же рекомендую вам протестировать ваши решения, и желательно из места, отличного от того, с которого вы обслуживаете файлы.
Приложение: здесь сказано, что работа с PHP - не лучшая идея, если вам не нужны функции управления заголовками и контроль .htaccess, потому что это просто добавляет больше вычислительной мощности. Безусловно, лучшим способом было бы просто иметь файлы в доступном каталоге. .htaccess может переписать доступ к файлам и папкам, а не только к PHP-скриптам.
Чтобы создать защищенные папки загрузки на основе Apache:
Options +FollowSymLinks
RewriteEngine On
RewriteRule ^/user/files/folder1.*$ http://example.com/userfiles/ [R=301,L]
Затем, если вам нужно защитить его паролем, вместо использования PHP, используйте Apache (который уже установлен в большинстве установок PHP). Это можно сделать, включив файл .htaccess в целевую папку (если вы динамически создаете пользователей, вам может потребоваться создать сценарий для их создания для каждого нового пользователя) и убедитесь, что apache подготовлен для обработки паролей:
AuthType Basic
AuthName "Authentication Required"
AuthUserFile "/user/password/.htpasswd"
Require valid-user
(Подробнее см. Здесь: Настройка паролей Apache).
После этого убедитесь, что в каталоге паролей есть файл .htpasswd в формате username: password / hashedpassword.
Например.:
andreas:$apr1$dHjB0/..$mkTTbqwpK/0h/rz4ZeN8M0
john:$apr1$IHaD0/..$N9ne/Bqnh8.MyOtvKU56j1
Теперь, если вы не хотите, чтобы они передавали пароль каждый раз, в ссылке для скачивания включите доступ
<a href="user:pass@http://example.com/userfiles/myCoolZip.zip">Link (hopefully behind a password-protected interface.)</a>
[Примечание: НЕ используйте метод прямой ссылки на пароль, если пароли не назначаются случайным образом для каждого файла.]
ИЛИ, если вы заполняете данные на основе управления паролями корневого Apache И ваш сайт использует apache для процесса входа в систему, они могут не нуждаться в пользователе: вообще пропустить часть ссылки, уже выполнив вход в Apache.
ВНИМАНИЕ :
Теперь, при этом, файлы будут доступны людям, которым предоставлена полная ссылка (с именем пользователя / паролем). Таким образом, они будут такими же безопасными (или такими же небезопасными), как протоколы https (или http, если вы позволите) вашего сервера, а также ваши пользователи, которые делятся или не делятся ссылками.
Делая это таким образом, файлы будут открыты для пользователей, для которых они предназначены, с полными возможностями веб-доступа, доступными для них, то есть помощниками по загрузке, подключаемыми модулями браузера, вызовами REST и т. Д., В зависимости от вариантов использования вашего пользователя. Это может снизить безопасность, которая может иметь или не иметь большого значения в зависимости от того, что вы размещаете. Если вы размещаете личные медицинские данные (мало пользователей, высокий уровень безопасности, низкие требования к скорости), я бы не стал так поступать. Если вы размещаете музыкальные альбомы, я бы сделал это полностью (много пользователей, низкий уровень безопасности, высокие требования к скорости).
Вы можете использовать .htaccess
для перенаправления запроса в файл, сохраняя структуру постоянной ссылки:
RewriteEngine On
RewriteBase /
RewriteRule ^download\/([^\/]+)\/file.zip download.php?id=$1 [L,NC]
Затем в своем download.php
вы можете проверить, является ли предоставленный идентификатор действительным:
// Path to file
$file = 'file.zip';
// If the ID is valid
if ($condition) {
header("Content-Disposition: attachment; filename=\"" . basename($file) . "\"");
header("Content-Type: application/force-download");
header("Content-Length: " . filesize($file));
header("Connection: close");
} else {
// Handle invalid ids
header('Location: /');
}
Когда пользователь посещает действительный URL http://example.com/download/f6zDaq/file.zip
, загрузка начнется и соединение будет закрыто.
Если пользователь посещает недействительный URL, он будет перенаправлен на домашнюю страницу.
Новые вопросы
php
PHP - это широко используемый высокоуровневый, динамический, объектно-ориентированный и интерпретируемый язык сценариев, в первую очередь предназначенный для серверной веб-разработки. Используется для вопросов о языке PHP.