Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- <?php
- /**
- * DOCXTemplate class 0.1.10 by sergey more at http://www.phpclasses.org/package/8247-PHP-Create-Microsoft-Word-documents-from-templates.html#applications
- * Replace {var} in MS Word 2007+ documents (*.docx)
- [test.tpl.docx]
- INVOICE {NUM} Invoice date {COMPANY}
- {DATE}
- <?php // test.php
- include('docxtemplate.class.php');
- $docx = new DOCXTemplate('test.tpl.docx');
- $docx->set('NUM', 123456 );
- $docx->set('DATE', date('m.d.Y'));
- $docx->set('COMPANY', 'SIBVISION.RU
- Russian Federation, Omsk
- phone: +73812590554');
- $docx->saveAs('test.docx'); // or $docx->downloadAs('test.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);
- chmod($filename, 0600);
- 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;
- }
- }
- ?>
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement