Завантаження файлів в php, direqtor

Багато ресурси використовують файлові сховища. Крім можливостей завантаження і зберігання файлів, буває необхідно організувати їх скачування. Одна справа коли файли лежать у відкритому доступі, а й тоді може знадобитися передача файлу через PHP. Наприклад, адміністратору ресурсу може бути потрібна інформація про кількість завантажень. Для файлів великого обсягу досі потрібна можливість докачки, що мабуть і є найважчим моментом для серверних скриптів. Подивимося як можна організувати роботу скрипта на PHP, який дозволяє реалізувати всі вищевказані можливості.

Почнемо з простого способу. Нехай наш скрипт отримує ім'я файлу через будь-якої з параметрів запиту. Це може бути реально набраний URL, а може бути і переписаний сервером за допомогою mod_rewrite. Скрипт викликає функцію file_download () з параметром $ filename. Крім прямої передачі в запиті $ filename може також обчислюватися на основі вихідного ідентифікатора із запиту або доповнюватися шляхом в дереві папок сервера.

Найлегший спосіб обробки запитів до викачуваним файлів - це просте перенаправлення на них.

function file_download # 40; $ filename # 41; # 123;
// Перевіряємо наявність файлу
if # 40; file_exists # 40; $ filename # 41; # 41; # 123;
// Тут пишемо код, який буде обробляти кожне завантаження файлу.

// перенаправляє клієнта на файл.
header # 40; 'Location:'. $ filename # 41; ;
# 125; else # 123;
// Якщо файл не знайдений, повідомляємо клієнту про це через заголовки HTTP
header # 40; $ _SERVER # 91; "SERVER_PROTOCOL" # 93 ;. '404 Not Found' # 41; ;
header # 40; 'Status: 404 Not Found' # 41; ;
# 125;
// Перериваємо подальше виконання скрипта, щоб не відправляти сміття у відповіді клієнту
exit;
# 125;

Для цього буде потрібно ускладнити нашу функцію закачування.

function file_download # 40; $ Filename. $ Mimetype = 'application / octet-stream' # 41; # 123;
if # 40; file_exists # 40; $ filename # 41; # 41; # 123;
// Відправляємо необхідні заголовки
header # 40; $ _SERVER # 91; "SERVER_PROTOCOL" # 93 ;. '200 OK' # 41; ;
// Тип вмісту. Може бути взятий з заголовків отриманих від клієнта
// при закачуванні файлу на сервер. Може бути отриманий за допомогою розширення PHP Fileinfo.
header # 40; 'Content-Type:'. $ mimetype # 41; ;
// Дата останньої модифікації файлу
header # 40; 'Last-Modified:'. gmdate # 40; 'R'. filemtime # 40; $ filename # 41; # 41; # 41; ;
// Відправляємо унікальний ідентифікатор документа,
// значення якого змінюється при його зміні.
// У наведеному нижче коді обчислення цього заголовка проводиться так само,
// як і в програмному забезпеченні сервера Apache
header # 40; 'ETag:'. sprintf # 40; '% X-% x-% x'. fileinode # 40; $ filename # 41 ;. filesize # 40; $ filename # 41 ;. filemtime # 40; $ filename # 41; # 41; # 41; ;
// Розмір файла
header # 40; 'Content-Length:'. # 40; filesize # 40; $ filename # 41; # 41; # 41; ;
header # 40; 'Connection: close' # 41; ;
// Файл, як він буде збережений в браузері або в програмі закачування.
// Без цього заголовка буде використовуватися базове ім'я скрипта PHP.
// Але цей заголовок не потрібен, якщо ви використовуєте mod_rewrite для
// перенаправлення запитів до сервера на PHP-скрипт
header # 40; 'Content-Disposition: attachment; filename = " '. basename # 40; $ filename # 41 ;. ' ";' # 41; ;
// Віддаємо вміст файлу
echo file_get_contents # 40; $ filename # 41; ;
# 125; else # 123;
header # 40; $ _SERVER # 91; "SERVER_PROTOCOL" # 93 ;. '404 Not Found' # 41; ;
header # 40; 'Status: 404 Not Found' # 41; ;
# 125;
exit;
# 125;

function file_download # 40; $ Filename. $ Mimetype = 'application / octet-stream' # 41; # 123;
if # 40; file_exists # 40; $ filename # 41; # 41; # 123;
header # 40; $ _SERVER # 91; "SERVER_PROTOCOL" # 93 ;. '200 OK' # 41; ;
header # 40; 'Content-Type:'. $ mimetype # 41; ;
header # 40; 'Last-Modified:'. gmdate # 40; 'R'. filemtime # 40; $ filename # 41; # 41; # 41; ;
header # 40; 'ETag:'. sprintf # 40; '% X-% x-% x'. fileinode # 40; $ filename # 41 ;. filesize # 40; $ filename # 41 ;. filemtime # 40; $ filename # 41; # 41; # 41; ;
header # 40; 'Content-Length:'. # 40; filesize # 40; $ filename # 41; # 41; # 41; ;
header # 40; 'Connection: close' # 41; ;
header # 40; 'Content-Disposition: attachment; filename = " '. basename # 40; $ filename # 41 ;. ' ";' # 41; ;
// Відкриваємо шуканий файл
$ F = fopen # 40; $ Filename. 'R' # 41; ;
while # 40 ;. feof # 40; $ f # 41; # 41; # 123;
// Читаємо кілобайтний блок, віддаємо його в висновок і скидаємо в буфер
echo fread # 40; $ F. 1024 # 41; ;
flush # 40; # 41; ;
# 125;
// Закриваємо файл
fclose # 40; $ f # 41; ;
# 125; else # 123;
header # 40; $ _SERVER # 91; "SERVER_PROTOCOL" # 93 ;. '404 Not Found' # 41; ;
header # 40; 'Status: 404 Not Found' # 41; ;
# 125;
exit;
# 125;

Я поки в роздумах з цього приводу. Може таймаут виконання скрипта PHP побільше виставити.
У себе поки такої баг не слова. хоча намагався.

Таймаут скрипта? ммм. треба тоді прив'язати таймаут до IP. еее. але файли-то від 1 Mb до 200. та й швидкість у всіх різна. Хтось на виділенка, а хтось на Dial-up. Не уявляю як розрахувати в цих умовах тайм-аути.
Я так розумію, що це не баг, а нормальна робота скрипта. При перенаправлення header'ом скрипт припиняє свою роботу (начебто логічно), природно викликаючи при цьому shutdown функцію, яка видаляє мітку для потоку, який насправді існує. = (
Адмін сервака впирається і не хоче рубати особливо настирних користувачів ні на рівні апача, ні до нього (скажімо, iptables). Загалом доводиться якось робити це програмно. Всі вже зробив. і htaccess хитрий написав, з редирект і перевірками куки, і перенаправлення на скрипт з потоками. Єдине, в чому затикаючи - передчасно видаляються мітки потоків. = (

Неуважний я. ) Не відразу зрозумів, що перенаправлення закриває з'єднання. Тоді їм не вийде скористатися в такій ситуації. При перенаправлення файли доступні безпосередньо і обмежити число потоків можна тільки через Апач. У httpd.conf або в файлах .htaccess є такий параметр. А засобами PHP тільки віддаючи файл через скрипт. Тоді є гарантія, що скрипт виконується поки йде закачування.

Ось ще що.
Може спробуєш заголовок Connection: Keep-alive
У мене поки немає часу тестувати, до файл-сервера свого тільки у вихідні доберуся, але може тут собака зарита. Треба ще в RFC поритися.

Фічі будуть такі: обмеження швидкості закачування для анонімів, віддача файлу в декілька потоків з можливістю докачки і часткового скачування, обмеження числа таких потоків.

Там купа тонких моментів: контроль активності сполуки, обробка та підтримка часткових GET-запитів.
За результатами буду писати замітки. Загалом, через тижнів зо два-три.

=)) Теж вирішив писати програмну віддачу. Але по швиденькому, на коліні. )) Треба якось людям доступ щось до файлів повернути.

>> В httpd.conf або в файлах .htaccess є такий параметр.
Дик то ж бо й воно, що в htaccess немає. Є тільки в Апачі і tcp / ip, але адмін недаеццо.
Пропонує міняти vds на Дедик. Не збагну він хитрий або ледачий))

Доброго вам дня!
Велике Спасибі за Ваші корисні статті!
Допоможіть розібратися з наступною проблемою.

Я за допомогою форми передаю параметри на іншу сторінку download.php
В якій прописана остання функція з даної статті і після неї запускаю
file_download ($ filename);

Підкажіть будь ласка, чому у мене замість закачування файлу, відкривається його код в браузері.

Перевірте, які заголовки отримує при цьому ваш браузер. Щоб файл Завантажити повинні бути передані заголовки, зазначені у функції. Якщо вони не передаються - копайте в сторону сервера

Схожі статті