Source of file api.docx.php
Size: 16,768 Bytes - Last Modified: 2024-04-27T15:26:05+03:00
/tmp/current_snapshot/api/libs/api.docx.php
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433 | <?php /** * DOCXTemplate class 0.1.10 * * @author sergey.shuchkin@gmail.com */ /** * Replace {var} in MS Word 2007+ documents (*.docx) */ class DOCXTemplate { private $data; private $package; private $error; public function __construct($template_filename, $is_data = false, $debug = false) { $this->data = array(); $this->error = false; $this->debug = $debug; $this->_unzip($template_filename, $is_data); } public function set($var, $value = NULL) { if (is_array($var) || is_object($var)) { foreach ($var as $k => $v) $this->data[$k] = $v; } else { $this->data[$var] = $value; } } public function error($set = false) { if ($set) { $this->error = $set; if ($this->debug) trigger_error(__CLASS__ . ': ' . $set, E_USER_WARNING); } else { return $this->error; } } public function success() { return !$this->error; } private function _parse() { if ($doc = $this->getEntryData('word/document.xml')) { if (preg_match_all('/\{[^}]+\}/', $doc, $m)) { foreach ($m[0] as $v) { $var = preg_replace('/[\s\{\}]/', '', strip_tags($v)); if (isset($this->data[$var])) { if (is_scalar($this->data[$var])) $doc = str_replace($v, $this->_esc($this->data[$var]), $doc); } else { $doc = str_replace($v, '{!404_' . __CLASS__ . '_' . $var . '}', $doc); } } } $this->setEntryData('word/document.xml', $doc); return true; } else return false; } private function _unzip($filename, $is_data = false) { // Clear current file $this->datasec = array(); if ($is_data) { $this->package['filename'] = 'default.xlsx'; $this->package['mtime'] = time(); $this->package['size'] = strlen($filename); $vZ = $filename; } else { if (!is_readable($filename)) { $this->error('File not found'); return false; } // Package information $this->package['filename'] = $filename; $this->package['mtime'] = filemtime($filename); $this->package['size'] = filesize($filename); // Read file $oF = fopen($filename, 'rb'); $vZ = fread($oF, $this->package['size']); fclose($oF); } // Cut end of central directory /* $aE = explode("\x50\x4b\x05\x06", $vZ); if (count($aE) == 1) { $this->error('Unknown format'); return false; } */ if (($pcd = strrpos($vZ, "\x50\x4b\x05\x06")) === false) { $this->error('Unknown format'); return false; } $aE = array( 0 => substr($vZ, 0, $pcd), 1 => substr($vZ, $pcd + 3) ); // Normal way $aP = unpack('x16/v1CL', $aE[1]); $this->package['comment'] = substr($aE[1], 18, $aP['CL']); // Translates end of line from other operating systems $this->package['comment'] = strtr($this->package['comment'], array("\r\n" => "\n", "\r" => "\n")); // Cut the entries from the central directory $aE = explode("\x50\x4b\x01\x02", $vZ); // Explode to each part $aE = explode("\x50\x4b\x03\x04", $aE[0]); // Shift out spanning signature or empty entry array_shift($aE); // Loop through the entries foreach ($aE as $vZ) { $aI = array(); $aI['E'] = 0; $aI['EM'] = ''; // Retrieving local file header information // $aP = unpack('v1VN/v1GPF/v1CM/v1FT/v1FD/V1CRC/V1CS/V1UCS/v1FNL', $vZ); $aP = unpack('v1VN/v1GPF/v1CM/v1FT/v1FD/V1CRC/V1CS/V1UCS/v1FNL/v1EFL', $vZ); // Check if data is encrypted // $bE = ($aP['GPF'] && 0x0001) ? TRUE : FALSE; $bE = false; $nF = $aP['FNL']; $mF = $aP['EFL']; // Special case : value block after the compressed data if ($aP['GPF'] & 0x0008) { $aP1 = unpack('V1CRC/V1CS/V1UCS', substr($vZ, -12)); $aP['CRC'] = $aP1['CRC']; $aP['CS'] = $aP1['CS']; $aP['UCS'] = $aP1['UCS']; // 2013-08-10 $vZ = substr($vZ, 0, -12); if (substr($vZ, -4) === "\x50\x4b\x07\x08") $vZ = substr($vZ, 0, -4); } // Getting stored filename $aI['N'] = substr($vZ, 26, $nF); if (substr($aI['N'], -1) == '/') { // is a directory entry - will be skipped continue; } // Truncate full filename in path and filename $aI['P'] = dirname($aI['N']); $aI['P'] = $aI['P'] == '.' ? '' : $aI['P']; $aI['N'] = basename($aI['N']); $vZ = substr($vZ, 26 + $nF + $mF); if (strlen($vZ) != $aP['CS']) { // check only if availabled $aI['E'] = 1; $aI['EM'] = 'Compressed size is not equal with the value in header information.'; } else { if ($bE) { $aI['E'] = 5; $aI['EM'] = 'File is encrypted, which is not supported from this class.'; } else { switch ($aP['CM']) { case 0: // Stored // Here is nothing to do, the file ist flat. break; case 8: // Deflated $vZ = gzinflate($vZ); break; case 12: // BZIP2 if (!extension_loaded('bz2')) { if (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN') { @dl('php_bz2.dll'); } else { @dl('bz2.so'); } } if (extension_loaded('bz2')) { $vZ = bzdecompress($vZ); } else { $aI['E'] = 7; $aI['EM'] = "PHP BZIP2 extension not available."; } break; default: $aI['E'] = 6; $aI['EM'] = "De-/Compression method {$aP['CM']} is not supported."; } if (!$aI['E']) { if ($vZ === FALSE) { $aI['E'] = 2; $aI['EM'] = 'Decompression of data failed.'; } else { if (strlen($vZ) != $aP['UCS']) { $aI['E'] = 3; $aI['EM'] = 'Uncompressed size is not equal with the value in header information.'; } else { if (crc32($vZ) != $aP['CRC']) { $aI['E'] = 4; $aI['EM'] = 'CRC32 checksum is not equal with the value in header information.'; } } } } } } $aI['D'] = $vZ; // DOS to UNIX timestamp $aI['T'] = mktime(($aP['FT'] & 0xf800) >> 11, ($aP['FT'] & 0x07e0) >> 5, ($aP['FT'] & 0x001f) << 1, ($aP['FD'] & 0x01e0) >> 5, ($aP['FD'] & 0x001f), (($aP['FD'] & 0xfe00) >> 9) + 1980); //$this->Entries[] = &new SimpleUnzipEntry($aI); $this->package['entries'][] = array( 'data' => $aI['D'], 'error' => $aI['E'], 'error_msg' => $aI['EM'], 'name' => $aI['N'], 'path' => $aI['P'], 'time' => $aI['T'] ); } // end for each entries } public function getPackage() { return $this->package; } public function entryExists($name) { // 0.6.6 $dir = dirname($name); $name = basename($name); foreach ($this->package['entries'] as $entry) if ($entry['path'] == $dir && $entry['name'] == $name) return true; return false; } public function getEntryData($name) { $dir = dirname($name); $name = basename($name); foreach ($this->package['entries'] as $entry) if ($entry['path'] == $dir && $entry['name'] == $name) return $entry['data']; $this->error('Unknown format'); return false; } public function setEntryData($name, $data) { $dir = dirname($name); $name = basename($name); foreach ($this->package['entries'] as $k => $entry) if ($entry['path'] == $dir && $entry['name'] == $name) { $this->package['entries'][$k]['data'] = $data; return; } return false; } private function _esc($s) { $s = str_replace(array('&', '"', "'", "<", ">"), array('&', '"', ''', '<', '>'), $s); $s = str_replace(array("\r\n", "\r"), "\n", $s); $s = str_replace("\n", '</w:t><w:br/><w:t>', $s); return $s; } private function _zip($fh) { $zipSignature = "\x50\x4b\x03\x04"; // local file header signature $dirSignature = "\x50\x4b\x01\x02"; // central dir header signature $dirSignatureE = "\x50\x4b\x05\x06"; // end of central dir signature $zipComments = 'Generated by ' . __CLASS__ . ' PHP class, thanks Sergey Shuchkin'; // $fh = fopen( $filename, 'wb' ); if (!$fh) return false; $cdrec = ''; foreach ($this->package['entries'] as $e) { $cfilename = ($e['path']) ? $e['path'] . '/' . $e['name'] : $e['name']; $e['uncsize'] = strlen($e['data']); // if data to compress is too small, just store it if ($e['uncsize'] < 256) { $e['comsize'] = $e['uncsize']; $e['vneeded'] = 10; $e['cmethod'] = 0; $zdata = $e['data']; } else { // otherwise, compress it $zdata = gzcompress($e['data']); $zdata = substr(substr($zdata, 0, strlen($zdata) - 4), 2); // fix crc bug (thanks to Eric Mueller) $e['comsize'] = strlen($zdata); $e['vneeded'] = 10; $e['cmethod'] = 8; } $e['bitflag'] = 0; $e['crc_32'] = crc32($e['data']); // Convert date and time to DOS Format, and set then $lastmod_timeS = str_pad(decbin(date('s') >= 32 ? date('s') - 32 : date('s')), 5, '0', STR_PAD_LEFT); $lastmod_timeM = str_pad(decbin(date('i')), 6, '0', STR_PAD_LEFT); $lastmod_timeH = str_pad(decbin(date('H')), 5, '0', STR_PAD_LEFT); $lastmod_dateD = str_pad(decbin(date('d')), 5, '0', STR_PAD_LEFT); $lastmod_dateM = str_pad(decbin(date('m')), 4, '0', STR_PAD_LEFT); $lastmod_dateY = str_pad(decbin(date('Y') - 1980), 7, '0', STR_PAD_LEFT); # echo "ModTime: $lastmod_timeS-$lastmod_timeM-$lastmod_timeH (".date("s H H").")\n"; # echo "ModDate: $lastmod_dateD-$lastmod_dateM-$lastmod_dateY (".date("d m Y").")\n"; $e['modtime'] = bindec("$lastmod_timeH$lastmod_timeM$lastmod_timeS"); $e['moddate'] = bindec("$lastmod_dateY$lastmod_dateM$lastmod_dateD"); $e['offset'] = ftell($fh); fwrite($fh, $zipSignature); fwrite($fh, pack('s', $e['vneeded'])); // version_needed fwrite($fh, pack('s', $e['bitflag'])); // general_bit_flag fwrite($fh, pack('s', $e['cmethod'])); // compression_method fwrite($fh, pack('s', $e['modtime'])); // lastmod_time fwrite($fh, pack('s', $e['moddate'])); // lastmod_date fwrite($fh, pack('V', $e['crc_32'])); // crc-32 fwrite($fh, pack('I', $e['comsize'])); // compressed_size fwrite($fh, pack('I', $e['uncsize'])); // uncompressed_size fwrite($fh, pack('s', strlen($cfilename))); // file_name_length fwrite($fh, pack('s', 0)); // extra_field_length fwrite($fh, $cfilename); // file_name // ignoring extra_field fwrite($fh, $zdata); // Append it to central dir $e['external_attributes'] = (substr($cfilename, -1) == '/' && !$zdata) ? 16 : 32; // Directory or file name $e['comments'] = ''; $cdrec .= $dirSignature; $cdrec .= "\x0\x0"; // version made by $cdrec .= pack('v', $e['vneeded']); // version needed to extract $cdrec .= "\x0\x0"; // general bit flag $cdrec .= pack('v', $e['cmethod']); // compression method $cdrec .= pack('v', $e['modtime']); // lastmod time $cdrec .= pack('v', $e['moddate']); // lastmod date $cdrec .= pack('V', $e['crc_32']); // crc32 $cdrec .= pack('V', $e['comsize']); // compressed filesize $cdrec .= pack('V', $e['uncsize']); // uncompressed filesize $cdrec .= pack('v', strlen($cfilename)); // file name length $cdrec .= pack('v', 0); // extra field length $cdrec .= pack('v', strlen($e['comments'])); // file comment length $cdrec .= pack('v', 0); // disk number start $cdrec .= pack('v', 0); // internal file attributes $cdrec .= pack('V', $e['external_attributes']); // internal file attributes $cdrec .= pack('V', $e['offset']); // relative offset of local header $cdrec .= $cfilename; $cdrec .= $e['comments']; } $before_cd = ftell($fh); fwrite($fh, $cdrec); // end of central dir fwrite($fh, $dirSignatureE); fwrite($fh, pack('v', 0)); // number of this disk fwrite($fh, pack('v', 0)); // number of the disk with the start of the central directory fwrite($fh, pack('v', count($this->package['entries']))); // total # of entries "on this disk" fwrite($fh, pack('v', count($this->package['entries']))); // total # of entries overall fwrite($fh, pack('V', strlen($cdrec))); // size of central dir fwrite($fh, pack('V', $before_cd)); // offset to start of central dir fwrite($fh, pack('v', strlen($zipComments))); // .zip file comment length fwrite($fh, $zipComments); return true; } function saveAs($filename) { if (!$this->_parse()) return false; $fh = fopen($filename, 'wb'); if (!$fh) return false; if (!$this->_zip($fh)) { fclose($fh); return false; } fclose($fh); return true; } function downloadAs($filename, $exit = true) { if (!$this->_parse()) return false; //php://stdin $fh = tmpfile(); if (!$fh) return false; if (!$this->_zip($fh)) { fclose($fh); return false; } $size = ftell($fh); $filename = ($filename) ? $filename : gmdate('Ymdhi'); header('Content-type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'); header('Content-Disposition: attachment; filename="' . $filename . '"'); header('Last-Modified: ' . gmdate('D, d M Y H:i:s \G\M\T', time())); header('Content-Length: ' . $size); fseek($fh, 0); echo fread($fh, $size); fclose($fh); if ($exit) exit(); return true; } } ?> |