PHP прокси для загрузки файлов

#php #proxy #download-manager #source-code-protection

#php #прокси #менеджер загрузок #защита исходного кода

Вопрос:

Я думаю, что это очень просто.

У меня есть простой веб-сайт с зарезервированной областью и некоторыми файлами для загрузки с него.

Я отключил прямую загрузку файлов с помощью .htaccess, и я управляю загрузкой файла с помощью этого простого proxy.php файл:

 // ....

if ($filename === null || !file_exists($proxiedDirectory.$filename)) {
    http_response_code(404);
    exit;
}

if (!$site->is_logged_in()) { 
    http_response_code(403);
    exit;
}

$fp = fopen($proxiedDirectory.$filename, 'rb');

header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="'.$filename.'"');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($filename));
fpassthru($fp);
exit;
  

Этот код РАБОТАЕТ отлично, но, к сожалению, у меня есть файл объемом 1,2 Гб, который пользователи могли бы загрузить, а этот скрипт работает слишком медленно и не позволяет загрузить файл полностью.

Буду признателен за любую помощь,

Заранее спасибо!

M.

Ответ №1:

Вы можете использовать комбинацию header() , set_time_limit() , fgets() ob_flush() , flush() filesize() . Вот мой пример, лучше всего использовать 64-битный Php на 64-битной ОС, потому что в этой архитектуре нет ограничений.

     // Set force download headers
    header('Content-Description: File Transfer');
    header('Content-Type: application/octet-stream');
    header('Content-Disposition: attachment; filename="' . $file . '"');
    header('Content-Transfer-Encoding: binary');
    header('Connection: Keep-Alive');
    header('Expires: 0');
    header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
    header('Pragma: public');
    header('Content-Length: ' . sprintf("%u", filesize($downloads_folder . $file)));
    // Open and output file contents
    set_time_limit(0);
    $fh = fopen($downloads_folder . $file, "rb");
    while (!feof($fh)) {
      echo fgets($fh);
      ob_flush();
      flush();
    }
    fclose($fh);
    exit;
  

Надеюсь, это поможет.

Ответ №2:

Используйте фрагментированную загрузку, что-то вроде этого:

 $chunkSize = 1024 * 1024;
while (!feof($fp))
{
    $buffer = fread($fp, $chunkSize);
    echo $buffer;
    ob_flush();
    flush();
}
  

Ответ №3:

использование nginx в качестве прокси может быть более подходящим. Причина проста: когда вы загружаете с помощью php, при запросе в php-fpm будет время ожидания, поэтому файл, скорее всего, не сможет быть загружен полностью.

 location /proxy.lua {
    proxy_pass http://proxy.com/link/;
} 
  

если вам нужно проверить, есть у пользователя логин или нет, вы можете использовать lua nginx (OpenResty)

тем не менее, есть простой способ проверить это: 1. proxy.php перенаправьте запрос на nginx location proxy.lua с двумя параметрами: ts и code.

 ts is timestamp of server
code is md5sum(ts "complexstring")
  
 header("Location: /proxy.lua?ts=122amp;code=xxxamp;filename=xxxx", 302);
exit(0);
  

когда в lua:

 parse the parameter ts and code, validate the code and ts value
proxy the file
  

Комментарии:

1. Спасибо, Райан, ваш ответ правильный, но, к сожалению, у меня общий хост apache : (

2. вы можете перенаправить запрос на какой-нибудь хост, которым является nginx или openresty. Когда прокси для большого файла или клиентской сети работает недостаточно быстро, обязательно произойдет тайм-аут.

Ответ №4:

Используйте ob_end_clean() перед fpassthru($fp)

например

 ob_end_clean();
fpassthru($fp);
  

Это может сработать для больших файлов