Головні новини
Ви тут: Головна / php / Генеруємо документи Microsoft Word на PHP

Генеруємо документи Microsoft Word на PHP



Ми живемо в світі, де PHP розробникам доводиться час від часу взаємодіяти з операційною системою Windows. WMI (Windows Management Interface, Інтерфейс управління Windows) – один з таких прикладів – взаємодія з Microsoft Office.

У даній статті ми розглянемо просту інтеграцію між Word і PHP: генерацію документа Microsoft Word на основі полів введення в HTML-формі за допомогою PHP (та його розширення Interop).

Підготовчі кроки

Першим ділом переконаємося, що у нас налаштоване базове оточення WAMP. Так як Interop присутня тільки в Windows, то нам необхідно, щоб наш сервер Apache і інсталяція PHP були розгорнуті на Windows машині. У цій якості я використовую EasyPHP 14.1, який вкрай простий в установці та налаштуванні.

Наступною справою необхідно встановити Microsoft Office. Версія не дуже важлива. Я використовую Microsoft Office 2013 Pro, але будь-яка версія Office старше 2007 повинна підійти.

Також необхідно переконатися, що у нас встановлені бібліотеки для розробки додатку Interop (PIA, Primary Interop Assemblies, Основні Сборки Interop). Дізнатися це можна відкривши Провідник Windows, і перейшовши в директорію \assembly, і там ми повинні побачити набір встановлених зборок:

1405290176PIA

Тут можна побачити елемент Microsoft.Office.Interop.Word (підкреслений на скріншоті). Це буде та збірка, яку ми будемо використовувати в нашій демонстрації. Будь ласка, зверніть особливу увагу на поля “Assembly name (Ім’я збірки)”, “Version (Версія)” і “Public key token (Токен публічного ключа)”. Їх ми скоро будемо використовувати в нашому PHP скрипті.

У цій директорії також присутні й інші збірки (включаючи і все сімейство Office), доступні для використання у своїх програмах (не тільки для PHP, але також і для VB.net, C#, і т.д.).

Якщо список збірок не включає весь пакет Microsoft.Office.Interop, то нам потрібно або перевстановити Office, додавши PIA, або вручну завантажити пакет з сайту Microsoft і встановити його. Для більш детальних інструкцій зверніться до цієї сторінки на MSDN.

Зауваження: до завантаження та встановлення доступний тільки дистрибутив PIA Microsoft Office 2010. Версія зборок в цьому пакеті 14.0.0, а 15 версія поставляється тільки з Office 2013.

І, нарешті, необхідно включити розширення php_com_dotnet.dll в php.ini і перезапустити сервер.

Тепер можна перейти до програмування.

HTML форма

Так як основна частина даного прикладу лягає на серверну сторону, ми створимо просту сторіночку з формою, яка буде виглядати наступним чином:
form

У нас є текстове поле для імені, група перемикачів для статті, слайдер для віку, і область введення тексту для введення повідомлення, а також відома кнопка “Відправити”.

Збережіть цей файл як “index.html” в директорії віртуального хоста, щоб до нього можна було дістатися за адресою типу http://test/test/interop.

Серверна частина

Файл-обробник на серверній стороні – це основна мета нашої розмови. Для початку я приведу повний код цього файлу, а потім поясню його крок за кроком.

<?php

$inputs = $_POST;
$inputs['printdate']='';
// Ініціалізація значення, щоб уникнути зауваження від PHP про те, що в POST даних немає змінної "printdate"

$assembly = 'Microsoft.Office.Interop.Word, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c';
$class = 'Microsoft.Office.Interop.Word.ApplicationClass';

$w = new DOTNET($assembly, $class);
$w->visible = true;

$fn = __DIR__ . '\\template.docx';

$d = $w->Documents->Open($fn);

echo "Документ відкритий.<br><hr>";

$flds = $d->Fields;
$count = $flds->Count;
echo "У документі $count полів.<br>";
echo "<ul>";
$mapping = setupfields();

foreach ($flds as $index => $f)
{
 $f->Select();
 $key = $mapping[$index];
 $value = $inputs[$key];
 if ($key == 'gender')
 {
 if ($value == 'm')
 $value = 'Mr.';
 else
 $value = 'Ms.';
 }

 if($key=='printdate')
 $value= date ('Y-m-d H:i:s');

 $w->Selection->TypeText($value);
 echo "<li>Призначаю полю $index: $key значення $value</li>";
}
echo "</ul>";

echo "Обробка завершена!<br><hr>";
echo "Друкую, будь ласка, зачекайте...<br>";

$d->PrintOut();
sleep(3);
echo "Готово!";

$w->Quit(false);
$w=null;

function setupfields()
{
 $mapping = array();
 $mapping[0] = 'gender';
 $mapping[1] = 'name';
 $mapping[2] = 'age';
 $mapping[3] = 'msg';
 $mapping[4] = 'printdate';


 return $mapping;
}

Після того, як ми записали в змінну $inputs значення, отримані з форми, а також створили порожній елемент з ключем printdate (навіщо ми це зробили – обговоримо пізніше), ми переходимо до чотирьох дуже важливих рядків:

$assembly = 'Microsoft.Office.Interop.Word, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c';
$class = 'Microsoft.Office.Interop.Word.ApplicationClass';

$w = new DOTNET($assembly, $class);
$w->visible = true;

Маніпулятор COM в PHP вимагає створення екземпляра класу в рамках “збірки”. У нашому випадку ми працюємо з Word. Якщо поглянути на перший скріншот, то можна записати повну сигнатуру збірки для Word:

“Name”, “Version”, “Public Key Token” – все це береться з інформації, яку можна переглянути в “c:\Windows\assembly”.
“Culture” завжди neutrual
Клас, на який ми хочемо посилатися, завжди називається “імя.збірки”+”.ApplicationClass”.

Встановивши два цих параметра ми зможемо отримати об’єкт для роботи з Word.

Цей об’єкт може залишатися в тлі, або ми можемо перевести його в робочий режим установкою атрибута visible в true.

Наступним кроком відкриваємо документ, що вимагає обробки, і записуємо примірник “документа” в змінну $d.

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

Самим неправильним було б жорстко прописати вміст документа в PHP, а потім вивести його в документ Word. Я настійно рекомендую цього не робити з наступних причин:

Ви втрачаєте гнучкість. Будь-які зміни в вихідному файлі зажадають зміни коду PHP.
Це порушує поділ управління та виду
Застосування стилів до вмісту документа (вирівнювання, шрифти, стилі, і т.д.) в скрипті сильно збільшить кількість рядків коду. Програмне зміна стилів надто громіздко.
Іншим варіантом буде використання пошуку і заміни. У PHP є хороші вбудовані засоби для цього. Ми можемо створити документ Word, в якому розмістимо мітки зі спеціальними роздільниками, які надалі будуть замінені. Наприклад, ми можемо створити документ, який буде містити наступний фрагмент:

{{Name}}

а за допомогою PHP ми легко можемо замінити його на вміст поля “Ім’я”, отримане з форми.

Це просто, і позбавляє нас від усіх неприємних наслідків, з якими ми стикаємося в першому способі. Нам лише потрібно визначитися з правильним роздільником, і в цьому випадку ми, виходить, використовуємо шаблон.

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

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

Word з самого початку не підтримував іменні індекси для полів. Навіть якщо ми і вказали імена для створюваних полів – нам все одно необхідно користуватися числовими ідентифікаторами цих полів. Це також пояснює, навіщо нам потрібно використовувати окрему функцію (setupfields) для того, щоб задати відповідність індексу поля та імені поля з форми.

В цьому демонстраційному уроці ми будемо використовувати документ з 5 полями MERGEFIELD. Шаблонний документ розмістимо там же, де і наш скрипт-обробник.

Прошу зауважити, що поле printdate не має відповідного поля на формі. Ось навіщо ми додали порожній елемент printdate в масив $ inputs . Без цього скрипт все ж буде запускатися і працювати, але PHP буде видавати попередження, що індекс printdate відсутня в масиві $inputs .

Після заміни полів новими значеннями ми віддрукуємо документ за допомогою

$d->PrintOut();

Метод PrintOut приймає кілька необов’язкових параметрів, і ми використовуємо найпростішу його форму. Так буде видрукувана одна копія документа на принтері за замовчуванням, який приєднаний до Windows-машині.

Також можна викликати PrintPreview , щоб поглянути на отриманий результат, перш ніж його віддрукувати. В повністю автоматичному оточенні ми, звичайно ж, будемо використовувати метод PrintOut .

Необхідно почекати деякий час, перш ніж завершити роботу з додатком Word, так потрібно час на те щоб поставити в чергу завдання на друк. Без delay (3) метод $ w-> Quit виконується негайно, і завдання не ставиться в чергу.

Нарешті, ми викликаємо $ w-> Quit (false) , що закриває додаток Word, яке було викликано нашим скриптом. Єдиним параметром, переданим в метод, є вказівка ​​зберегти файл перед виходом. Ми зробили правки в документі, але ми не хочемо їх зберігати, так як нам потрібен чистий шаблон для подальшої роботи.

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

1405290174php

1405290179word

Поліпшення швидкості обробки і трохи докладніше про PIA

PHP – слабо типізована мова. Об’єкт COM типу Object. Під час написання скрипта у нас немає можливості отримати опис об’єкта, будь воно додатком Word, документом або полем. Ми не знаємо, які властивості є в цього об’єкта, або які він підтримує методи.

Це сильно сповільнить швидкість розробки. Щоб прискорити розробку, я б рекомендував писати функції спочатку на C#, а після переводити код в PHP. Я можу рекомендувати безкоштовну IDE для розробки на C# під назвою “#develop”. Знайти її можна тут. Я віддаю перевагу її Visual Studio, так як #develop менше, простіше і швидше.

Міграція C# коду в PHP не так страшна, як здається. Давайте я покажу вам пару рядків на C#:

Можна помітити, що код на C # дуже схожий на код PHP, який я показував раніше. C # – строго типізований мову, так що в цьому прикладі можна помітити кілька операторів приведення типів, а також змінним необхідно вказувати тип.

Із зазначенням типу змінної, можна насолоджуватися більш зрозумілим кодом і автодоповнення, і швидкість розробки істотно підвищується.

Інший спосіб підвищити швидкість розробки на PHP – викликати макрос в Word. Ми проводимо ту ж послідовність дій, а після зберігаємо її як макрос. Макрос написаний на Visual Basic, який також просто перевести в PHP.

І, що найважливіше – документація по Office PIA від Microsoft , особливо документація по просторам імен кожного додатка Office є самим детальним довідковим матеріалом. Найбільш використовувані три додатки:

Excel 2013: http://msdn.microsoft.com/en-us/library/microsoft.office.interop.excel(v=office.15).aspx
Word 2013: http://msdn.microsoft.com/en-us/library/microsoft.office.interop.word(v=office.15).aspx
PowerPoint 2013: http://msdn.microsoft.com/en-us/library/microsoft.office.interop.powerpoint(v=office.15).aspx

Висновок

У цій статті ми показали, як заповнити даними документ Word за допомогою бібліотек PHP COM і можливостями взаємодії Microsoft Office.

Windows і Office широко використовуються в повсякденному житті. Знати силу Office / Window і PHP буде корисно кожному PHP і Windows розробнику.

За допомогою розширення PHP COM вам відчиняються двері до використання цієї комбінації.

Також хотілось би упомянути дуже крутий сайт на який я недавно завітав. В ньому можна купить канцелярию дешево. Рекомендую цей сайт для покупки канцелярії.



Автор Володимир Гривінський



Залишити коментар

Ваша електронна адреса не буде опублікована.

Вгору
UA TOP Bloggers