Замена текста в файле RTF средствами php
Эта статья о способах шаблонизации RTF документов, попросту говоря, замене текста в документе. Например, в бланк накладной или договора нужно подставить название организации и другие реквизиты. Так же будет небольшой обзор RTF формата и самых нужных(в рамках поставленной задачи) способах форматирования текста + работа с различными кодировками. В конце статьи будет полный пример следующего: будет браться RTF бланк, налету будут меняться некоторые данные, и сразу измененный файл будет отдаваться в браузер клиенту.
Немного теории не помешает.
Rich Text Format (англ. rich — богатый) — формат для кодирования текста и графики. Формат создан в далеком 1982 году компаний Microsoft. Rtf оказвается тоже Билл Гейтс придумал:). Это открытый формат, в отличии от doc и docx. Открыв rtf документ в блокноте, вы не увидите ни одного бинарного (непечатного) символа. Такой формат читается на различных, платформах и осях. И все вроде в нем хорошо, и полная обратная совместимость со старыми версиями Word(и пр.), и кроссплатформенность, но есть один недостаток. Т.к. вся информация хранится в обычном текстовом виде, в том числе служебная, файл получается слишком раздутым по объему. Большие по объему данные хранить в этом формате грешновато(для сравнения docx, это по сути zip-архив). Но для небольших по объему документов: бланков, накладных, договоров, это совсем не критично.
Откройте тот же ворд, напечатайте любое слово сохраните в rtf и потом посмотрите в блокноте сколько всякого-разного там понатыкано(не даром формат назван богатым:)). Надеюсь понятно, что это не обычный текстовой формат, в этом формате можно хранить форматированный текст, картинки, таблицы, формулы и прочее
Создание и редактирование.
Итак, приступим. Для создания rtf документов, есть отлично документированный класс PHPRtfLite, всем кому нужно создавать с нуля rtf документы, вам туда. Все же приведу небольшой кусок кода, который создает rtf документ. Так сказать, необходимый минимум.
$sData = '{\rtf1\ansi\deff HELLO WORLD}'; file_put_contents('test-file.rtf', $sData);
Поставленная цель все же другая, а именно шаблонизация документа, замена текста. Если нужна замена только на английские слова, то никаких проблем быть не должно.
Вот простой пример кода, который, это делает:
$sData = file_get_contents('source.rtf'); $sData = str_replace('COMPANYNAME', 'My Company', $sData); file_put_contents('result.rtf', $sData);
Слово, которое нужно заменить писать именно в таком виде, одним словом, без всяких там {{COMPANYNAME}} или [[COMPANYNAME]] или COMPANY_NAME. Так работать не будет, дело в том , что такие конструкции не хранятся в виде одного слова, а в виде нескольких конструкций вперемешку с управляющими символами.
Если же нужно производить замену на слова любого другого языка, например русского, то нельзя просто вот так вписать символы в файл. Есть 2 момента. Первый, дело в том что rtf формат понимает только ANSI кодировку(для кириллицы это window-1251), соответственно нужно привести символы в эту кодировку(если это не так) и второй каждый символ нужно вписывать в виде его кода в шестнадцатеричной системе. Например, слово ‘Мир’ должно будет записано в виде \'cc\'e8\'f0
СС – это число 204 в шестнадцатеричной системе, а 204 – это код символа M в таблице символов window-1251. Символы должны разделяться слешем и кавычкой. Благо написана функция, которая будет все преобразования делать самостоятельно:
function strToHexByRtf($sString, $sEncoding = 'utf-8') { $sString = iconv($sEncoding, 'windows-1251', $sString); $sString = preg_replace("/([a-zA-Z0-9]{2})/", "\'$1", bin2hex($sString)); return $sString; }
Если заведомо известно, что текст в 'windows-1251', то первую строку в функции можно удалить. Итак, пример кода замены для кириллицы:
function strToHexByRtf($sString, $sEncoding = 'utf-8') { $sString = iconv($sEncoding, 'windows-1251', $sString); $sString = preg_replace("/([a-zA-Z0-9]{2})/", "\'$1", bin2hex($sString)); return $sString; } $sData = file_get_contents('source.rtf'); $sReplace = strToHexByRtf('Моя компания'); $sData = str_replace('COMPANYNAME', $sReplace, $sData); file_put_contents('result.rtf', $sData);
Вот собственно и все. Остается только выдать пользователю видоизмененные данные виде файла, прямо в браузер.
В итоге получилось
Итак, полный код:
function strToHexByRtf($sString, $sEncoding = 'utf-8') { $sString = iconv($sEncoding, 'windows-1251', $sString); $sString = preg_replace("/([a-zA-Z0-9]{2})/", "\'$1", bin2hex($sString)); return $sString; } // считываем файл $sFileName = 'source.rtf'; $sData = file_get_contents($sFileName); // меняем текст $sReplase = strToHexByRtf('Моя компания'); $sData = str_replace('COMPANYNAME', $sReplase, $sData); // отдаем измененный файл пользователю прямо в браузер header('Content-Description: File Transfer'); header('Content-Type: application/octet-stream'); header('Content-Disposition: attachment; filename=' . basename($sFileName)); header('Content-Transfer-Encoding: binary'); header('Expires: 0'); header('Cache-Control: must-revalidate'); header('Pragma: public'); header('Content-Length: ' . strlen($sData)); print $sData;
На этом основная часть статьи окончена. Осталось сказать пару слов о форматировании текста в формате rtf. Скорей всего будет нужен перенос строк и выделение текста жирным шрифтом.
Перенос строки, пример: $sReplace = '{ some text \par}';
'\par' и есть перенос строки(от параграф)
Выделение жирным шрифтом, пример: $sReplase = '{\b email:} {\b0 some@email.com}'
Слово email будет выделено жирным шрифтом.
Еще одно занятное наблюдение. LibreOffice криво сохраняет rtf формат, баг был отловлен на ОС Ubuntu. Я просто открыл doc документ и сохранил в формате rtf. При попытке открытия сохраненного(им же) документа LibreOffice выдал ошибку: "Ошибка формата файла в позиции..." или "File format error found at ..." Версия LibreOffice 4.0.2.2, Ubuntu 13.04 Если открыть в том-же netbeans, то видно, что в rtf документе не парное кол-во фигурных скобок. Дивно. Так-что, не юзайте LibreOffice для преобразования формата. В OpenOffice 3.3 под Windows 7 баг не повторился, нормально сохранило в rtf формате.
Спасибо за внимание. Вопросы, жалобы, предложения оставляйте в коментах или пишите на gubarevm@mail.ru. Удачи.



