Поиск по сайту:
taxpert.ruБлог — Вставка колонтитулов в DOCX без PHPWord

Вставка колонтитулов в DOCX без PHPWord

22.10.2020

Секция: Сайтостроение и WEB-разработка

Просмотров: 565

Комментарии (1)добавить комментарий

Примерно с неделю тому назад передо мной была поставлена руководством задача автоматической вставки колонтитулов в документы формата MS Word — DOCX. В принципе, никаких особых сложностей не предвиделось: ведь DOCX — это всего лишь zip-архив с XML-файлами внутри. А те, в свою очередь — всего лишь структурированный текст. То есть теоретически можно было даже обойтись своими силами, без каких-либо фреймворков типа PHPWord. Ну, погнали?

Вычислить изменения, которые необходимо проделать с элементами документа, особого труда не составило: следы вставленного в нижнюю часть страницы колонтитула отчётливо обозначились в нескольких элементах внутренней структуры документа, затем был составлен список необходимых для вставки колонтитула манипуляций со структурой документа — осталось лишь проделать то же самое в автоматическом режиме. Разумеется, распаковывать архивы своими силами, на мой взгляд, было бы перебором — предоставленная мне версия PHP скомпилирована с подключенной библиотекой ZipArchive.

Буквально в тот же день составления списка необходимых изменений в элементах документа, радостно потирая руки в предвкушении заветного результата, я запустил готовый PHP-сценарий вставки колонтитула, затем открыл обработанный скриптом документ, и... не увидел в нижней части страницы никаких колонтитулов. Вообще говоря, это в порядке вещей: обычно при первых запусках у меня неизменно обнаруживаются какие-нибудь мелкие, но досадные ошибки, и порой приходится потратить немало времени, чтобы их выловить и исправить. На сей раз, однако, самая тщательная проверка не выявила ни малейших ошибок. Следующая проверка, ещё более тщательная, также не принесла никаких результатов. Тем не менее колонтитулы в документе упорно отказывались появляться.

Постепенно, в результате многочисленных экспериментов с документами, стало ясно, что ручная вставка колонтитула — методом модификации элементов внутренней структуры документа — приводит к успеху, тогда как попытки сделать то же самое автоматически, посредством PHP-сценария — дают нулевой результат.

Попутные усилия решить задачу при помощи PHPWord завершились бесполезной потерей колоссального количества времени: оказалось, что разработка этого фреймворка, версия beta 0.6.3 которого была создана одним разработчиком, продолжилась силами других разработчиков, причём с необходимостью установки через какой-то Composer (без него фреймворк категорически отказывался работать), по поводу которого никто (включая разработчиков PHPWord) особо не стал заморачиваться с объяснениями, что это такое, где его искать и как запускать (настраивает зависимости, набираете в консоли «бла-бла-бла -опции» и пользуетесь — офигительный мануал, даже и спросить-то особо нечего после этого). Постепенно, по крупицам, удалось лишь узнать, что Composer входит в состав OpenServer (последний, если что — это наследник знаменитого программного пакета PHP-разработчиков Denwer) и даже запускается через консоль OpenServer, хотя и устарел, о чём выводится соответствующее уведомление, и даже что-то делает, но что, как и зачем — хрен его знает. Ещё удалось узнать, что начиная с 2016 года разработчики PHPWord принялись клепать версии своего продукта, которые без Composer якобы вообще в принципе невозможно установить. Правда или нет — не в курсе, потому что идея воспользоваться плодом такого редкостного программного рукожопия была отложена мной до наступления самого-самого крайнего случая.

Но я отвлёкся. Вернёмся к вставке колонтитула своими силами. Убедившись в десятый или в двадцатый раз, что все необходимые манипуляции по вставке колонтитула с документом моим PHP-сценарием безрезультатны (при видимом наличии внутри структуры документа следов этих манипуляций), во время одного из экспериментов я практически случайно обнаружил любопытный эффект: достаточно было разархивировать документ обычным архиватором, а потом заархивировать обратно и переименовать в DOCX — как внизу документа откуда ни возьмись появлялся вожделённый колонтитул. После этого мне стало, что причиной первоначального отсутствия колонтитула сразу после обработки являются никакие не ошибки, а что-то другое. Что?

