С помощью LibreOffice я разработал и написал текстовый документ (формат ODT). Теперь я хочу программно найти определенные заполнители и заменить их текстом из базы данных.
Я знаю, что есть некоторые библиотеки ODT для PHP, но поскольку файлы ODT — это просто ZIP-файлы, содержащие XML-файлы (среди прочего), я думаю, что это должно быть возможно с базовым PHP и без каких-либо библиотек, не так ли?
Поэтому я написал короткий скрипт, который распаковывает ODT-файл, изменяет content.xml, а затем снова архивирует папку. Вы можете увидеть полный код ниже.
Хотя я могу распаковать, заменить, заархивировать вручную, это не работает, когда я позволяю приведенному ниже PHP-скрипту выполнять эту работу. LibreOffice сообщит мне, что не может открыть документ и может попытаться восстановить его (что тоже не работает).
Есть ли какие-то особые требования, на которые мне нужно обратить внимание? Нужно ли мне изменять какие-либо метафайлы, кроме content.xml?
if (unzipFolder('Template.odt', 'temp')) {
$source = file_get_contents('temp'.DIRECTORY_SEPARATOR.'content.xml');
$source = str_replace('XXXplaceholder1XXX', 'Example Value #1', $source);
$source = str_replace('XXXplaceholder2XXX', 'Example Value #2', $source);
file_put_contents('temp'.DIRECTORY_SEPARATOR.'content.xml', $source);
zipFolder('temp', 'output/Document.odt');
}
function unzipFolder($zipInputFile, $outputFolder) {
$zip = new ZipArchive;
$res = $zip->open($zipInputFile);
if ($res === true) {
$zip->extractTo($outputFolder);
$zip->close();
return true;
}
else {
return false;
}
}
function zipFolder($inputFolder, $zipOutputFile) {
if (!extension_loaded('zip') || !file_exists($inputFolder)) {
return false;
}
$zip = new ZipArchive();
if (!$zip->open($zipOutputFile, ZIPARCHIVE::CREATE)) {
return false;
}
$inputFolder = str_replace('\\', DIRECTORY_SEPARATOR, realpath($inputFolder));
if (is_dir($inputFolder) === true) {
$files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($inputFolder), RecursiveIteratorIterator::SELF_FIRST);
foreach ($files as $file) {
$file = str_replace('\\', DIRECTORY_SEPARATOR, $file);
if (in_array(substr($file, strrpos($file, '/')+1), array('.', '..'))) {
continue;
}
$file = realpath($file);
if (is_dir($file) === true) {
$dirName = str_replace($inputFolder.DIRECTORY_SEPARATOR, '', $file.DIRECTORY_SEPARATOR);
$zip->addEmptyDir($dirName);
}
else if (is_file($file) === true) {
$fileName = str_replace($inputFolder.DIRECTORY_SEPARATOR, '', $file);
$zip->addFromString($fileName, file_get_contents($file));
}
}
}
else if (is_file($inputFolder) === true) {
$zip->addFromString(basename($inputFolder), file_get_contents($inputFolder));
}
return $zip->close();
}
Правка №1: приведенный выше код не работает даже в том случае, если вы просто разархивируете и повторно заархивируете содержимое файла ODT, т. е. если вы раскомментируете все манипуляции с данными. Что-то не так с форматом вывода PHP ZipArchive?
Правка №2. Точнее, метод zipFolder(...)
все ломает. Вы можете позволить PHP выполнить распаковку, манипуляции со строками также работают нормально (str_replace(...)
), но когда функция zipFolder(...)
создает архив, его нельзя открыть, в то время как он работает нормально, если вы создаете архив вручную (с помощью 7-Zip, например ).
Правка №3: я даже заработал, просто заменив часть повторного архивирования в PHP вызовом 7-Zip через exec(...)
. Таким образом, проблема определенно заключается в создании правильного ZIP-архива. Для лучшей переносимости и меньшего количества зависимостей, было бы лучше, конечно, чтобы решение с PHP'овским ZipArchive
работало и нам не нужен был 7-Zip.
$zip->extractTo('./'.$outputFolder);
, чтобы он извлекал .odt в относительную временную папку. - person CrazySabbath   schedule 19.12.2013.odt
. Выведенный.odt
отлично работает в MS Word, но не открывается в LibreOffice. Однако продукты MS нередко стараются изо всех сил, даже если файл или формат поврежден (подумайте, что старый IE прощает небрежный HTML-код). - person user555   schedule 20.12.2013