3 +--------------------------------------------------------------------+
4 | CiviCRM version 4.7 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2017 |
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
10 | CiviCRM is free software; you can copy, modify, and distribute it |
11 | under the terms of the GNU Affero General Public License |
12 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
14 | CiviCRM is distributed in the hope that it will be useful, but |
15 | WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
17 | See the GNU Affero General Public License for more details. |
19 | You should have received a copy of the GNU Affero General Public |
20 | License and the CiviCRM Licensing Exception along |
21 | with this program; if not, contact CiviCRM LLC |
22 | at info[AT]civicrm[DOT]org. If you have questions about the |
23 | GNU Affero General Public License or the licensing of CiviCRM, |
24 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
25 +--------------------------------------------------------------------+
31 * @copyright CiviCRM LLC (c) 2004-2017
34 require_once 'TbsZip/tbszip.php';
37 * Class CRM_Utils_PDF_Document.
39 class CRM_Utils_PDF_Document
{
41 public static $ooxmlMap = array(
43 'dataFile' => 'word/document.xml',
44 'startTag' => '<w:body>',
45 'pageBreak' => '<w:p><w:pPr><w:pStyle w:val="Normal"/><w:rPr></w:rPr></w:pPr><w:r><w:rPr></w:rPr></w:r><w:r><w:br w:type="page"/></w:r></w:p>',
46 'endTag' => '</w:body></w:document>',
49 'dataFile' => 'content.xml',
50 'startTag' => '<office:body>',
51 'pageBreak' => '<text:p text:style-name="Standard"></text:p>',
52 'endTag' => '</office:body></office:document-content>',
57 * Convert html to a Doc file.
60 * @param string $fileName
61 * @param array|int $format
63 public static function html2doc($pages, $fileName, $format = array()) {
64 if (is_array($format)) {
65 // PDF Page Format parameters passed in - merge with defaults
66 $format +
= CRM_Core_BAO_PdfFormat
::getDefaultValues();
69 // PDF Page Format ID passed in
70 $format = CRM_Core_BAO_PdfFormat
::getById($format);
72 $paperSize = CRM_Core_BAO_PaperSize
::getByName($format['paper_size']);
74 $metric = CRM_Core_BAO_PdfFormat
::getValue('metric', $format);
76 'orientation' => CRM_Core_BAO_PdfFormat
::getValue('orientation', $format),
77 'pageSizeW' => self
::toTwip($paperSize['width'], $paperSize['metric']),
78 'pageSizeH' => self
::toTwip($paperSize['height'], $paperSize['metric']),
79 'marginTop' => self
::toTwip(CRM_Core_BAO_PdfFormat
::getValue('margin_top', $format), $metric),
80 'marginRight' => self
::toTwip(CRM_Core_BAO_PdfFormat
::getValue('margin_right', $format), $metric),
81 'marginBottom' => self
::toTwip(CRM_Core_BAO_PdfFormat
::getValue('margin_bottom', $format), $metric),
82 'marginLeft' => self
::toTwip(CRM_Core_BAO_PdfFormat
::getValue('margin_left', $format), $metric),
85 $ext = pathinfo($fileName, PATHINFO_EXTENSION
);
87 $phpWord = new \PhpOffice\PhpWord\
PhpWord();
89 $phpWord->getDocInfo()
90 ->setCreator(CRM_Core_DAO
::getFieldValue('CRM_Contact_BAO_Contact', CRM_Core_Session
::getLoggedInContactID(), 'display_name'));
92 foreach ((array) $pages as $page => $html) {
93 $section = $phpWord->addSection($pageStyle +
array('breakType' => 'nextPage'));
94 \PhpOffice\PhpWord\Shared\Html
::addHtml($section, $html);
97 self
::printDoc($phpWord, $ext, $fileName);
101 * @param object|string $phpWord
103 * @param string $fileName
105 public static function printDoc($phpWord, $ext, $fileName) {
107 'docx' => 'Word2007',
114 if (realpath($fileName)) {
115 $phpWord = \PhpOffice\PhpWord\IOFactory
::load($fileName, $formats[$ext]);
118 \PhpOffice\PhpWord\Settings
::setOutputEscapingEnabled(TRUE); //CRM-20015
119 $objWriter = \PhpOffice\PhpWord\IOFactory
::createWriter($phpWord, $formats[$ext]);
121 CRM_Utils_System
::setHttpHeader('Content-Type', "application/$ext");
122 CRM_Utils_System
::setHttpHeader('Content-Disposition', 'attachment; filename="' . $fileName . '"');
123 $objWriter->save("php://output");
131 public static function toTwip($value, $metric) {
132 $point = CRM_Utils_PDF_Utils
::convertMetric($value, $metric, 'pt');
133 return \PhpOffice\PhpWord\Shared\Converter
::pointToTwip($point);
137 * @param array $path docx/odt file path
138 * @param string $type File type
141 * Return extracted content of document in HTML and document type
143 public static function docReader($path, $type) {
144 $type = array_search($type, CRM_Core_SelectValues
::documentApplicationType());
145 $fileType = ($type == 'docx') ?
'Word2007' : 'ODText';
147 $phpWord = \PhpOffice\PhpWord\IOFactory
::load($path, $fileType);
148 $phpWordHTML = new \PhpOffice\PhpWord\Writer\
HTML($phpWord);
150 // return the html content for tokenreplacment and eventually used for document download
151 return array($phpWordHTML->getWriterPart('Body')->write(), $type);
155 * Extract content of docx/odt file
157 * @param string $filePath Document file path
158 * @param string $docType File type of document
161 * [string, clsTbsZip]
163 public static function unzipDoc($filePath, $docType) {
164 $dataFile = self
::$ooxmlMap[$docType]['dataFile'];
166 $zip = new clsTbsZip();
167 $zip->Open($filePath);
168 $content = $zip->FileRead($dataFile);
170 return array($content, $zip);
174 * Modify contents of docx/odt file(s) and later merged into one final document
176 * @param string $filePath
178 * @param array $contents
179 * Content of formatted/token-replaced document
180 * @param string $docType
181 * Document type e.g. odt/docx
182 * @param clsTbsZip $zip
184 * @param bool $returnFinalContent
185 * Return the content of file document as a string used in unit test
189 public static function printDocuments($filePath, $contents, $docType, $zip, $returnFinalContent = FALSE) {
190 $dataMap = self
::$ooxmlMap[$docType];
192 $finalContent = $zip->FileRead($dataMap['dataFile']);
194 // token-replaced document contents of each contact will be merged into final document
195 foreach ($contents as $key => $content) {
197 $finalContent = $content;
201 // 1. fetch the start position of document body
202 // 2. later fetch only the body part starting from position $start
203 // 3. replace closing body tag with pageBreak
204 // 4. append the $content to the finalContent
205 $start = strpos($content, $dataMap['startTag']);
206 $content = substr($content, $start);
207 $content = str_replace($dataMap['startTag'], $dataMap['pageBreak'], $content);
208 $finalContent = str_replace($dataMap['endTag'], $content, $finalContent);
211 if ($returnFinalContent) {
212 return $finalContent;
215 // Replace the loaded document file content located at $filePath with $finaContent
216 $zip->FileReplace($dataMap['dataFile'], $finalContent, TBSZIP_STRING
);
218 $fileName = pathinfo($filePath, PATHINFO_FILENAME
) . '.' . $docType;
219 $zip->Flush(TBSZIP_DOWNLOAD
, $fileName);