Комментарии 23
Было бы неплохо рассмотреть ещё сжатие данных (мы же zip'уем, а не tar'им) и защиту паролем.
Ну и объединение массивов стоило сделать через array_merge, а не сложением. (не заметил хаб Ненормальное программирование
)
На всякий случай не буду обещать что-нибудь, но в планах маленький цикл статей о zip, php и nginx, что с этим всем можно делать. И тут zip больше как контейнер (не рассматривал tar, потому что он не так широко распространен среди обычных пользователей, хотя когда-то, давным-давно, по мотивам одной статьи писал tar-упаковщик, тоже на php). Но если будут силы, я очень постараюсь не обойти тему сжатия стороной.
не заметил хаб Ненормальное программирование
То есть, теги вас не смутили?)
А что там рассматривать zip по сути просто контейнер. Сами данные можно сжимать разными алгоритмами, deflate (тот же gzip без дополнительных gzip заголовков) или bzip2, ну и более продвинутые lzma (но это уже не все смогут распаковать).
Значительно интересней то, что zip позволяет сохранять потоки. Т.е. не обязательно точно знать размер и CRC файла для заголовка. Например, когда делаешь бэкап БД (на пару гигов) то не нужно сначала это всё во временный файл писать, а потом уже в zip. Можно сразу писать в zip, на лету считая CRC и размеры, и эти данные сохранять после файла (там специальные опции для этого) плюс в центральном каталоге. Вот это уже ни одна из многочисленных доступных реализаций на PHP (по сути они только необходимый минимум умеют) не поддерживает.
Значительно интересней то, что zip позволяет сохранять потоки. Т.е. не обязательно точно знать размер и CRC файла для заголовка. Например, когда делаешь бэкап БД (на пару гигов) то не нужно сначала это всё во временный файл писать, а потом уже в zip. Можно сразу писать в zip, на лету считая CRC и размеры, и эти данные сохранять после файла (там специальные опции для этого) плюс в центральном каталоге. Вот это уже ни одна из многочисленных доступных реализаций на PHP (по сути они только необходимый минимум умеют) не поддерживает.
А можно даже этот бекап прям сразу на лету и заливать куда-нибудь в облако, не сохраняя у себя вообще никаких временных данных.
PHP позволяет считать хеши инрементально, так что это очень даже возможно и, вроде, не сложно.
Я думаю, что следующая статья как раз про это и будет, постараюсь только набросать хоть как-нибудь интересный proof of concept, чтоб это можно было запустить и пощупать результат.
PHP позволяет считать хеши инрементально, так что это очень даже возможно и, вроде, не сложно.
Я думаю, что следующая статья как раз про это и будет, постараюсь только набросать хоть как-нибудь интересный proof of concept, чтоб это можно было запустить и пощупать результат.
Чисто технически нет проблем, я даже прикручивал сжатие и шифрование на лету. Можно покопать в сторону фильтров (именно на них делал), ну и будет не совсем банальное решение. Но в реальности вылазит такое ограничение, как скорость аплоада. Т.е. аплоад на облако может длиться в десятки раз дольше самого бэкапа. Если заливать на тот же Dropbox. То лучше всё же сохранять бэкап на локалке, чтобы сделать это как можно быстрее и разлочить базу. А потом уже потихоньку заливать. Причем заливать можно в несколько параллельных потоков, что сильно ускоряет процесс.
Ну и в любом случае, решение проверить на больших файлах (чтобы не помещались в разнообразные буферы), в основном все «вкусности» там вылазят.
Ну и в любом случае, решение проверить на больших файлах (чтобы не помещались в разнообразные буферы), в основном все «вкусности» там вылазят.
Спасибо большое за статью!
Всегда нравились с потрошением каких-нибудь популярных штук, общаться с которыми (со штуками) доводилось только через API.
С моей точки зрения, наиболее жизненное использование знаний приведённых в статье — это организация скачивания из веб-приложения нескольких файлов одним запросом. Подобное реализовано в популярных облачных хранилищах файлов.
Причём реализовать это можно в виде «realtime стриминга» без предварительного создания zip-файла на диске сервера. И ещё будет возможность докачки после разрыва связи, т.к. за счёт отсутствия сжатия мы можем быстро рассчитать итоговый размер архива, и определять что должно находится по любому смещению от его начала.
Причём реализовать это можно в виде «realtime стриминга» без предварительного создания zip-файла на диске сервера. И ещё будет возможность докачки после разрыва связи, т.к. за счёт отсутствия сжатия мы можем быстро рассчитать итоговый размер архива, и определять что должно находится по любому смещению от его начала.
У популярных облачных хранилищ скорей всего есть предрасчитанный crc32, что немного им упрощает дело.
Я постараюсь в следующей статье показать вариант, когда мы даже не знаем размер упаковываемых файлов (например, у нас список URL, а мы хотим собрать zip-архив с содержимым), но можем это все упаковывать на лету и отдавать пользователю одновременно с прогрессом скачивания файла нами.
Но и про ваш вариант, думаю, расскажу :)
Я постараюсь в следующей статье показать вариант, когда мы даже не знаем размер упаковываемых файлов (например, у нас список URL, а мы хотим собрать zip-архив с содержимым), но можем это все упаковывать на лету и отдавать пользователю одновременно с прогрессом скачивания файла нами.
Но и про ваш вариант, думаю, расскажу :)
Приходилось делать подобную систему. Там файлы для «упаковки» собирались из достаточно больших блоков (до 3Гб макс, файл чуть меньше 4Гб макс — ограничение зипа), и часть блоков была динамическая. Пересчитывать crc для всего файла на лету при таких размерах, понятно, не вариант. :)
Рассчитанные crc всех статических блоков хранились, для динамических считались в процессе генерации и подгонялись так, чтобы общий crc файла сходился.
Отдавалось всё это через nginx с использованием SSI, в итоге пхп на выходе выдавал динамические блоки + SSI-разметку для nginx, а тот уже сам «собирал» итоговый файл из разных блоков с диска по мере необходимости.
Точно так же потом собирался и рар-архив без сжатия.
Ещё таймстэмпы, конечно, реальные были, и куча всего другого :)
И докачка была, с вычислением смещения и отдачей только нужного куска.
Зип со сжатием тоже делал, но для файлов поменьше. Теоретически, его тоже можно делать с предрассчитанными «блоками» (при аналогичной задаче «сборки» файла из блоков), надо поковыряться немного с кишками deflate для уточнения, но большие всё равно были уже жатые так что необходимости в этом так и не возникло.
Всё собирался статью писать, но не думаю, что дойдут руки… Так что если вдруг интересны какие-то детали…
Рассчитанные crc всех статических блоков хранились, для динамических считались в процессе генерации и подгонялись так, чтобы общий crc файла сходился.
Отдавалось всё это через nginx с использованием SSI, в итоге пхп на выходе выдавал динамические блоки + SSI-разметку для nginx, а тот уже сам «собирал» итоговый файл из разных блоков с диска по мере необходимости.
Точно так же потом собирался и рар-архив без сжатия.
Ещё таймстэмпы, конечно, реальные были, и куча всего другого :)
И докачка была, с вычислением смещения и отдачей только нужного куска.
Зип со сжатием тоже делал, но для файлов поменьше. Теоретически, его тоже можно делать с предрассчитанными «блоками» (при аналогичной задаче «сборки» файла из блоков), надо поковыряться немного с кишками deflate для уточнения, но большие всё равно были уже жатые так что необходимости в этом так и не возникло.
Всё собирался статью писать, но не думаю, что дойдут руки… Так что если вдруг интересны какие-то детали…
Большое спасибо!
Очень люблю почитать вот такие истории, особенно когда в них фигурирует php:)
Насчет ssi думал когда нужно было склеивать несколько файлов и отдавать как один, но как-то дальше думать это не пошло и пока все это дело на lua.
Вообще реально им собирать несколько удаленных файлов в один?
То есть у меня есть location с proxy_pass, который отдает файл откуда-то.
но файл может быть разбит на насколько (ну, например, зип-архив просто разбитый на куски по 200мб, не многотомник) и пользователю нужно, соответственно, отдать нормальный файл, а не 2-3куска. я могу отдать из php такой ssi, чтоб nginx последовательно подсунул пользователю несколько кусков как один файл?
Очень люблю почитать вот такие истории, особенно когда в них фигурирует php:)
Насчет ssi думал когда нужно было склеивать несколько файлов и отдавать как один, но как-то дальше думать это не пошло и пока все это дело на lua.
Вообще реально им собирать несколько удаленных файлов в один?
То есть у меня есть location с proxy_pass, который отдает файл откуда-то.
но файл может быть разбит на насколько (ну, например, зип-архив просто разбитый на куски по 200мб, не многотомник) и пользователю нужно, соответственно, отдать нормальный файл, а не 2-3куска. я могу отдать из php такой ssi, чтоб nginx последовательно подсунул пользователю несколько кусков как один файл?
Ну да, конечно. Там получается в итоге просто последовательно несколько SSI-тегов со ссылками на соответствующие куски/локейшны. И между ними если надо можно вставлять всё, что душе угодно — nginx корректно всё обрабатывает. На другом проекте по тому же принципу менялась иконка в exe-файле — подготовленные блоки + рассчитанные куски секции ресурсов, заголовки, контрольные суммы, и т.п. PHP отдавал nginx-у мешанину из байтиков и ssi-тегов, а тот уже всё собирал по мере отдачи файла.
Т.е. например если юзер прерывал загрузку в самом начале nginx уже не читал следующие блоки с диска.
Т.е. например если юзер прерывал загрузку в самом начале nginx уже не читал следующие блоки с диска.
Конечно, любой адекватный человек скажет, что писать архиваторы на php это бесполезная затеяОдин знакомый писал рекурсивный упаковщик на Basic. Да, рекурсивный в смысле ненулевого прироста сжатия в каждой итерации. На вид был вполне нормальным. Чем закончился проект — засекречиванием или белой рубашкой с не по росту длинными рукавами — не знаю, потерялись.
Не забывайте про фактор кодировки для имени файла в архиве!
По поводу применения — таким подходом я пользовался, чтобы дать пользователям возможность скачивать несколько файлов за раз…
По поводу применения — таким подходом я пользовался, чтобы дать пользователям возможность скачивать несколько файлов за раз…
Интересно.
Ну, я с zip тоже не за 5 минут разобрался)
Главное время и упорство, а там все получится.
Главное время и упорство, а там все получится.
Попробуйте http://kaitai.io/ — очень полезная штука для ковыряния в кишках бинарников.
Делал подобную дичь для использования в 1с, которая хранит сжатые данные в deflate: к ним пришлось прикручивать все рассчитанные секции zip-формата, чтобы потом можно было извлечь данные из полноценного zip-архива.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
Как выглядит zip-архив и что мы с этим можем сделать