Відправка файлів php. Віддаємо файли ефективно за допомогою PHP

Відправка файлів php. Віддаємо файли ефективно за допомогою PHP

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

Для цього нам знадобиться html форма з полем введення типу . Крім того, для передачі файлів на сервер необхідно формі встановити тип multipart. Для цього в якості параметра enctype вказується значення multipart / form-data.

Після того, як на html сторінці ми розмістимо форму з полем у вікні браузера відобразиться поле з можливістю вибрати файл на локальному комп'ютері.

Після того, як користувач вибере потрібний файл і натисне кнопку «Завантажити» форма передасть дані php скрипту на сервер, який вказаний в actionформи. Якщо action форми порожній, то дані будуть передані той же файл, на якому знаходиться форма. Вся інформація про завантаження поміщається в масив $ _FILES. Нам лише залишається витягти цю інформацію і перемістити файл у потрібний нам місце.

Перш, ніж приступити до написання скрипта обробки multipart-форми, Потрібно відредагувати файл конфігурації php.ini , Щоб дозволити завантаження файлів на сервер.

Конфігураційний файл PHP php.ini має три параметри, пов'язані з завантаженням файлів на сервер:

  • file_uploads \u003d On - дозволяє завантаження файлів на сервер по протоколу HTTP;
  • upoad_tmp_dir \u003d / tmp - встановлює каталог для тимчасового зберігання завантажених файлів;
  • upload_max_filesize \u003d 2M - встановлює максимальний обсяг завантаження.

Отже, створіть новий файл з ім'ям upload.php і скопіюйте в нього наступний код.

Якщо уважно подивитися на форму, то Ви побачите приховане поле

Воно вказує на максимальний розмір прийнятого файлу в байтах. Але не слід довіряти цьому значення, так як воно є лише повідомляти і його легко можна обійти! Так що майте це на увазі!

Після того як користувач вибрав файл і натиснув на кнопку «Завантажити», вся інформація про фото, як згадувалося раніше, поміщається в масив $ _FILES, а сам файл поміщається в тимчасовий каталог на сервері, який вказаний в в php.ini.

Так як поле file називалося name \u003d "uploadFile", То масив $ _FILES буде містити асоціативний масив з ключем "UploadFile" .

  • $ _FILES [ "uploadFile"] [ "name"] - ім'я файлу до його відправки на сервер, наприклад, pict.gif;
  • $ _FILES [ "uploadFile"] [ "size"] - розмір прийнятого файлу в байтах;
  • $ _FILES [ "uploadFile"] [ "type"] - MIME-тип прийнятого файлу (якщо браузер зміг його визначити), наприклад: image / gif, image / png, image / jpeg, text / html;
  • $ _FILES [ "uploadFile"] [ "tmp_name"] - містить ім'я файлу в тимчасовому каталозі, наприклад: / tmp / phpV3b3qY;
  • $ _FILES [ "uploadFile"] [ "error"] - Код помилки, яка може виникнути при завантаженні файлу.

Після завершення роботи скрипта, тимчасовий файл буде видалений. Це означає, що ми повинні його скопіювати в інше місце до завершення роботи скрипта.

Отже, з алгоритмом розібралися! Тепер давайте поглянемо на код.

Насамперед ми перевіряємо чи була натиснута кнопка submit.

If (isset ($ _ POST [ "upload"])) ()

If (is_uploaded_file ($ _ FILES [ "uploadFile"] [ "tmp_name"])) (Виконуємо дію над файлом) else (echo "Немає запису завантажений";)

Якщо файл був завантажений через HTTP POST, то далі ми його переміщаємо з тимчасового каталогу в потрібний нам каталог. Це робиться за допомогою функції move_uploaded_file, яка приймає два параметри: ім'я файлу для завантаження і шлях куди буде переміщений файл. У разі успішного переміщення файлу, дана функція поверне true, в іншому випадку -false.

If (move_uploaded_file ($ _ FILES [ "uploadFile"] [ "tmp_name"], $ uploadedFile)) (echo Файл завантажений;) else (echo Під час завантаження файлу сталася помилка;)

У нашому випадку в якості імені файлу виступає ім'я тимчасового файлу на сервері - $ _FILES [ "uploadFile"] [ "tmp_name"], а в якості каталогу, куди буде переміщений файл - змінна $ uploadedFile, яка була оголошена вище в скрипті і містить нове місце зберігання файлу.

$ Folder \u003d "path / to / folder /"; $ UploadedFile \u003d $ folder. basename ($ _ FILES [ "uploadFile"] [ "name"]);

Зі свого досвіду можу сказати, що зберігати оригінальну назву файлу на сервері не варто, тому його можна перейменувати. Для цього сгенерируем випадкова назва для нашого файлу і функція move_uploaded_file () перемістить і перейменує наш файл:

// Отримуємо розширення файлу $ file_ext \u003d strtolower (strrchr ($ _ FILES [ "uploadFile"] [ "name"], ".")); // Генеруємо випадкове число $ file_name \u003d uniqid (rand (10000,99999)); // Формуємо шлях на сервері $ uploadedFile \u003d $ folder. $ File_name. $ File_ext;

Ну і наостанок наведу список можливих помилок, які виникають під час завантаження файлів на сервер. Нагадую, що код помилки зберігається в змінній $ _FILES [ "uploadFile"] [ "error"]:

  • 0- Помилок не виникало, файл був успішно завантажений на сервер.
  • 1 Розмір прийнятого файлу перевищив максимально допустимий розмір, який заданий директивою upload_max_filesize конфігураційного файлу php.ini ..
  • 2 Розмір завантаження перевищив значення MAX_FILE_SIZE, Вказане в HTML-формі.
  • 3 Завантажуваний файл був отриманий тільки частково.
  • 4 Немає запису був завантажений.
  • 6 Ні тимчасову папку.
  • 7- Збій при записуванні файлів на диск.

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

За допомогою нашого Скрітпи зловмисник зможе завантажувати довільні файли на сервер, наприклад, він зможе закачати на сервер php-скрипт, який рекурсивно зможе видалити всі ваші файли на сервері або PHP-shell, так що якщо ви пишете свій завантажувач файлів, то до цього справі треба підійти серйозно, нічого не загубивши.

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

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

Вихідні файли поточної статті ви можете завантажити за.

Почнемо зі створення форми, в якій буде присутній поле для завантаження файлу. На що тут варто звернути увагу? По-перше, поле для відправки файлу повинна мати спеціальний тип - type \u003d "file". По-друге, файл може бути відправлений тільки в тілі запиту, тому метод GET для відправки форми не підійде, потрібно використовувати тільки метод POST - method \u003d "post». Ну і, по-третє, для форми необхідний спеціальний атрибут enctype з певним значенням - enctype \u003d »multipart / form-data». Без цього атрибута файл просто не буде відправлений.

Виходячи з озвученого вище, наш код буде приблизно таким:

< form class = "form-horizontal" method = "post" enctype = "multipart/form-data" action = "file.php" >

< div class = "form-group" >

< label for = "name" class = "col-sm-2 control-label" > Названіефайла< / label >

< div class = "col-sm-8" >

< input type = "text" id = "name" class = "form-control" name = "name" placeholder = "Назва файлу" >

< / div >

< / div >

< div class = "form-group" >

< label for = "file" class = "col-sm-2 control-label" > файл< / label >

< div class = "col-sm-8" >

< input type = "file" name = "file" id = "file" >

< / div >

< / div >

< div class = "form-group" >

< div class = "col-sm-offset-2 col-sm-8" >

< button type = "submit" id = "submit" class = "btn btn-primary" > Надіслати< / button >

< div > < / div >

< / div >

< / div >

< / form >

В результаті ми отримаємо приблизно таку форму:

Поле для завантаження файлів виглядає не дуже привабливо, але, тим не менш, зі своїм завданням впорається без проблем: файл можна прикріпити і відправити на сервер. У наступній статті ми спробуємо красиво оформити поле для завантаження файлу, а поки давайте перевіримо, чи завантажується файл. Як бачимо, форма буде відправлена \u200b\u200bв файл file.php, який вказаний в атрибуті action. Давайте створимо цей файл.

Останнє оновлення: 1.11.2015

Щоб завантажити файл на сервер, нам треба використовувати форму з параметром enctype \u003d "multipart / form-data" і масив $ _FILES. Отже, створимо файл upload.php наступного змісту:

