Как увеличить размер загружаемого файла dle

Обновлено: 18.05.2024

Однажды в очередной раз возникла задача о закачке относительно больших файлов. Говоря конкретно, клиент захотел заливать на сайт через админку видеоролики размером 20-40 мегабайт. Казалось бы, в наше просвещенное время подобный размер — это такая мелочь, о коей и говорить стыдно. Но внезапно все уперлось в настройки виртуального хостинга. Мы с ужасом обнаружили, что максимальный размер закачиваемого файла — 2M, и поменять эту цифру нет возможности. И менять хостинг по ряду причин нельзя — по крайней мере не сейчас.


Самая первая наша реакция — посмотреть возможности различных флеш-аплоадеров. Ведь не может быть, чтобы мировая техническая мысль не реализовала такой полезной вещи, как загрузка файла по частям. Перебираем последовательно Uploadify, SWFUpload, FancyUpload, jqUploader, jquery-transmit. Но все тщетно. Искомой фичи мы не видим. Вполне вероятно, что надо копать дальше, но время поджимает, и надо уже что-то делать…

Вышеописанное печально. Однако нам на руку играет тот факт, что это админка. Т.е. нам вовсе не нужно ориентироваться на кроссбраузерность. Достаточно того, что этот механизм будет работать на браузере клиента, каковым (о чудо!) является FF.

Тут же вспоминаем, что в FF последних версий есть возможность получить в строку содержимое файла, загруженного в поле file-upload. И в голову приходит желание разбивать эту строку на куски и закачивать частями, используя Ajax.

Клиентская часть

Сначала нарисуем необходимое в статическом HTML:

Теперь нам надо написать ту самую функцию big_file_upload:

Получение содержимого файла

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

  • file.get(0) — получение DOM-объекта из jQuery-объекта, переданного в функцию
  • files.item(0) — получение первого файла из списка. Здесь он у нас единственный, однако напомню, что уже есть возможность множественной закачки файлов из одного контрола.
  • getAsDataURL() — получение содержимого файла в формате Data:URL. Есть еще методы getAsText и getAsBinary, однако нам нужно передавать на сервер методом POST, поэтому желательно получить содержимое файла, закодированное в Base64.

Поскольку содержимое у нас в формате Data:URL, то неплохо было бы отрезать заголовочную часть, в которой находится информация о MIME-типе и способе кодирования. В более общем варианте нашей функции эту информацию надо бы использовать, но в данном примере она нам только будет мешаться при декодировании. Поэтому просто отрежем все по первую запятую (включительно), которой отделяется заголовок:

Отправка файла кусками

Здесь все банально:

Серверная часть

Теперь сделаем на сервере принимающий PHP-скрипт upload.php. В варианте для примера он также предельно прост:

Файл открывается с опцией «а», т.е. предлагается не перезаписывать существующий файл, а дополнять его. Таким способом мы из кусков соберем целый файл.

Думаю, всем понятно, что данный скрипт должен лежать в закрытой админской части сайта чтобы к нему не имели доступа разные личности со стороны. Кроме того, имя файла и сам файл должны проверяться на валидность. Иначе — это даже не уязвимость, а… я и слова-то такого не знаю…

Пробуем запустить

Попробовали? Получилось? Держу пари, что получилось совсем не то, что ожидалось. Файл вроде бы закачался. Вроде бы даже длина правильная. А вот содержимое — какая-то каша.

Почему так получилось? Ответ прост: POST-запросы отправляются в асинхронном режиме по нескольку кусков одновременно, поэтому никто не гарантирует, что на сервер они будут приходить именно в той последовательности, в которой были поданы команды на отправку. Мало того, что никто не гарантирует, а я прямо-таки утверждаю, что никогда они не придут в нужной последовательности. Всегда будет получаться каша.

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

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

Читайте также: