Есть у меня сервер с PHP 7.1. Есть задание сгенерировать файл docx на основе шаблона docx.
То есть имеется файл template.php, где в нужных местах есть "переменные" вида ${name}$. Мне нужно их заменить на значения из БД.
О PHPWordЗнаю что есть библиотека PHPWord, но во-первых хочется обойтись без нее, так как эта задача, как мне кажется не заслуживает подключения целой библиотеки для решения. Во-вторых он какой-то мудреный, и, думаю, в итоге потрачу больше времени на изучение возможностей библиотеки.
В общем что я пытаюсь сделать:
1) Распаковываю docx через ZipArchive во временную директорию.
$temp_file_folder = $_SERVER["DOCUMENT_ROOT"].'/test/temp_docx/';
$res_file = $_SERVER["DOCUMENT_ROOT"].'/test/test.docx';
$zip = new ZipArchive;
if ($zip->open($TemplatePath) === TRUE) {
$zip->extractTo($temp_file_folder);
$zip->close();
echo 'готово';
} else {
echo 'ошибка';
}
2) Произвожу замену по шаблону
$temp_file_path = $temp_file_folder.'word/document.xml'; // В этом файле хранится весь текст докх файла
$temp_file_text = file_get_contents($temp_file_path, true); // В этой строке храню содержимое файла
$xml = explode('${', $temp_file_text); // т.к. "заглушки" отделены символами ${ и }$
foreach($xml as $key=>$mini_xml)
{
$current_mini = explode('}$', $mini_xml); // т.к. "заглушки" отделены символами ${ и }$
if( array_key_exists(strip_tags($current_mini[0]), $FieldTemplates) ) // $FieldTemplates содержит список соответствия названий заглушек с названиями записей в БД
{
$keyer = $FieldTemplates[strip_tags($current_mini[0])];
$Values = $Templates[$keyer]; // $Templates содержит значения записей из БД по ключу, полученному из $FieldTemplates
if($Values)
{
$real_mini = str_replace(strip_tags($current_mini[0]), $Values, $current_mini); // Таким образом пытаюсь сохранить структуру узлов docx файла, заменив только текст, который мне нужен
$temp_file_text = str_replace($current_mini[0], $real_mini[0], $temp_file_text); // Заменяю все, что между символами ${ и }$ на аналогичную строку, но с замененными переменными
}
else
{
pre('NO VALUES!! :'.$keyer); // Если в БД нет записи по конкретному полю
}
}
}
3) Убираю лишнее
$temp_file_text = str_replace('${', '', $temp_file_text); // Сразу заменять заглушки на инфу из БД не получается, так как ворд странно разбивает символы. Там структура типа такой <w:t>${</w:t> .... <w:t>name</w:t>
$temp_file_text = str_replace('}$', '', $temp_file_text);
4) Перезаписываем файл document.xml и запаковываю архив (docx)
file_put_contents($temp_file_path, $temp_file_text);
$zip = new ZipArchive();
$zip->open($res_file, ZipArchive::CREATE | ZipArchive::OVERWRITE);
$files = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($temp_file_folder),
RecursiveIteratorIterator::LEAVES_ONLY
);
foreach ($files as $name => $file)
{
if (!$file->isDir())
{
$filePath = $file->getRealPath();
$relativePath = substr($filePath, strlen($temp_file_folder));
$zip->addFile($filePath, $relativePath);
}
}
$zip->close();
Некоторые файлы нормально сохраняются, но по некоторым шаблонам все идет не по плану. Пробую открыть получившийся файл, пишет, что ошибка и не получается открыть файл, мол проблема в 0-м символе 17-й строки. Это никак не помогло, потому что во-первых что еще за 0-й символ? Во-вторых почти весь файл в одну строку записан. Но через бьютифайер если отформатировать document.xml, то на ошибку ругается уже на другой строке, и можно сделать вывод, что проблема похоже во вставляемой таблице. Которая сделана следующим образом (кто-то это написал кучу лет назад):
$index = 1;
$content = false;
$all = 0;
$db_sched = CIBlockElement::Getlist(
array("PROPERTY_DATE" => 'ASC'),
array('IBLOCK_ID' => 32, "PROPERTY_CONTRACT_ID" => $Templates['ID'], 'ACTIVE' => 'Y'),
false,
false,
array('PROPERTY_DATE', 'PROPERTY_SUMM')
);
while($ar_sched = $db_sched->Fetch())
{
if($index == 1)
{
$Templates['PROPERTY_FIRST_PAYMENT'] = number_format($ar_sched['PROPERTY_SUMM_VALUE'], 2, '.', '');
$Templates['PROPERTY_FIRST_PAYMENT_LANG'] = Number2Word_Rus($Templates['PROPERTY_FIRST_PAYMENT'], 'N', 'RUB');
$Templates['PROPERTY_FIRST_PAYMENT_CNT'] = substr($Templates['PROPERTY_FIRST_PAYMENT'], strpos($Templates['PROPERTY_FIRST_PAYMENT'], ".") + 1, 2).'/100';
$Templates['PROPERTY_FIRST_PAYMENT'] = number_format($Templates['PROPERTY_FIRST_PAYMENT'], 2, ',', ' ');
$Templates['PROPERTY_FIRST_DATE_PAYMENT'] = $ar_sched['PROPERTY_DATE_VALUE'];
}
$Templates['PROPERTY_LAST_NUMBER_PAYMENT'] = $index;
$currency = preg_match('[A-Z]', $product['PROPERTY_CURRENCY']) ? $product['PROPERTY_CURRENCY'] : 'RUB'; //set default currency (REQUIRED FOR CurrencyFormat() FUNCTION!)
$content .= '<w:tr w:rsidR="00375458" w:rsidTr="00375458">
<w:tc>
<w:p w:rsidR="00375458" w:rsidRPr="00967154" w:rsidRDefault="00967154"><w:pPr><w:rPr><w:lang w:val="en-US"/></w:rPr></w:pPr><w:r><w:rPr><w:sz w:val="19"/><w:szCs w:val="19"/><w:lang w:val="en-US"/></w:rPr><w:t>'.$index.'.</w:t></w:r></w:p></w:tc>
<w:tc>
<w:p w:rsidR="00375458" w:rsidRPr="00967154" w:rsidRDefault="00967154"><w:pPr><w:jc w:val="center"/><w:rPr><w:lang w:val="en-US"/></w:rPr></w:pPr><w:r><w:rPr><w:sz w:val="19"/><w:szCs w:val="19"/><w:lang w:val="en-US"/></w:rPr><w:t>'.$ar_sched['PROPERTY_DATE_VALUE'].'</w:t></w:r></w:p></w:tc>
<w:tc>
<w:p w:rsidR="00375458" w:rsidRPr="00967154" w:rsidRDefault="00967154"><w:pPr><w:jc w:val="center"/><w:rPr><w:lang w:val="en-US"/></w:rPr></w:pPr><w:r><w:rPr><w:sz w:val="19"/><w:szCs w:val="19"/><w:lang w:val="en-US"/></w:rPr><w:t>'.number_format($ar_sched['PROPERTY_SUMM_VALUE'], 2, ',', ' ').'</w:t></w:r></w:p></w:tc>
</w:tr>' ;
$index ++;
$all = $all + $ar_sched['PROPERTY_SUMM_VALUE'];
}
$content .= '<w:tr w:rsidR="00375458" w:rsidTr="00375458">
<w:tc>
<w:p w:rsidR="00375458" w:rsidRPr="00967154" w:rsidRDefault="00967154"><w:pPr><w:rPr><w:lang w:val="en-US"/></w:rPr></w:pPr><w:r><w:rPr><w:sz w:val="19"/><w:szCs w:val="19"/><w:lang w:val="en-US"/></w:rPr><w:t></w:t></w:r></w:p></w:tc>
<w:tc>
<w:p w:rsidR="00375458" w:rsidRPr="00967154" w:rsidRDefault="00967154"><w:pPr><w:jc w:val="left"/><w:rPr><w:lang w:val="en-US"/></w:rPr></w:pPr><w:r><w:rPr><w:sz w:val="19"/><w:szCs w:val="19"/><w:lang w:val="en-US"/><w:b/></w:rPr><w:t>Итого:</w:t></w:r></w:p></w:tc>
<w:tc>
<w:p w:rsidR="00375458" w:rsidRPr="00967154" w:rsidRDefault="00967154"><w:pPr><w:jc w:val="center"/><w:rPr><w:lang w:val="en-US"/></w:rPr></w:pPr><w:r><w:rPr><w:sz w:val="19"/><w:szCs w:val="19"/><w:lang w:val="en-US"/></w:rPr><w:t>'.number_format($all, 2, ',', ' ').'</w:t></w:r></w:p></w:tc>
</w:tr>' ;