завантаження файлу

Виберіть файл:

Тут визначена форм з атрибутом enctype \u003d "multipart / form-data". Форма містить спеціальне поле для вибору файлу.

Всі файли файли потрапляють в асоціативний масив $ _FILES. Щоб визначити, а чи є взагалі завантажені файли, можна використовувати конструкцію if: if ($ _FILES)

Масив $ _FILES є двовимірним. Ми можемо завантажити набір файлів, і кожен завантажений файл можна отримати по ключу, який збігається зі значенням атрибута name.

Так як елемент для завантаження файлу на формі має name \u003d "filename", то даний файл ми можемо отримати за допомогою виразу $ _FILES [ "filename"].

У кожного об'єкта файлу є свої параметри, які ми можемо отримати:

    $ _FILES [ "file"] [ "name"]: ім'я файлу

    $ _FILES [ "file"] [ "type"]: тип вмісту файлу, наприклад, image / jpeg

    $ _FILES [ "file"] [ "size"]: розмір файлу в байтах

    $ _FILES [ "file"] [ "tmp_name"]: ім'я тимчасового файлу, збереженого на сервері

    $ _FILES [ "file"] [ "error"]: код помилки при завантаженні

Також ми можемо перевірити наявність помилок при завантаженні. Якщо у нас немає помилки, то поле $ _FILES [ "filename"] [ "error"] містить значення UPLOAD_ERR_OK.

При відправці файлу на сервер він спочатку завантажується у тимчасове місце, з якого потім за допомогою функції move_uploaded_file () він переміщається в каталог сервера.

Функція move_uploaded_file () приймає два параметри шлях до завантаженого тимчасового файлу і шлях, куди треба помістити долучення.

Обмеження і чи потрібно завантажувати

За замовчуванням розмір файлів обмежений 2 мб. Однак можна налаштувати даний показник в файлі конфігурації. Змінимо цей показник, наприклад, до 10 мб. Для цього знайдемо в файлі php.ini наступний рядок:

Upload_max_filesize \u003d 2M

Змінимо її на

Upload_max_filesize \u003d 10M

Також ми можемо налаштувати папку для тимчасових файлів, що завантажуються. Для цього в файлі php.ini знайдемо такий рядок:

; Upload_tmp_dir \u003d

Змінимо її на

Upload_tmp_dir \u003d "C: / php / upload"

Також в каталозі php нам треба створити папку upload.

мультизагрузка

змінимо скрипт upload.php так, щоб він підтримував множинну завантаження:

$ Error) (if ($ error \u003d\u003d UPLOAD_ERR_OK) ($ tmp_name \u003d $ _FILES [ "uploads"] [ "tmp_name"] [$ key]; $ name \u003d $ _FILES [ "uploads"] [ "name"] [$ key]; move_uploaded_file ($ tmp_name, "$ name");)))?\u003e

завантаження файлу




Кожне поле вибору файлу має атрибут name \u003d "uploads", тому сервер буде розглядати набір відправлених файлів як єдиний масив.

Потім використовуючи цикл foreach, проходимо по всі файлів і зберігаємо їх в каталог веб-сайту.

У Вас в браузері заблокований JavaScript. Дозвольте JavaScript для роботи сайту!

Завантаження файлів на сервер

Короткий ексурсія в upload

Що таке Upload files, або чому не працює
copy ( "c: \\ images \\ sample.jpg", "http://mysite.ru/uploads/sample.jpg")

Навіть якщо у Вас в розпорядженні всього один комп'ютер, на якому суміщений і сервер і робоча станція, не варто забувати про те, що php використовує технологію клієнт / сервер. Файл, який ми хочемо завантажити, як правило, знаходиться на машині клієнта, тобто користувача, звичайного відвідувача сайту. Місце призначення - сервер. Для того щоб зробити процес передачі файлу, нам знадобитися наступна форма:

Send this file:

При цьому в полі action повинен бути вказаний URL Вашого php-скрипта, який в подальшому буде займатися обробкою завантаження. Приховане поле MAX_FILE_SIZE має передувати полю вибору файлу, і містити максимально допустимий розмір файлу в байтах. Його призначення - перевірка розміру файлу ще до моменту відправки файлу на сервер. Це має позбавити користувача від тривалої і безрезультатної завантаження файлу на сервер і освіти зайвого трафіку, але не варто особливо покладатися на це обмеження, так як його легко обійти.

Що відбувається, коли користувач вибрав файл на своєму диску, і натиснув на кнопку "Send file"? Браузер відсилає файл на сервер, де php-інтерпретатор поміщає його в свою тимчасову директорію, привласнюючи йому випадкове ім'я і виконує скрипт, вказаний в полі action.

Як повинен виглядати upload.php?

$ Uploaddir \u003d "/ var / www / uploads /"; if (move_uploaded_file ($ _ FILES [ "userfile"] [ "tmp_name"], $ uploaddir. $ _FILES [ "userfile"] [ "name"])) (print "File is valid, and was successfully uploaded.";) else (print "There some errors!";)

При написанні скрипта, виникає природне запитання: як отримати інформацію про завантаженому файлі і достукатися до самого файлу. Якщо Ви використовуєте PHP версії 4.1.0 і старше, найкраще буде звернутися до глобального масиву $ _FILES. Для кожного завантаженого файлу він містить хеш-масив, реєструючи такі дані:

  • $ _FILES [ "userfile"] [ "name"] - оригінальне ім'я файлу, таке, яким його бачив користувач, вибираючи файл;
  • $ _FILES [ "userfile"] [ "type"] - mime / type файлу, наприклад, може бути image / gif; це поле корисно зберегти, якщо Ви хочете надавати інтерфейс для скачування завантажених файлів;
  • $ _FILES [ "userfile"] [ "size"] - розмір завантаженого файлу;
  • $ _FILES [ "userfile"] [ "tmp_name"] - повний шлях до тимчасового файлу на диску;
  • $ _FILES [ "userfile"] [ "error"] - Починаючи з версії 4.2.0, містить код помилки, який дорівнює 0, якщо операція пройшла успішно.

Для PHP версії нижче 4.1.0 цей масив називається $ HTTP_POST_FILES. Не варто забувати, що на відміну від $ _FILES цей масив не є суперглобального і при зверненні до нього, наприклад, з функції, необхідно явно вказувати global $ HTTP_POST_FILES;

Якщо в налаштуваннях Вашого сервера register_globals \u003d on, будуть створені додаткові змінні виду $ userfile_name, $ userfile_type, $ userfile_size ... З огляду на, що, починаючи з версії 4.2.0, в настройках за умовчанням register_globals \u003d off використання цих змінних не рекомендовано, навіть якщо вони визначені. Кращий спосіб отримання інформації про завантажуються файли - використовувати масив $ _FILES.

Для роботи з завантаженими файлами найкраще використовувати вбудовані функції is_uploaded_file () і move_uploaded_file (), які перевіряють, чи був завантажений файл, і поміщають його в зазначену папку відповідно. Більш детальну інформацію Ви можете знайти на сторінках керівництва. Не варто винаходити велосипед і працювати самому з тимчасовими файлами, копіювати їх, видаляти. Це вже зроблено до Вас і для Вас.

Налаштування сервера

Я все зробив правильно, але у мене щось не працює. Може, у мене неправильно налаштований сервер?

Якщо Ви "все зробили правильно", але Ваш код неработает, або працює неправильно, не поспішайте впадати у відчай. Можливо проблема не в Ваших руках, а в невірних налаштуваннях сервера. Ось список директив, які мають відношення до завантаження файлів:

У файлі php.ini:

  • Якщо Ви хочете дізнатися, де розташований Ваш php.ini, виконайте
  • file_uploads - можливість заборонити або дозволити завантаження файлів в цілому. За замовчуванням On.
  • upload_max_filesize - максимальний розмір файлу, який може бути завантажений. Якщо Вам необхідно працювати з великими файлами, змініть цю настройку. За замовчуванням 2М. Не забудьте змінити post_max_size.
  • post_max_size - загальне обмеження зверху на розмір даних, переданих в POST запиті. Якщо Вам необхідно працювати з великими файлами, або передавати кілька файлів одночасно, змініть цю настройку. Значення за замовчуванням 8М.
  • upload_tmp_dir - тимчасова директорія на сервері, в яку будуть міститися всі компоненти для завантаження. Перевірте, які на неї виставлені права (якщо на даному етапі у Вас виникли складнощі, дивіться пояснення в кінці статті). Така директорія повинна існувати і у користувача, під яким виконується Apache, також повинні бути права на запис в цю директорію. Якщо Ви працюєте з включеним обмеженням open_basedir - то тимчасовий каталог повинен знаходитися всередині. Вам не потрібно турбуватися про її чищенню або про унікальність імен, PHP вирішує цю проблему за Вас.

У файлі httpd.conf:

  • Перш за все, переконайтеся, що Ви використовуєте веб-сервер Apache 1.3 (остання версія на момент написання статті - 1.3.27). Якщо Ви використовуєте Apache 2.0, Вам слід прочитати наступний уривок з документації:

    Do not use Apache 2.0 and PHP in a production environment neither on Unix nor on Windows.

  • Якщо Ви отримали повідомлення "POST Method Not Allowed", це означає, що треба шукати щось схоже на наступні директиви, і використовувати ключове слово Allow: Order allow, deny Allow from all
  • Проблеми із завантаженням бінарних файлів - класичне запитання "чому б'ються файли при upload". Ось спосіб рішення, запропонований Дімою Бородіно (http://php.spb.ru): У директорії, де лежить скрипт, робимо файл .htaccess, в якому пишемо: CharsetDisable On У файл httpd.conf дописати рядки: CharsetRecodeMultipartForms Off

Невеликі пояснення, до цього рецепту: вищеописана проблема, коли завантажені на сервер в архівах не збереглися розпаковуються і картинки не відображаються, може виникати через те, що використовується веб-сервер Russian Apache. Директива CharsetDisable відключає модуль charset-processing module, тобто ніякої перекодування при скачуванні файлів, що знаходяться в цій папці, відбуватися не буде. Директива CharsetRecodeMultipartForms вимикає перекодування даних, переданих методом POST з заголовком Content-Type: multipart / form-data. Тобто двійкові дані, передані з такою налаштуванням, будуть залишені в первісному вигляді, а все інше наповнення сайту буде перетворено відповідно до поточних налаштувань сервера.

Але при цьому можуть виникнути ускладнення: будьте готові до того, що в деяких випадках текстові частини запитів вам доведеться перекодувати самостійно. Ось що з цього приводу говориться в документації:

Використовуйте директиву CharsetRecodeMultipartForms, яка з'явилася в PL23, але при цьому вам все-одно доведеться перекодувати вручну текстові частини запитів. Для цього можна використовувати Russian Apache API, доступне в інших модулях або Russian Apache Perl API, доступне з mod_perl.

Один із прикладів визначення кодування ви можете знайти тут: http://tony2001.phpclub.net/detect_charset/detect.phps

Найсвіжіша документація по Russian Apache знаходиться на його офіційному сайті: http://apache.lexa.ru/.

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

Також можлива настройка параметрів Apach з помощью.htaccess:

Php_value upload_max_filesize 50M php_value post_max_size 50M

Додаткові можливості

Завантаження декількох файлів одночасно

Приклад форми завантаження декількох файлів:

Send these files:


І не забудьте збільшити post_max_size, Якщо передбачається багато файлів

Автоматичне завантаження файлів на сервер

Не варто забувати, що файли на диску користувача - конфіденційна інформація, до якої ні JavaScript, ні вже тим більше PHP не мають ні найменшого відношення. До тих пір, поки користувач сам не вибрав файл за допомогою ні про яку роботу з ним не може йти й мови. І не забувайте, що у даного поля введення атрибут value призначений лише для читання.

Зберігання файлів в базі даних mySQL

Якщо Ви зібралися зберігати загружаеми файли в базі даних, Вам необхідно пам'ятати наступні моменти:

  • Необхідно використовувати поле типу BLOB
  • Перед тим, як класти в базу, не забути застосувати до рядка mysql_escape_string ()
  • При відображенні файлу необхідно вказувати заголовок content / type

Пам'ятайте, що скрипт відображає ваш HTML ніяк не пов'язаний зі скриптом, який повинен виводити зображення. Це повинні бути два різні додатки.

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

Отримання властивостей зображення.

Якщо перед вами постало завдання перевірити тип або розміри картинки перед завантаженням файлу на сервер, вам буде потрібно функція getimagesize (). Як аргумент вона приймає ім'я файлу на диску і повертає масив, перші два елементи якого - ширина і висота відповідно, третій - тип зображення. У разі неможливості прочитати з зазначеного файлу коректне зображення, функція повертає брехня.

Завантаження файлів, що мають російсько-мовне назву

При завантаженні на сервер файлів, необхідно перевіряти їхні оригінальні імена на предмет наявності "нестандартних" символів (наприклад російських букв). У разі їх присутності необхідно провести заміну. Оригінальна назва файлу можна знайти в змінній $ _FILES [ "userfile"] [ "name"]. Як перекодувати російськомовну рядок в трансліт можна можна знайти в прикладах PHP.

Відображення статусу завантаження (Progress bar)

Необхідно враховувати, що до повного завантаження файлу, PHP не може оперувати ні розміром файлу, ні відсотком його завантаження. Тільки коли файл вже знаходиться на сервері PHP, то він отримує можливість звертатися до інформації. Якщо вам все-таки вкрай необхідно реалізувати таку можливість, скористайтеся Java-аплетів.

Права на файли

Проблеми з правами на сервері (upload_tmp_dir)

В Unix-подібних операційних системах кожної папки, файлу, заслання виставлені відповідність права доступу. Вони можуть виглядати як rwx-rw-r- або ж як число 754.

Доступність файлу або каталогу залежать від ідентифікатора користувача і ідентифікатора групи, в яку він входить. Режим в цілому описується в термінах трьох послідовностей, по три букви в кожній:

Власник Група Інші (u) (g) (o) rwx rwx rwx

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

r Право на читання. (4)
w Право на запис. (2)
x Право на виконання (пошук в каталозі). (1)

  • Встановити власником каталогу користувача, з чиїми привелегиями виконується apache. Це можна дізнатися з файлу httpd.conf або переглянувши список процесів на сервері. Права на каталог повинні бути 700 (rwx ------).
  • Незалежно від того, хто є власником каталогу, встановити права 777 (rwxrwxrwx).

    Приклад реалізації завантаження картинок на сервер.

    $ Max_image_width \u003d 380; $ Max_image_height \u003d 600; $ Max_image_size \u003d 64 * 1024; $ Valid_types \u003d array ( "gif", "jpg", "png", "jpeg"); if (isset ($ _ FILES [ "userfile"])) (if (is_uploaded_file ($ _ FILES [ "userfile"] [ "tmp_name"])) ($ filename \u003d $ _FILES [ "userfile"] [ "tmp_name"]; $ ext \u003d substr ($ _ FILES [ "userfile"] [ "name"], 1 + strrpos ($ _ FILES [ "userfile"] [ "name"], ".")); if (filesize ($ filename)\u003e $ max_image_size ) (echo "Error: File size\u003e 64K.";) elseif (! in_array ($ ext, $ valid_types)) (echo "Error: Invalid file type.";) else ($ size \u003d GetImageSize ($ filename); if (($ size) && ($ size< $max_image_width) && ($size < $max_image_height)) { if (@move_uploaded_file($filename, "/www/htdocs/upload/")) { echo "File successful uploaded."; } else { echo "Error: moving fie failed."; } } else { echo "Error: invalid image properties."; } } } else { echo "Error: empty file."; } } else { echo "
    Send this file:
    "; }

    Оригінал статті знаходиться на сайті PHP Club


    Як завантажити файл з сервера?
  • Якщо Вам потрібно віддавати файли не безпосередньо веб сервером, а за допомогою PHP (наприклад для збору статистики завантажень), прошу під кат.

    1. Використовуємо readfile ()

    Метод гарний тим, що працює з коробки. Треба тільки написати свою функцію відправки файлу (трохи змінений приклад з офіційної документації):

    Function file_force_download ($ file) (if (file_exists ($ file)) (// скидаємо буфер виведення PHP, щоб уникнути переповнення пам'яті виділеної під скрипт // якщо цього не зробити файл буде читатися в пам'ять повністю! If (ob_get_level ()) ( ob_end_clean ();) // змушуємо браузер показати вікно збереження файлу header ( "Content-Description: File Transfer"); header ( "Content-Type: application / octet-stream"); \u200b\u200bheader ( "Content-Disposition: attachment; filename \u003d ". basename ($ file)); header (" Content-Transfer-Encoding: binary "); header (" Expires: 0 "); header (" Cache-Control: must-revalidate "); header (" Pragma: public "); header (" Content-Length: ". filesize ($ file)); // читаємо файл і відправляємо його користувачеві readfile ($ file); exit;))
    Таким способом можна відправляти навіть великі файли, так як PHP буде читати файл і відразу віддавати його користувачеві по частинах. У документації чітко сказано, що readfile () не повинен створювати проблеми з пам'яттю.

    особливості:

    • Файл читається в внутрішній буфер функції readfile (), розмір якого становить 8Кб (спасибі 2fast4rabbit)

    2. Читаємо і відправляємо файл вручну

    Метод використовує той же Drupal при відправці файлів з приватної файлової системи (файли недоступні безпосередньо по посиланнях):

    Function file_force_download ($ file) (if (file_exists ($ file)) (// скидаємо буфер виведення PHP, щоб уникнути переповнення пам'яті виділеної під скрипт // якщо цього не зробити файл буде читатися в пам'ять повністю! If (ob_get_level ()) ( ob_end_clean ();) // змушуємо браузер показати вікно збереження файлу header ( "Content-Description: File Transfer"); header ( "Content-Type: application / octet-stream"); \u200b\u200bheader ( "Content-Disposition: attachment; filename \u003d ". basename ($ file)); header (" Content-Transfer-Encoding: binary "); header (" Expires: 0 "); header (" Cache-Control: must-revalidate "); header (" Pragma: public "); header (" Content-Length: ". filesize ($ file)); // читаємо файл і відправляємо його користувачеві if ($ fd \u003d fopen ($ file," rb ")) (while (! feof ($ fd)) (print fread ($ fd, 1024);) fclose ($ fd);) exit;))
    особливості:

    • Скрипт чекає поки весь файл буде прочитаний і відданий користувачеві.
    • Дозволяє заощадити пам'ять сервера

    3. Використовуємо модуль веб сервера

    3a. Apache
    Модуль XSendFile дозволяє за допомогою спеціального заголовка передати відправку файлу самому Apache. Існують версії по Unix і Windows, під версії 2.0. *, 2.2. * І 2.4. *

    В налаштуваннях хоста потрібно включити перехоплення заголовка за допомогою директиви:
    XSendFile On
    Також можна вказати білий список директорій, файли в яких можуть бути оброблені. Важливо: якщо у Вас сервер на базі Windows шлях повинен включати букву диска у верхньому регістрі.

    Опис можливих опцій на сайті розробника: https://tn123.org/mod_xsendfile/

    Приклад відправки файлу:

    Function file_force_download ($ file) (if (file_exists ($ file)) (header ( "X-SendFile:". Realpath ($ file)); header ( "Content-Type: application / octet-stream"); \u200b\u200bheader ( " Content-Disposition: attachment; filename \u003d ". basename ($ file)); exit;))

    3b. Nginx
    Nginx вміє відправляти файли з коробки через спеціальний заголовок.

    Для коректної роботи потрібно заборонити доступ до папку безпосередньо через конфігураційний файл:
    location / protected / (internal; root / some / path;)
    Приклад відправки файлу (файл повинен знаходитися в директорії / some / path / protected):

    Function file_force_download ($ file) (if (file_exists ($ file)) (header ( "X-Accel-Redirect:". $ File); header ( "Content-Type: application / octet-stream"); \u200b\u200bheader ( "Content -Disposition: attachment; filename \u003d ". basename ($ file)); exit;))
    Більше інформації на сторінці офіційної документації

    особливості:

    • Скрипт завершується відразу після виконання всіх інструкцій
    • Фізично файл відправляється модулем самого веб сервера, а не PHP
    • Мінімальне споживання пам'яті та ресурсів сервера
    • Максимальна швидкодія

    Update: Хабраюзер ilyaplot дає слушну пораду, що краще слати НЕ application / octet-stream, а реальний mime type файлу. Наприклад, це дозволить браузеру підставити потрібні програми в діалог збереження файлу.

     

     

    Це цікаво: