Представляю на всеобщее обозрение результат двухнедельного поиска в интернете соответствующей информации. Передо мной встала следующая задача. Из корпоративной базы данных информацию выдать в виде отчетов в формате MS Word и MS Excel. Ну и конечно отчет выставить в WEB. Механизм выборки данных и публикации в WEB описывать не буду. Очень много информации в инете, да и баз данных море. А вот формирование документов по шаблону - вещь полезная. Почему то нигде не нашел примеров работы с шаблонами. Оговорка. Всё отрабатывалось на Windows Server 2003 + Oracle Apache Server. О Linux-платформе в конце статьи. Итак. Excel. С Excel-ом попроще. Готовим красивый файл. Форматируем внутренности, т.е. готовим ячейки куда будем прописывать данные. Теперь пишем PHP: <?php // Создаем СОМ-объект $excel = new COM("Excel.Application") or die("Unable to instanciate excel"); $excel->Visible = false; $excel->DisplayAlerts = false; // Выводим версию MS Excel echo "I'm using MS Excel {$excel->Version}"; $excel->Application->Visible = 0; $excel->DisplayAlerts = 0; # Открытие сущуствующей проформы $excel->Workbooks->Open("C:\\temp\\example.xls"); // Выбираем активный лист и устанавливаем курсов в область ячейки (1, 1) $sheet = $excel->Worksheets(1); $sheet->activate; $cell = $sheet->Cells(1,1); $cell->Activate; // Записываем в ячейку текст или данные $cell->value = 'Test'; // Сохраняем как новый документ - от туда и выбрасываем в инет $excel->Workbooks[1]->SaveAs("c:\\temp\\New.xls"); // Всё - уходим $excel->Quit(); $excel->Release(); $excel = Null; ?> Примеры форматирования ячеек $change = $excel -> Selection -> Range("A1"); $change -> Font -> Bold = true; $change -> Font -> Italic = true; $change -> Font -> Underline = true; $change -> Font -> Name = "Times New Roman"; $change -> Font -> Size = 12; $change -> Font -> ColorIndex = 3; Про форматирование в конце статьи дам общие рекомендации. Word. Ну а теперь самое интересное. Пока до этого докопался ... Даже в O'Reilly Programming PHP такого не нашел. С Вордовскими шаблонами работа заключается в следующем: а) записать данные в закладку (надеюсь не надо объяснять что такое закладка в Ворде) - использовать что-то типа <FIELD1> и методом поиска и замены не рекомендую - может когда-то такая комбинация встретиться; б) добавить какое-то количество строк в какую-то таблицу в документе (таблиц может быть много, причем как в колонтитулах так и в самом документе); в) записать данные в ячейку таблицы; г) нарисовать в ячейке линию (border) - это для подчеркивания итогов в основном; д) объединить несколько ячеек таблицы - это из практики формирования судовых документов. Поверьте - всё остальное готовится заранее в шаблоне. Ну что? Кто нибудь решал такую задачу? Итак пишем PHP: <?php //создаем новый объект COM – word.application $word = new COM("word.application") or die("Cannot create Word object"); $word->Visible = false; $word->DisplayAlerts = false; // переменная $empty нужна для подстановки // неопределенных переменных в методы VBA $empty = new VARIANT(); // Открытие сущуствующей проформы $template_file = "C:/temp/doc3.doc"; $word->Documents->Open($template_file); // // Пишем в закладку 'test' // естественно в шаблоне такая закладка в нужном // месте должна быть подготовлена $current_date = date("m/d/Y"); $bookmarkname = "test"; $objBookmark = $word->ActiveDocument->Bookmarks($bookmarkname); $range = $objBookmark->Range; $range->Text = $current_date; // // Пишем в ячейку таблицы $objTable = $word->ActiveDocument->Tables(1); $objCell = $objTable->Cell(1,1); $range = $objCell->Range; $range->Text = "cell(1.1)"; // // Рисуем линию ячейки $mySelect = $objCell->Select(); $myBorder = $word->Selection->Borders(-1); $myBorder->LineStyle = 1; // Оговорка - не используйте Borders(wdBorderTop) // Для распознавания Виндовых имен типа wdBorderTop // необходимо подгружать библиотеку //com_load_typelib('Word.Application'); // что в свою очередь инициирует на сервере еще один процесс MS Word // который потом закончить нельзя // числовые эквиваленты таких имен как wdBorderTop // легко найти в справке по VBA в самом Ворде // // Добавляем строки к таблице $word->Selection->GoTo('2',$empty,'2',$empty); $word->Selection->InsertRowsBelow(1); // Самое интересное // Объединяем ячейки $myTable = $word->ActiveDocument->Tables(2); $rangeStart = $myTable->Cell(1,4); $myRangeStart = $rangeStart->Range->Start(); $rangeEnd = $myTable->Cell(2,4); $myRangeEnd = $rangeEnd->Range->End(); $myRange = $word->ActiveDocument->Range($myRangeStart,$myRangeEnd); $myRange->Cells->Merge(); // // Сохраняем документ под новым именем $new_file = "C:/temp/new3.doc"; $word->Documents[1]->SaveAs($new_file); // // Всё - уходим $word->Quit(); $word = null; unset($word); ?> Ну вот и всё. Пользуйтесь. Теперь общие замечания или выводы по интерпретации кода VBA в PHP. Всё очень просто. Оказывается если придерживаться одного правила, то переносить код VBA в PHP очень просто. //////////////////////////////////////////////////////////////////////////////////////////// ПРАВИЛО! Использовать больше двух '->' в одной строке нельзя!!! //////////////////////////////////////////////////////////////////////////////////////////// Пример. Объединение ячеек. Код в VBA: Set myTable = ActiveDocument.Tables(1) If Not IsNull(rstBl!ORDER_NO) Then ActiveDocument.Tables(1).Cell(vCurentRow, 10).Range.Text = rstBl![ORDER_NO].Value Set myRange = ActiveDocument.Range(myTable.Cell(vCurentRow, 10).Range.Start, myTable.Cell((vCurentRow + vMaxRows), 10).Range.End) myRange.Select Selection.Cells.Merge End If Код PHP: // Объединяем ячейки $myTable = $word->ActiveDocument->Tables(2); $rangeStart = $myTable->Cell(1,4); $myRangeStart = $rangeStart->Range->Start(); $rangeEnd = $myTable->Cell(2,4); $myRangeEnd = $rangeEnd->Range->End(); $myRange = $word->ActiveDocument->Range($myRangeStart,$myRangeEnd); $myRange->Cells->Merge(); Как видите - внимательно превращая VBA-точки в PHP-стрелки, можно писать в PHP как в VBA. Теперь про платформу Linux. Конечно с таким решением задачи я сам лично не согласен. Т.е. приходится использовать Виндовый сервак. Нужен движок Ворда и Экселя. Я выбрал решение следующее. Linux, OpenOffice Calc Writer, JavaScript, PHP. Как решу задачу - дополню эту статью. Всем успехов. Письма благодарности жду по адресу n.kostilev@gmail.com
1. Excel - есть готовые классы. порыться надо только. 2. Word. все давно юзают под эту тему RTF формат.
440Hz, ответь на вопрос юного падавана плиз: Вот есть OpenOffice, у него(если я не ошибаюсь) открытые исходники, если выдрать из него процесс конвертации в .doc формат и сделать отдельной программой, это будет очень суровым решением подобной проблемы?
Херня понаписана. И ворд, и эксель понимают html разметку в теле документа. И никаких ком-обьектов не надо.
Просьба не выражаться. А с такими "культурными" общаться желания нету. Про классы - да есть, RTF - можно - а в жизни, когда юзверю всё ни почём и он жалуется руководителю - надо в ворде - попробуй не сделать. Про поиск - попробуй найти хоть один пример. Две недели поиска - ничего реального. Тока запись в голый документ.
с вордом делал только вставку в готовый RTF (RTF открытый формат. можно поизголяться). с екселем классов море. PHP: <?php require_once('../../texdoc.inc'); require_once('../../trash.inc'); require_once('../../../../oops/start.inc'); function xlsBOF() { echo pack("ssssss", 0x809, 0x8, 0x0, 0x10, 0x0, 0x0); return; } // Excel end of file footer function xlsEOF() { echo pack("ss", 0x0A, 0x00); return; } // Function to write a Number (double) into Row, Col function xlsWriteNumber($Row, $Col, $Value) { echo pack("sssss", 0x203, 14, $Row, $Col, 0x0); echo pack("d", $Value); return; } // Function to write a label (text) into Row, Col function xlsWriteLabel($Row, $Col, $Value ) { $L = strlen($Value); echo pack("ssssss", 0x204, 8 + $L, $Row, $Col, 0x0, $L); echo $Value; return; } header ( "Expires: Mon, 1 Apr 1974 05:00:00 GMT" ); header ( "Last-Modified: " . gmdate("D,d M YH:i:s") . " GMT" ); header ( "Cache-Control: no-cache, must-revalidate" ); header ( "Pragma: no-cache" ); header ( "Content-type: application/x-msexcel" ); header ( "Content-Disposition: attachment; filename=order.xls" ); header ( "Content-Description: PHP Generated XLS Data" ); xlsBOF(); xlsWriteLabel(0,0,"Производитель"); xlsWriteLabel(0,1,"Код"); xlsWriteLabel(0,2,"Описание"); xlsWriteLabel(0,3,"Кол-во"); xlsWriteLabel(0,4,"Цена"); xlsWriteLabel(0,5,"Всего"); $DATA = $TT->Getdata(); $TOT = 0; $num = 1; foreach($DATA as $TK => $TV) { xlsWriteLabel ($num,0,$TV->brand); xlsWriteLabel ($num,1,$TV->code); xlsWriteLabel ($num,2,$TV->name); xlsWriteNumber($num,3,$TV->cnt); xlsWriteLabel ($num,4,(number_format($TV->price/100,2,',',''))); xlsWriteLabel ($num,5,(number_format($TV->price/100*$TV->cnt,2)).''); $TOT += $TV->price*$TV->cnt; $num++; } xlsWriteLabel($num,0,'ИТОГО'); xlsWriteLabel($num,5,(number_format($TOT/100,2)).''); xlsEOF(); ?> мне несколько раз предлагали и требовали сделать ворд из инета - я посылал нафиг. сразу.
Если у кого-то есть практический пример решения такой задачи на платформе Linux (Ooo Calc, Ooo Writer, PHP, Java, JavaScript) - просьба поделиться примером.
про ворд не знаю, никогда не приходилось такого делать, а вот про Excel после долгих поисков и разочарований пришел к PHPExcel. Логика там проста: - готовишь документ в памяти при помощи класса PHPExcel. - потом выбираешь один из 5 райтеров, который записывает его в нужный формат или отправляет пользаку- это одной строчкой. или если наоборот надо готовый файл обработать, то - читаешь файл при помощи одного из ридеров в память в PHPExcel, - при помощи методов PHPExcel читаешь его как душе угодно В комплекте есть ридеры и райтеры для Ex 2003, Ex 2007, CSV и Acrobat. Я добавил туда свой PostgresReader, который по SQL-запросу заполняет PHPExcel, а потом я его могу любым райтером выгрузить. И написал небольшой моторчик для работы с шаблонами. Пол года уже не знаю проблем. Главное достоинство- один интерфейс для все работает на *никсах.
объем чего? памяти или документа вот простой примерчик, который иллюстрирует удобства PHPExcel это экселевский файл, который выступает в роли шаблона документов а это документ, который получается после того как над шаблоном немного поработает простенький шаблонизатор в принципе логика работы шаблонизатора понятна из картинок. Фишка тут в том, что все форматирование документа, то есть как он будет выглядеть в итоге производится в самом экселе (просто редактирую а потом сохраняю обычный экселевский файл). А из PHP только наполнение. К примеру, до PHPExcel я пользовался пировским Excel_spreadsheet_writer. Чтобы добиться там такого же форматирования как на картинке нужно было убить целый день. В PHPExcel доступны фильтры, шмильтры, колонтитулы, разметка страницы, положение страницы, метаданные типа автора и описания, блокировки ячеек, именнованые ячейки, которые можно использовать для написания настоящего шаблонизатора на подобии 1С, всплывающие подсказки, графики, картинки любое форматирование текста, фоны, шмоны, границы и все остальное, я уже устал. Еще если не нравится Эксель2007, можно сохранить в PDF. для этого нужно только поменять одну строчку, где выбирается райтер $writer= PHPExcel_IOFactory($excel, 'Excel2007') заменить на $writer= PHPExcel_IOFactory($excel, 'PDF') весь остальной код остается неизменным, потому что документ готовится в памяти и только в последний момент привязывается к какому- то конкретному формату, а все ридеры и райтеры, которые это делают, реализуют один интерфейс и отличаются только реализацией.
просто исходники устроят? а то у меня тут аврал с переводом на AD и на новый интерфейс, да еще одно старое направление возрождать буду. все разом навалилось. если надо примеры и комментарии, то только по-позже, как немного разгребусь.
Хорошо, лучше в качественном виде тогда потом, только не забудь плз, многим будет полезно, мне в том числе
А почему вы не хотите сохранить нужный шаблончик ехел документа в формате хмл с настройками фильтров, цветов, шрифтом и прочего и уже потом из пхп крутить и вертеть его как угодно? чем не вариант... а пользователю передать файл с расширением cls (если не ошибаюсь) и всё будет ровненько)
Тема интересная и важная, но как верно подметил 440Hz, под никсами такая штука не катит. У меня такой вопрос. При генерации дока в RTF, например при открытии в ненависном опенофис проблем не будет? Сталкивался с тем (конечно история другая), что при простой вставке html в doc в опенофисе сюрприз - крякозябры. Вот и вопрос - этот опенофис вообще открывает RTF? если да, то кодировка не должна изменятся специально под этот опенофис?
Исчо такой вопросище - у кого-нить есть скрипт подтим этого: http://www.paggard.com/projects/rtf.generator/demo.php ?
Тоже появилась задача работы с RTF, XLS, PDF или подобными... лучше используя готовые шаблоны. получилось-таки реализовать не на виндах? ;-)