Вот тогда-то меня и заинтересовали права элементов внутри DOCX. Да, конечно, есть правая кнопка мыши, и есть меню «Свойства», но шанс узнать подробную, корректную информацию о файле, тем более из архива, таким способом — крайне невелик. А значит, права элементов внутри документа — останутся тайной за семью печатями?

Только не для программистов. В PHP есть замечательный оператор fileowner, который не мудрствуя лукаво возвращает числовой идентификатор владельца любого элемента файловой системы. Именно он и помог мне быстро прояснить ситуацию: вставляемый в документ шаблон колонтитула в формате XML имел совершенно иной идентификатор владельца, нежели размещённые в документе элементы.

По всей видимости, это и было истинной причиной отсутствия колонтитула: то ли текстовый редактор (нет, не MS Word, потому что работаю под Ubuntu, а это отдельная история!) категорически отказывался выводить в документе «чужой» колонтитул, то ли архив считал «чужой» элемент повреждённым.

И начались танцы с бубном. Попытка изменить владельца шаблона колонтитула — мимо: запрещено (почему — неважно, потом разберёмся, дальше, дальше!) Попытка изменить права на файл перед вставкой в документ — пожалуйста, но изменить после этого владельца файла — опять-таки запрещено (ну и хрен с тобой, золотая рыбка!). Попытка изменить атрибуты элемента уже после вставки в архив методами ZipArchive — пожалуйста, правда, после этого атрибуты не изменятся, но и ошибки не возникает, ну и на том спасибо. Что там ещё в арсенале? Ага, распаковываем из документа элемент-донор атрибутов, и его атрибутами щедро осыпаем шаблон колонтитула — легко, но владелец у шаблона при этом не меняется, снова мимо. Но нас же, программистов, на мякине не проведёшь: извлекаем из документа любой априори присутствующий там элемент (скажем, document.xml), со всеми присущими ему правами и владельцем, вставляем в него текстовое содержимое шаблона колонтитула, проверяем владельца (ага, вот теперь то что надо!), закачиваем обратно, открываем модифицированный таким образом документ, и...

Колонтитул отсутствует.

Это финал. Провал. Абсолютное фиаско. Ассортимент уловок окончательно и бесповоротно исчерпан.

Ровно до тех пор, пока от руководства (нет, я не оговорился!) не поступает простенький такой, но со вкусом сформированный совет: полностью разархивировать документ, модифицировать необходимые элементы и полностью заархивировать обратно в DOCX. Почему бы и нет, если других вариантов уже не осталось? По крайней мере, будет основание заявить: ты сделал всё, что мог. Правда, структура у DOCX не самая однородная, и придётся создать рекурсивную функцию сбора сведений о структуре распакованного документа о пятнадцати строках PHP-кода, чтобы после запуска всей этой конструкции в сто пятидесятый раз запустить полученный архив с расширением DOCX...

...и с искренним изумлением обнаружить заветный колонтитул в том самом месте, где ему полагалось быть ещё несколько дней тому назад.

Безо всяких там PHPWord, средствами одного лишь ZipArchive и собственного кода.

Всё остальное, надеюсь — уже дело техники.

Комментарии

добавить комментарий

24.02.2021 16:25 Комментирует Антон:

Пример кода есть где посмотреть?

Ответ автора сайта: Увы, всё разработанное мной в рабочее время на рабочем месте, согласно доп. соглашению к договору, принадлежит компании, и я не вправе распоряжаться этим кодом по своему усмотрению. В записи блога, впрочем, я описал общий принцип, который несложно реализовать по описанию алгоритма.


© Taxpert. Интернет-мастерская М. Ю. Уткина.