Работа с docx стандартными возможностями PHP, почему замена в document.xml не спасает?

Есть у меня сервер с 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>' ;
  • Вопрос задан
  • 724 просмотра
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы