{{tag>php scripts libraries word docx}}

====== Библиотека PHPWord: основные возможности ======
Библиотека [[http://phpword.codeplex.com|PHPWord]], находящаяся уже почти год в стадии бета-тестирования((на 07.05.2011 библиотека имеет версию 0.6.2 от 25.07.2010)), предоставляет возможность создания сложных документов формата OOXML (***.docx**). Рассмотрим основные возможности этой библиотеки. Для начала работы  достаточно распаковать архив с библиотекой в каталог с создаваемым вами документом PHP и подгрузить основной класс библиотеки, расположенный в файле **PHPWord.php**:
<code php>include_once 'PHPWord.php';</code>

===== Свойства документа и шрифт по-умолчанию =====
Создание документа начинается с объявления экземпляра класса PHPWord. Конструктор не требует передачи аргументов:
<code php>$word = new PHPWord();</code>
Далее следует задать название и размер шрифта по-умолчанию:
<code php>$word->setDefaultFontName('Times New Roman');
$word->setDefaultFontSize(14);</code>
В рассматриваемой версии до применения указанных выше функций шрифтом по-умолчанию является **Arial размером 20 пунктов**. Теперь можно задать время создания документа, имя автора и так далее:
<code php>
$meta = $word->getProperties();
$meta->setCreator('Имя создателя документа'); 
$meta->setCompany('Организация');
$meta->setTitle('Название документа');
$meta->setDescription('Описание документа'); 
$meta->setCategory('Категория документа');
$meta->setLastModifiedBy('Имя последнего редактора');
$meta->setCreated( mktime(0, 0, 0, 5, 12, 2011) ); // Дата и время создания документа
$meta->setModified( time() ); //Дата и время последнего изменения документа
$meta->setSubject('Тема документа'); 
$meta->setKeywords('ключевые, слова, документа');
</code>
По-умолчанию в качестве даты создания и изменения документа указывается текущее время, а остальные свойства заполняются пустыми значениями. Если требуется указать конкретную дату создания или изменения, используйте функцию [[php>mktime|mktime]] или любую другую функцию, возвращающую [[wpru>Unix_time|время в стиле Unix]].

===== Создание разделов =====
Основным элементом документа Word является **Раздел**. Раздел представляет собой прямоугольную область, внутри которой помещаются остальные элементы страницы: текст, изображения, таблицы и т.д.

Раздел может иметь книжную или альбомную ориентацию, настраиваемые поля (margins), настраиваемые цвета границ раздела и их толщину (на рисунке показана пунктиром):
^  Параметр  ^  Описание  ^
|orientation  |Ориентация страницы:\\ null - книжная ориентация,\\ landscape - альбомная  |
|marginTop  |Размер верхнего поля во внутренних единицах  |
|marginRight  |Размер правого поля во внутренних единицах  |
|marginBottom  |Размер нижнего поля во внутренних единицах  |
|marginLeft  |Размер левого поля во внутренних единицах  |
|borderTopSize  |Толщина верхнего края рамки во внутренних единицах  |
|borderRightSize  |Толщина правого края рамки во внутренних единицах  |
|borderBottomSize  |Толщина нижнего края рамки во внутренних единицах  |
|borderLeftSize  |Толщина левого края рамки во внутренних единицах  |
|borderTopColor  |Цвет верхнего края рамки в шестнадцатеричном формате  |
|borderRightColor  |Цвет правого края рамки в шестнадцатеричном формате  |
|borderBottomColor  |Цвет нижнего края рамки в шестнадцатеричном формате  |
|borderLeftColor  |Цвет левого края рамки в шестнадцатеричном формате  |
Для создания раздела существует функция **createSection**. В качестве внутренних единиц используются [[wpru>Twip|типографские твипы]]. Если вам непривычно указывать размеры в твипах, можно написать простую функцию, преобразующую миллиметры в твипы:
<code php>
function m2t($millimeters){
  return floor($millimeters*56.7); //1 твип равен 1/567 сантиметра
}//m2t
</code>
Указанные в таблице параметры могут быть переданы в виде массива при создании раздела...
<code php>
$sectionStyle = array('orientation' => 'landscape',
               'marginLeft' => m2t(15), //Левое поле равно 15 мм
               'marginRight' => m2t(15),
               'marginTop' => m2t(15),
               'borderTopColor' => 'C0C0C0'
         );
$section = $word->createSection($sectionStyle);
</code>
... или могут быть установлены по-отдельности после создания раздела:
<code php>
$section = $word->createSection();
$sectionStyle = $section->getSettings();
$sectionStyle->setLandscape(); //или setPortrait()
$sectionStyle->setMarginLeft(m2t(15));
$sectionStyle->setMarginRight(m2t(15));
$sectionStyle->setBorderBottomSize(m2t(1));
$sectionStyle->setBorderTopColor('C0C0C0');
</code>

===== Добавление текста =====
==== Добавление блока текста ====
Под блоком текста понимается отрывок текста, имеющий одинаковое форматирование (цвет, размер шрифта и т.п.). Для создания блока текста в выбранном разделе используйте функцию **addText**:
<code php>$section->addText( $text, [$fontStyle[, $paragraphStyle]] );</code>
Здесь $text - добавляемый текст, необязательный параметр $fontStyle - имя определенного ранее текстового стиля, необязательный параметр $paragraphStyle - имя определенного ранее стиля абзаца.

==== Изменение форматирования текста ====
Форматирование текста, как и форматирование раздела, может осуществляться при его создании...
<code php>
$fontStyle = array('color'=>'FFFF00', 'size'=>18, 'bold'=>true);
$section->addText('Привет!', $fontStyle); //Массив с параметрами форматирования передается при создании
</code>
... или устанавливается после создания предназначенными для этого методами:
<code php>
$text = $section->addText('Привет!');
$style = $text->getStyle();
$style->setColor('FFFF00');
$style->setSize(18);
$style->setBold();
</code>

Ниже приведен полный список доступных параметров форматирования текста:
^Параметр  ^Описание  ^
|size  |Размер шрифта в типографских пунктах  |
|name  |Название шрифта (кегль)  |
|bold  |Является ли текст полужирным (true\false)  |
|italic  |Выделен ли текст курсивом (true\false)  |
|superScript  |Является ли текст надстрочным (true\false)  |
|subScript  |Является ли текст подстрочным (true\false)  |
|underline  |Вид подчеркивания((Все возможные виды подчеркивания можно посмотреть в диалоге **Шрифт** Microsoft Word)) из набора констант PHPWord_Style_Font:\\ UNDERLINE_NONE - нет подчеркивания,\\ UNDERLINE_DASHHEAVY - жирная штриховая линия,\\ UNDERLINE_DASHLONG - удлиненная штриховая линия,\\ UNDERLINE_DASHLONGHEAVY - удлиненная жирная штриховая линия,\\ UNDERLINE_DOUBLE - двойная линия,\\ UNDERLINE_DOTHASH((Вообще должно быть UNDERLINE_DOTDASH, видимо опечатка в коде)) - штрих-пунктир,\\ UNDERLINE_DOTHASHHEAVY - жирный штрих-пунктир,\\ UNDERLINE_DOTDOTDASH - две точки + тире,\\ UNDERLINE_DOTDOTDASHHEAVY - жирные две точки + тире,\\ UNDERLINE_DOTTED - пунктир,\\ UNDERLINE_DOTTEDHEAVY - жирный пунктир,\\ UNDERLINE_SINGLE - одинарная линия,\\ UNDERLINE_WAVY - волнистая линия,\\ UNDERLINE_WAVYDOUBLE - двойная волнистая линия,\\ UNDERLINE_WAVYHEAVY - тройная волнистая линия,\\ UNDERLINE_WORDS - подчеркивать только слова (не подчеркивать пробелы)  |
|Color  |Цвет шрифта в шестнадцатеричном формате  |
|fgColor  |Цвет выделения маркером из набора констант PHPWord_Style_Font:\\ FGCOLOR_YELLOW - желтый,\\ FGCOLOR_LIGHTGREEN - ярко-зеленый,\\ FGCOLOR_CYAN - бирюзовый,\\ FGCOLOR_MAGENTA - лиловый,\\ FGCOLOR_BLUE - синий,\\ FGCOLOR_RED - красный,\\ FGCOLOR_DARKBLUE - темно-синий,\\ FGCOLOR_DARKCYAN - сине-зеленый,\\ FGCOLOR_DARKGREEN - темно-зеленый,\\ FGCOLOR_DARKMAGENTA - фиолетовый,\\ FGCOLOR_DARKRED - темно-красный,\\ FGCOLOR_DARKYELLOW - коричнево-зеленый,\\ FGCOLOR_DARKGRAY - серый 50%,\\ FGCOLOR_LIGHTGRAY - серый 25%,\\ FGCOLOR_BLACK - черный  |
Названия параметров должны употребляться с соблюдением регистра. В случае параметров **underline** и **fgColor** применение значений, не указанных в таблице, не допускается.

Cписок доступных параметров форматирования абзаца:
^Параметр  ^Описание  ^
|align  |Выравнивание текста в абзаце:\\ left - по левому краю,\\ right - по правому краю,\\ center - по центру,\\ both или justify - по ширине  |
|spaceBefore  |Отступ абзаца сверху в твипсах  |
|spaceAfter  |Отступ абзаца снизу в твипсах  |
|spacing  |Интервал между строк в твипсах  |

==== Определение стилей текста и абзаца ====
Вместо того, чтобы каждый раз передавать в функцию createText массив с параметрами, вы можете создать именованный стиль, а затем указывать только название этого стиля:
<code php>$word->addFontStyle($styleName, $fontStyle);</code>
Здесь **$styleName** - заданное вами имя стиля, **$fontStyle** - массив, содержащий определение стиля. После создания стиля его имя можно использовать при создании блоков текста, например:
<code php>
$fontStyle = array('color'=>'006699', 'size'=>18, 'italic'=>true, underline=>PHPWord_Style_Font::UNDERLINE_DOUBLE);
$word->addFontStyle('myTextStyle', $fontStyle); //myTextStyle - это имя стиля
$text = $section->addText('Привет!', 'myTextStyle');
</code>

Аналогичным образом осуществляется создание стиля абзаца:
<code php>
$paragraphStyle = array('color'=>'006699', 'size'=>18, 'italic'=>true, underline=>UNDERLINE_DOUBLE);
$word->addParagraphStyle('myParagraphStyle', $paragraphStyle);
$text = $section->addText('Привет!', 'myTextStyle', 'myParagraphStyle');
</code>

==== Группировка блоков текста в абзац ====
Блоки текста с различным форматированием могут быть объединены в абзац заданного вида. Для этого применяется команда **createTextRun**:
<code php>$textrun = $section->createTextRun([$paragraphStyle]);
$textrun->addText('Полужирный текст', array('bold'=>true)); 
$textrun->addText('Курсив', array('italic'=>true));
$textrun->addText('Цветной текст', array('color'=>'AACC00'));
</code>
Необязательный параметр **$paragraphStyle** - массив со стилем абзаца или название созданного ранее именованного стиля.

==== Добавление заголовков ====
В библиотеке имеются отдельные функции для добавления заголовков (**addTitle**) и задания их стилей (**addTitleStyle**). Применение заголовков вместо форматированных блоков текста необходимо в том случае, если вы хотите добавить в документ автоматически создаваемое оглавление, поскольку в оглавление включаются только заголовки, а не обычные блоки текста. При добавлении заголовков создание стилей заголовков обязательно:
<code php>$word->addTitleStyle($titleLevel[, $fontStyle[, $paragraphStyle]]);</code>
Здесь **$titleLevel** - уровень заголовка, для которого задается стиль (обычно от 1 до 6), **$fontStyle** - массив со стилем форматирования заголовка, **$paragraphStyle** - массив со стилем форматирования абзаца. Как видите, форматирование можно не трогать, но сам стиль заголовка требуемого уровня должен быть обязательно создан. Добавление заголовка делается так:
<code php>$section->addTitle( $text[, $titleLevel]);</code>
По-умолчанию создается заголовок 1 уровня.

==== Добавление ссылок ====
Добавление ссылок мало чем отличается от добавления обычного текста. Для добавления ссылки используется команда:
<code php>$section->addLink($url, [$text[, $fontStyle[, $paragraphStyle]]]);</code>
Здесь **$url** - URL ссылки. В случае, если $text не указана в качестве отображаемого текста, используется URL. Не знаю зачем, но для изменения форматирования ссылок используется отдельная функция **addLinkStyle**. Ее аргументы полностью совпадают с аргументами **addFontStyle**. Если требуется указать название стиля, но переменную **$text** хочется оставить пустой, передайте ей значение null:
<code php>$section->addLink('http://www.phpexport.ru/', NULL, 'myLinkStyle');</code>

==== Разрыв строки и страницы ====
Для принудительного переноса строки используйте синтаксис:
<code php>$section->addTextBreak([$num]);</code>
Необязательный параметр $num, по-умолчанию равный 1, указывает сколько переносов строки необходимо сделать. Для принудительной вставки разрыва страницы выполните:
<code php>$section->addPageBreak();</code>

==== Добавление оглавления ====
Для добавления оглавления используется функция **addTOC**:
<code php>$section->addTOC([$fontStyle[, $tocStyle]]);</code>
Здесь **$fontStyle** - форматирование текста, определенное одним из ранее указанных способов, **$tocStyle** - массив со стилем оформления оглавления, возможные параметры которого приведены в таблице:
 ^  Параметр  ^  Описание  ^
|tabLeader  |Заполнитель между заголовком и номером страницы из набора констант PHPWord_Style_TOC:\\ TABLEADER_DOT - точки,\\ TABLEADER_UNDERSCORE - символ подчеркивания,\\ TABLEADER_LINE - линия,\\ TABLEADER_NONE - нет заполнителя  |
|tabPos  |Положение номера страницы в твипсах  |
|Indent  |Отступ заголовков в твипсах  |

===== Добавление списков =====
Присутствует возможность добавления нумерованных и ненумерованных списков в документ. Для добавления элемента списка используйте код:
<code php>$section->addListItem( $text[, $depth[, $textStyle[, $listStyle[, $paragraphStyle]]]]);</code>
Здесь **$text** - текст добавляемого элемента списка, **$depth** - глубина вложенности элемента в списке (от 1 до 9, по-умолчанию равна 1), **$textStyle** - форматирование текста списка одним из предложенных ранее способов, **$listStyle** - форматирование самого списка при помощи массива параметров, **$paragraphStyle** - форматирование абзаца. На данный момент не существует функции **addListStyle**, поскольку у списков пока может изменяться только один параметр:
^  Параметр  ^  Описание  ^
|listType  |Вид списка из набора констант PHPWord_Style_ListItem:\\ TYPE_NUMBER - одноуровневый нумерованный список,\\ TYPE_NUMBER_NESTED - многоуровневый нумерованный список,\\ TYPE_BULLET_FILLED - ненумерованный список с маркерами в виде закрашенных кругов,\\ TYPE_BULLET_EMPTY - ненумерованный список с маркерами в виде незакрашенных кругов,\\ TYPE_SQUARE_FILLED - ненумерованный список с маркерами в виде закрашенных квадратов  |

===== Добавление таблиц =====
Важной частью документа Word являются таблицы. Для создания таблицы в PHPWord выполните:
<code php>$table = $section->addTable([$tableStyle]);</code>
Необязательный аргумент **$tableStyle** - массив с описанием стиля таблицы или название такового, определенного методом **addTableStyle**:
<code php>$word->addTableStyle($styleName,  $tableStyle[, $firstRowStyle]);</code>
Аргументы: **$styleName** - название стиля, **$tableStyle** - массив с определением стиля, **$firstRowStyle** - массив с определением стиля ячеек 1 строки (шапки) таблицы. Ниже приведена таблица возможных стилевых параметров таблицы в целом:
 ^  Параметр  ^  Описание  ^
|cellMarginTop  |Отступ от ячейки сверху в твипсах  |
|cellMarginRight  |Отступ от ячейки справа в твипсах  |
|cellMarginBottom  |Отступ от ячейки снизу в твипсах  |
|cellMarginLeft  |Отступ от ячейки слева в твипсах  |
Теперь в созданную таблицу можно добавить ячейки. Как и в XHTML, вначале нужно создать строку...
<code php>$table->addRow([$rowHeight]);</code>
... затем добавить ячейки и заполнить их форматированным текстом...
<code php>
$cell = $table->addCell([$cellWidth[, $cellStyle]]);
$cell->addText('Текст ячейки');
</code>
... или сделать то же самое одной командой...
<code php>$table->addCell([$cellWidth[, $cellStyle]])->addText('Текст ячейки');</code>
... или вместо простого текста добавить изображения, списки ссылки одной из следующих команд:
^  Команда  ^  Действие  ^
|addText  |Добавить форматированный текст  |
|addTextBreak  |Добавить перенос строки  |
|addLink  |Добавить ссылку  |
|addListItem  |Добавить элемент списка  |
|addImage  |Добавить изображение из файла  |
|addMemoryImage  |Добавить динамически сгенерированное изображение  |
|addObject  |Добавить объект OLE  |
|addPreserveText  |Добавить поле (например, нумерацию страниц)  |
Как вы уже, наверное, догадались, параметр **$rowHeight** - позволяет задать высоту в твипсах создаваемой строки, **$cellWidth** - ширину ячейки (столбца), а **$cellStyle** - изменить форматирование ячейки. При форматировании ячейки поддерживаются следующие параметры:
^  Параметр  ^  Описание  ^
|valign  |Выравнивание в ячейке по-вертикали: both - по-вертикали по ширине,\\ top - по верхнему краю,\\ bottom - по нижнему краю,\\ center - по-центру |
|textDirection  |Направление текста из набора констант PHPWord_Style_Cell:\\ TEXT_DIR_BTLR - развернут на 90 градусов против часовой стрелки,\\ TEXT_DIR_TBRL - развернут на 90 градусов по часовой стрелке  |
|bgColor  |Цвет фона ячейки в шестнадцатеричном формате  |
|borderTopSize  |Толщина верхней границы ячейки в твипсах  |
|borderRightSize  |Толщина правой границы ячейки в твипсах  |
|borderBottomSize  |Толщина нижней границы ячейки в твипсах  |
|borderLeftSize  |Толщина левой границы ячейки в твипсах  |
|borderTopColor  |Цвет верхней границы ячейки в шестнадцатеричном формате  |
|borderRightColor  |Цвет правой границы ячейки в шестнадцатеричном формате  |
|borderBottomColor  |Цвет нижней границы ячейки в шестнадцатеричном формате  |
|borderLeftColor  |Цвет левой границы ячейки в шестнадцатеричном формате  |
===== Добавление изображений =====
PHPWord позволяет добавлять в создаваемый документ изображения 2 типов: **из файла** (метод **addImage**) и **динамически сгенерированное сценарием изображение** (метод **addMemoryImage**). Поддерживаются файлы форматов jpg, png, gif, tiff, bmp. Примеры применения методов:
<code php>$section->addImage($src[, $imageStyle]);
$section->addMemoryImage($url[, $imageStyle]);</code>
Здесь **$src** и **$url** - соответственно путь к файлу и  абсолютный путь к сценарию (с адресом сайта и промежуточных каталогов), **$imageStyle** - массив с форматированием изображения. Поддерживаемые параметры форматирования:
^  Параметр  ^  Описание  ^
|width  |Требуемая ширина изображения в пикселях  |
|height  |Требуемая высота изображения в пикселях  |
|align  |Горизонтальное выравнивание изображения:\\ left - по левому краю,\\ right - по правому краю,\\ center - по центру  |
Если требуемые размеры изображения не указаны - библиотека пытается определить фактические размеры изображения при помощи функции [php>getimagesize|getimagesize]].
===== Добавление объектов OLE =====
С помощью метода **addObject** вы можете внедрить в создаваемый документ фрагмент другого документа (*.docx, *.xlsx, *.pptx) при помощи технологии [[wpru>OLE]]:
<code php>$section->addObject($src[, $objectStyle]);</code>
Массив **$objectStyle** может содержать только один параметр:
^  Параметр  ^  Описание  ^
|align  |Выравнивание объекта по-горизонтали:\\ left - по левому краю,\\ right - по правому краю,\\ center - по центру  |
===== Колонтитулы =====
Каждый раздел документа может иметь свой верхний (**header**) и нижний (**footer**) колонтитул, отображаемый на всех принадлежащих ему страницах. С точки зрения Word колонтитул является особым видом раздела, поэтому к колонтитулу применимо большинство описанных выше методов: addText, createTextRun, addTextBreak, addImage, addMemoryImage, addListItem, addTable. Кроме этого колонтитул имеет собственный метод addPreserveText, позволяющий создавать нумерацию страниц. Пример создания верхнего (**createHeader**) и нижнего (**createFooter**) колонтитула:
<code php>//Верхний колонтитул со статическим текстом
$header = $section->createHeader();
$header->addText('Этот документ создан Vania-pooh при помощи PHPWord!');
//Нижний колонтитул с нумерацией страниц посередине
$footer = $section->createFooter();
$footer->addPreserveText('Страница {PAGE} из {NUMPAGES}.', array('bold'=>true),array('align'=>'center'));</code>
Как и всегда форматирование текста колонтитула и абзаца являются необязательными параметрами.
===== Использование шаблонов =====

Библиотека PHPWord поддерживает еще один интересный метод создания документов Word - использование шаблонов. Подробный принцип работы при генерировании документов из шаблонов описан в статье [[:ru:formats:office:docx-templates|docx-templates]]. В качестве метки в PHPWord используется комбинация **${NAME}**, где NAME - имя метки. Пример генерирования с использованием меток:
<code php>
$template = $word->loadTemplate('template.docx'); //Загружаем шаблон
$template->setValue('Name', 'Иванов'); //Производим замену метки на значение
$template->setValue('Surname', 'Иван'); //И еще одну метку
$template->save('document.docx'); //Сохраняем результат в файл

</code>


===== Сохранение файла =====
Для сохранения файла на жесткий диск или вывода его для скачивания пользователю используется метод **save** класса PHPWord_Writer_Word2007. В качестве единственного аргумента метода указывается строка **<nowiki>'php://output'</nowiki>**, если требуется вывести документ для скачивания пользователем или **имя файла**, если документ нужно сохранить на жесткий диск. При выводе файла для скачивания не забудьте отправить браузеру пользователя соответствующие заголовки:
<code php>header('Content-Type: application/vnd.openxmlformats-officedocument.wordprocessingml.document');
header('Content-Disposition: attachment;filename="document.docx"');
header('Cache-Control: max-age=0');
$writer = PHPWord_IOFactory::createWriter($word, 'Word2007');
$writer->save('php://output');</code>
Сохранение файла на жесткий диск:
<code php>
$writer = PHPWord_IOFactory::createWriter($word, 'Word2007');
$writer->save('filename.docx');</code>

===== Пример =====
Подытоживая все вышесказанное хочется привести пример, в котором проиллюстрировано применение большинства возможностей библиотеки PHPWord:

<note important>Текст примера появится несколько позже, когда автор сможет сгенерировать документ с кириллицей (на английском работает). Проблема связана с функцией [[php>utf8_encode]], используемой в PHPWord. Если у вас есть решение этой проблемы, просьба отписаться.</note>

<note important>Update! Проблема с функцией [[php>utf8_encode]] и кириллической кодировкой решается если заменить функцию на [[php>iconv]] и указать входящую кодировку CP1251 и выходе UTF8. Сделать это надо во всех местах библиотеки где используется функция [[php>utf8_encode]].</note>

Данный пример в работе можно посмотреть по [[example>phpword| этой ссылке]]. В заключение хотелось бы отметить, что для сайтов, где структура docx-файла слабо((То есть в худшем случае существует конечное число возможных видов генерируемого документа, а в лучшем случае все документы выглядят одинаково, меняются только пользовательские данные.)) зависит от входных данных, рекомендуемым способом стоит считать [[ru:formats:office:docx-templates]], поскольку:
  * Механизм шаблонов должен работать быстрее, так как основная структура документа уже создана до выполнения сценария((Но я не проверял так ли это на самом деле))
  * Можно создавать документы любой сложности. Библиотека же всегда будет иметь ограничения.
  * Шаблон может быть создан в самой свежей версии Microsoft Word и будет учитывать все возможные изменения внесенные создателями программы
  * В случае, если в зависимости от исходных данных документ может иметь несколько разных представлений, можно создать ровно такое же число разных шаблонов