diff --git a/.gitignore b/.gitignore index 46c3cd9..1c3d582 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ -vendor* +/vendor* /books.fw.png /datatypes.fw.png /styles.fw.png +/.gitignore diff --git a/CHANGELOG.md b/CHANGELOG.md index 1bd7ec3..07df59b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ # Changelog +## 1.1.10 (2022-02-05) +* namespace added, use Shuchkin\SimpleXLSXGen + ## 1.0.23 (2022-02-01) * fixed dates if year < 1900 and time only cells, thx [fapth](https://github.com/shuchkin/simplexlsxgen/issues/51) diff --git a/README.md b/README.md index 6aeb579..f296a56 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,10 @@ # SimpleXLSXGen [](https://github.com/shuchkin/simplexlsxgen/blob/master/license.md) [](https://github.com/shuchkin/simplexlsxgen/stargazers) [](https://github.com/shuchkin/simplexlsxgen/network) [](https://github.com/shuchkin/simplexlsxgen/issues) -Export data to Excel XLSX file. PHP XLSX generator. No external tools and libraries.
-(!) XLSX reader [here](https://github.com/shuchkin/simplexlsx). +Export data to Excel XLSX file. PHP XLSX generator. No external tools and libraries. +- XLSX reader [here](https://github.com/shuchkin/simplexlsx) +- XLS reader [here](https://github.com/shuchkin/simplexls) +- CSV reader/writer [here](https://github.com/shuchkin/simplecsv) **Sergey Shuchkin** 2020-2021
@@ -15,7 +17,7 @@ $books = [ [618260307, 'The Hobbit', 'J. R. R. Tolkien', 'Houghton Mifflin', 'USA'], [908606664, 'Slinky Malinki', 'Lynley Dodd', 'Mallinson Rendel', 'NZ'] ]; -$xlsx = SimpleXLSXGen::fromArray( $books ); +$xlsx = Shuchkin\SimpleXLSXGen::fromArray( $books ); $xlsx->saveAs('books.xlsx'); // or downloadAs('books.xlsx') or $xlsx_content = (string) $xlsx ``` ![XLSX screenshot](books.png) @@ -46,7 +48,7 @@ $data = [ ['Hyperlink + Anchor', 'SimpleXLSXGen'], ['RAW string', "\0".'2020-10-04 16:02:00'] ]; -SimpleXLSXGen::fromArray( $data )->saveAs('datatypes.xlsx'); +Shuchkin\SimpleXLSXGen::fromArray( $data )->saveAs('datatypes.xlsx'); ``` ![XLSX screenshot](datatypes.png) @@ -66,7 +68,7 @@ $data = [ ['Right', 'Right Text'], ['Center + Bold', '
Name
'] ]; -SimpleXLSXGen::fromArray( $data ) +Shuchkin\SimpleXLSXGen::fromArray( $data ) ->setDefaultFont( 'Courier New' ) ->setDefaultFontSize( 14 ) ->saveAs('styles_and_tags.xlsx'); @@ -76,15 +78,16 @@ SimpleXLSXGen::fromArray( $data ) ### More examples ```php // Fluid interface, output to browser for download -SimpleXLSXGen::fromArray( $books )->downloadAs('table.xlsx'); +Shuchkin\SimpleXLSXGen::fromArray( $books )->downloadAs('table.xlsx'); // Fluid interface, multiple sheets -SimpleXLSXGen::fromArray( $books )->addSheet( $books2 )->download(); +Shuchkin\SimpleXLSXGen::fromArray( $books )->addSheet( $books2 )->download(); // Alternative interface, sheet name, get xlsx content -$xlsx_cache = (string) (new SimpleXLSXGen)->addSheet( $books, 'Modern style'); +$xlsx_cache = (string) (new Shuchkin\SimpleXLSXGen)->addSheet( $books, 'Modern style'); // Classic interface +use Shuchkin\SimpleXLSXGen $xlsx = new SimpleXLSXGen(); $xlsx->addSheet( $books, 'Catalog 2021' ); $xlsx->addSheet( $books2, 'Stephen King catalog'); @@ -101,5 +104,5 @@ $data = [ ['Debug', 123] ]; -SimpleXLSXGen::fromArray( $data )->saveAs('debug.xlsx'); +Shuchkin\SimpleXLSXGen::fromArray( $data )->saveAs('debug.xlsx'); ``` diff --git a/composer.json b/composer.json index 4547ccf..0679aca 100644 --- a/composer.json +++ b/composer.json @@ -17,6 +17,7 @@ ] }, "require": { + "php": ">=5.4", "ext-mbstring": "*", "ext-zlib": "*" } diff --git a/src/SimpleXLSXGen.php b/src/SimpleXLSXGen.php index c574c6e..4851e14 100644 --- a/src/SimpleXLSXGen.php +++ b/src/SimpleXLSXGen.php @@ -1,4 +1,6 @@ curSheet = -1; + $this->defaultFont = 'Calibri'; + $this->sheets = [ ['name' => 'Sheet1', 'rows' => [], 'hyperlinks' => [] ] ]; + $this->SI = []; // sharedStrings index + $this->SI_KEYS = []; // & keys + $this->F = [ self::F_NORMAL ]; // fonts + $this->F_KEYS = [0]; // & keys + $this->XF = [ [self::N_NORMAL, self::F_NORMAL, self::A_DEFAULT] ]; // styles + $this->XF_KEYS = ['N0F0A0' => 0 ]; // & keys - public function __construct() { - $this->curSheet = -1; - $this->defaultFont = 'Calibri'; - $this->sheets = [ ['name' => 'Sheet1', 'rows' => [], 'hyperlinks' => [] ] ]; - $this->SI = []; // sharedStrings index - $this->SI_KEYS = []; // & keys - $this->F = [ self::F_NORMAL ]; // fonts - $this->F_KEYS = [0]; // & keys - $this->XF = [ [self::N_NORMAL, self::F_NORMAL, self::A_DEFAULT] ]; // styles - $this->XF_KEYS = ['N0F0A0' => 0 ]; // & keys - - $this->template = [ - '_rels/.rels' => ' + $this->template = [ + '_rels/.rels' => ' ', - 'docProps/app.xml' => ' + 'docProps/app.xml' => ' 0 '.__CLASS__.'', - 'docProps/core.xml' => ' + 'docProps/core.xml' => ' {DATE} en-US {DATE} 1 ', - 'xl/_rels/workbook.xml.rels' => ' + 'xl/_rels/workbook.xml.rels' => ' {SHEETS}', - 'xl/worksheets/sheet1.xml' => ' + 'xl/worksheets/sheet1.xml' => ' {COLS}{ROWS}{HYPERLINKS}', - 'xl/worksheets/_rels/sheet1.xml.rels' => ' + 'xl/worksheets/_rels/sheet1.xml.rels' => ' {HYPERLINKS}', - 'xl/sharedStrings.xml' => ' + 'xl/sharedStrings.xml' => ' {STRINGS}', - 'xl/styles.xml' => ' + 'xl/styles.xml' => ' {FONTS} @@ -84,15 +85,15 @@ class SimpleXLSXGen { {XF} - + ', - 'xl/workbook.xml' => ' + 'xl/workbook.xml' => ' {SHEETS} ', - '[Content_Types].xml' => ' + '[Content_Types].xml' => ' @@ -103,568 +104,568 @@ class SimpleXLSXGen { {TYPES} ', - ]; + ]; - // - // 01001200 - // Простой шаблонБудем делать генератор - } - public static function fromArray( array $rows, $sheetName = null ) { + // + // 01001200 + // Простой шаблонБудем делать генератор + } + public static function fromArray( array $rows, $sheetName = null ) { return (new static())->addSheet( $rows, $sheetName ); - } + } - public function addSheet( array $rows, $name = null ) { + public function addSheet( array $rows, $name = null ) { - $this->curSheet++; - if ( $name === null ) { // autogenerated sheet names - $name = 'Sheet'.($this->curSheet+1); - } else { - $names = []; - foreach( $this->sheets as $sh ) { - $names[ mb_strtoupper( $sh['name']) ] = 1; - } - for( $i = 0; $i < 100; $i++ ) { - $new_name = ($i === 0) ? $name : $name .' ('.$i.')'; - $NEW_NAME = mb_strtoupper( $new_name ); - if ( !isset( $names[ $NEW_NAME ]) ) { - $name = $new_name; - break; - } - } - } + $this->curSheet++; + if ( $name === null ) { // autogenerated sheet names + $name = 'Sheet'.($this->curSheet+1); + } else { + $names = []; + foreach( $this->sheets as $sh ) { + $names[ mb_strtoupper( $sh['name']) ] = 1; + } + for( $i = 0; $i < 100; $i++ ) { + $new_name = ($i === 0) ? $name : $name .' ('.$i.')'; + $NEW_NAME = mb_strtoupper( $new_name ); + if ( !isset( $names[ $NEW_NAME ]) ) { + $name = $new_name; + break; + } + } + } - $this->sheets[$this->curSheet] = ['name' => $name, 'hyperlinks' => []]; + $this->sheets[$this->curSheet] = ['name' => $name, 'hyperlinks' => []]; - if ( isset( $rows[0] ) && is_array($rows[0]) ) { - $this->sheets[$this->curSheet]['rows'] = $rows; - } else { - $this->sheets[$this->curSheet]['rows'] = []; - } - return $this; - } + if ( isset( $rows[0] ) && is_array($rows[0]) ) { + $this->sheets[$this->curSheet]['rows'] = $rows; + } else { + $this->sheets[$this->curSheet]['rows'] = []; + } + return $this; + } - public function __toString() { - $fh = fopen( 'php://memory', 'wb' ); - if ( ! $fh ) { - return ''; - } + public function __toString() { + $fh = fopen( 'php://memory', 'wb' ); + if ( ! $fh ) { + return ''; + } - if ( ! $this->_write( $fh ) ) { - fclose( $fh ); - return ''; - } - $size = ftell( $fh ); - fseek( $fh, 0); + if ( ! $this->_write( $fh ) ) { + fclose( $fh ); + return ''; + } + $size = ftell( $fh ); + fseek( $fh, 0); - return (string) fread( $fh, $size ); - } + return (string) fread( $fh, $size ); + } - public function saveAs( $filename ) { - $fh = fopen( $filename, 'wb' ); - if (!$fh) { - return false; - } - if ( !$this->_write($fh) ) { - fclose($fh); - return false; - } - fclose($fh); + public function saveAs( $filename ) { + $fh = fopen( $filename, 'wb' ); + if (!$fh) { + return false; + } + if ( !$this->_write($fh) ) { + fclose($fh); + return false; + } + fclose($fh); - return true; - } + return true; + } - public function download() { - return $this->downloadAs( gmdate('YmdHi') . '.xlsx' ); - } + public function download() { + return $this->downloadAs( gmdate('YmdHi') . '.xlsx' ); + } - public function downloadAs( $filename ) { - $fh = fopen('php://memory','wb'); - if (!$fh) { - return false; - } + public function downloadAs( $filename ) { + $fh = fopen('php://memory','wb'); + if (!$fh) { + return false; + } - if ( !$this->_write( $fh )) { - fclose( $fh ); - return false; - } + if ( !$this->_write( $fh )) { + fclose( $fh ); + return false; + } - $size = ftell($fh); + $size = ftell($fh); - 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); + 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); - while( ob_get_level() ) { - ob_end_clean(); - } - fseek($fh,0); - fpassthru( $fh ); + while( ob_get_level() ) { + ob_end_clean(); + } + fseek($fh,0); + fpassthru( $fh ); - fclose($fh); - return true; - } + fclose($fh); + return true; + } - protected function _write( $fh ) { + protected function _write( $fh ) { - $dirSignatureE= "\x50\x4b\x05\x06"; // end of central dir signature - $zipComments = 'Generated by '.__CLASS__.' PHP class, thanks sergey.shuchkin@gmail.com'; + $dirSignatureE= "\x50\x4b\x05\x06"; // end of central dir signature + $zipComments = 'Generated by '.__CLASS__.' PHP class, thanks sergey.shuchkin@gmail.com'; - if (!$fh) { - return false; - } + if (!$fh) { + return false; + } - $cdrec = ''; // central directory content - $entries= 0; // number of zipped files - $cnt_sheets = count( $this->sheets ); + $cdrec = ''; // central directory content + $entries= 0; // number of zipped files + $cnt_sheets = count( $this->sheets ); - foreach ($this->template as $cfilename => $template ) { - if ( $cfilename === 'xl/_rels/workbook.xml.rels' ) { - $s = ''; - for ( $i = 0; $i < $cnt_sheets; $i++) { - $s .= '\n"; - } - $s .= ''; - $template = str_replace('{SHEETS}', $s, $template); - $this->_writeEntry($fh, $cdrec, $cfilename, $template); - $entries++; - } elseif ( $cfilename === 'xl/workbook.xml' ) { - $s = ''; - foreach ( $this->sheets as $k => $v ) { - $s .= ''; - } - $template = str_replace('{SHEETS}', $s, $template); - $this->_writeEntry($fh, $cdrec, $cfilename, $template); - $entries++; - } - elseif ( $cfilename === 'docProps/core.xml' ) { - $template = str_replace('{DATE}', gmdate('Y-m-d\TH:i:s\Z'), $template); - $this->_writeEntry($fh, $cdrec, $cfilename, $template); - $entries++; - } elseif ( $cfilename === 'xl/sharedStrings.xml' ) { - if (!count($this->SI)) { - $this->SI[] = 'No Data'; - } - $si_cnt = count($this->SI); - $si = ''.implode("\r\n", $this->SI).''; - $template = str_replace(['{CNT}', '{STRINGS}'], [ $si_cnt, $si ], $template ); - $this->_writeEntry($fh, $cdrec, $cfilename, $template); - $entries++; - } elseif ( $cfilename === 'xl/worksheets/sheet1.xml' ) { - foreach ( $this->sheets as $k => $v ) { - $filename = 'xl/worksheets/sheet'.($k+1).'.xml'; - $xml = $this->_sheetToXML($k, $template); - $this->_writeEntry($fh, $cdrec, $filename, $xml ); - $entries++; - } - $xml = null; - } elseif ( $cfilename === 'xl/worksheets/_rels/sheet1.xml.rels' ) { - foreach ( $this->sheets as $k => $v ) { - if ( count($v['hyperlinks'])) { - $RH = []; - $filename = 'xl/worksheets/_rels/sheet' . ( $k + 1 ) . '.xml.rels'; - foreach ( $v['hyperlinks'] as $h ) { - $RH[] = ''; - } - $xml = str_replace( '{HYPERLINKS}', implode( "\r\n", $RH ), $template ); - $this->_writeEntry( $fh, $cdrec, $filename, $xml ); - $entries++; - } - } - $xml = null; + foreach ($this->template as $cfilename => $template ) { + if ( $cfilename === 'xl/_rels/workbook.xml.rels' ) { + $s = ''; + for ( $i = 0; $i < $cnt_sheets; $i++) { + $s .= '\n"; + } + $s .= ''; + $template = str_replace('{SHEETS}', $s, $template); + $this->_writeEntry($fh, $cdrec, $cfilename, $template); + $entries++; + } elseif ( $cfilename === 'xl/workbook.xml' ) { + $s = ''; + foreach ( $this->sheets as $k => $v ) { + $s .= ''; + } + $template = str_replace('{SHEETS}', $s, $template); + $this->_writeEntry($fh, $cdrec, $cfilename, $template); + $entries++; + } + elseif ( $cfilename === 'docProps/core.xml' ) { + $template = str_replace('{DATE}', gmdate('Y-m-d\TH:i:s\Z'), $template); + $this->_writeEntry($fh, $cdrec, $cfilename, $template); + $entries++; + } elseif ( $cfilename === 'xl/sharedStrings.xml' ) { + if (!count($this->SI)) { + $this->SI[] = 'No Data'; + } + $si_cnt = count($this->SI); + $si = ''.implode("\r\n", $this->SI).''; + $template = str_replace(['{CNT}', '{STRINGS}'], [ $si_cnt, $si ], $template ); + $this->_writeEntry($fh, $cdrec, $cfilename, $template); + $entries++; + } elseif ( $cfilename === 'xl/worksheets/sheet1.xml' ) { + foreach ( $this->sheets as $k => $v ) { + $filename = 'xl/worksheets/sheet'.($k+1).'.xml'; + $xml = $this->_sheetToXML($k, $template); + $this->_writeEntry($fh, $cdrec, $filename, $xml ); + $entries++; + } + $xml = null; + } elseif ( $cfilename === 'xl/worksheets/_rels/sheet1.xml.rels' ) { + foreach ( $this->sheets as $k => $v ) { + if ( count($v['hyperlinks'])) { + $RH = []; + $filename = 'xl/worksheets/_rels/sheet' . ( $k + 1 ) . '.xml.rels'; + foreach ( $v['hyperlinks'] as $h ) { + $RH[] = ''; + } + $xml = str_replace( '{HYPERLINKS}', implode( "\r\n", $RH ), $template ); + $this->_writeEntry( $fh, $cdrec, $filename, $xml ); + $entries++; + } + } + $xml = null; - } elseif ( $cfilename === '[Content_Types].xml' ) { - $TYPES = ['']; - foreach ( $this->sheets as $k => $v) { - $TYPES[] = ''; - if (count( $v['hyperlinks'])) { - $TYPES[] = ''; - } - } - $template = str_replace('{TYPES}', implode("\r\n", $TYPES), $template); - $this->_writeEntry($fh, $cdrec, $cfilename, $template); - $entries++; - } elseif ( $cfilename === 'xl/styles.xml' ) { - $FONTS = ['']; - foreach ( $this->F as $f ) { - $FONTS[] = '' - . ( $this->defaultFontSize ? '' : '' ) - .( $f & self::F_BOLD ? '' : '') - .( $f & self::F_ITALIC ? '' : '') - .( $f & self::F_UNDERLINE ? '' : '') - .( $f & self::F_STRIKE ? '' : '') - .( $f & self::F_HYPERLINK ? '' : '') - .''; - } - $FONTS[] = ''; - $XF = ['']; - foreach( $this->XF as $xf ) { - $align = ($xf[2] === self::A_LEFT ? ' applyAlignment="1">' : '') - .($xf[2] === self::A_RIGHT ? ' applyAlignment="1">' : '') - .($xf[2] === self::A_CENTER ? ' applyAlignment="1">' : ''); - $XF[] = ' 0 ? ' applyNumberFormat="1"' : '') - .($align ? $align . '' : '/>'); + } elseif ( $cfilename === '[Content_Types].xml' ) { + $TYPES = ['']; + foreach ( $this->sheets as $k => $v) { + $TYPES[] = ''; + if (count( $v['hyperlinks'])) { + $TYPES[] = ''; + } + } + $template = str_replace('{TYPES}', implode("\r\n", $TYPES), $template); + $this->_writeEntry($fh, $cdrec, $cfilename, $template); + $entries++; + } elseif ( $cfilename === 'xl/styles.xml' ) { + $FONTS = ['']; + foreach ( $this->F as $f ) { + $FONTS[] = '' + . ( $this->defaultFontSize ? '' : '' ) + .( $f & self::F_BOLD ? '' : '') + .( $f & self::F_ITALIC ? '' : '') + .( $f & self::F_UNDERLINE ? '' : '') + .( $f & self::F_STRIKE ? '' : '') + .( $f & self::F_HYPERLINK ? '' : '') + .''; + } + $FONTS[] = ''; + $XF = ['']; + foreach( $this->XF as $xf ) { + $align = ($xf[2] === self::A_LEFT ? ' applyAlignment="1">' : '') + .($xf[2] === self::A_RIGHT ? ' applyAlignment="1">' : '') + .($xf[2] === self::A_CENTER ? ' applyAlignment="1">' : ''); + $XF[] = ' 0 ? ' applyNumberFormat="1"' : '') + .($align ? $align . '' : '/>'); - } - $XF[] = ''; - $template = str_replace(['{FONTS}','{XF}'], [implode("\r\n", $FONTS), implode("\r\n", $XF)], $template); - $this->_writeEntry($fh, $cdrec, $cfilename, $template); - $entries++; - } else { - $this->_writeEntry($fh, $cdrec, $cfilename, $template); - $entries++; - } - } - $before_cd = ftell($fh); - fwrite($fh, $cdrec); + } + $XF[] = ''; + $template = str_replace(['{FONTS}','{XF}'], [implode("\r\n", $FONTS), implode("\r\n", $XF)], $template); + $this->_writeEntry($fh, $cdrec, $cfilename, $template); + $entries++; + } else { + $this->_writeEntry($fh, $cdrec, $cfilename, $template); + $entries++; + } + } + $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', $entries)); // total # of entries "on this disk" - fwrite($fh, pack('v', $entries)); // total # of entries overall - fwrite($fh, pack('V', mb_strlen($cdrec,'8bit'))); // size of central dir - fwrite($fh, pack('V', $before_cd)); // offset to start of central dir - fwrite($fh, pack('v', mb_strlen($zipComments,'8bit'))); // .zip file comment length - fwrite($fh, $zipComments); + // 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', $entries)); // total # of entries "on this disk" + fwrite($fh, pack('v', $entries)); // total # of entries overall + fwrite($fh, pack('V', mb_strlen($cdrec,'8bit'))); // size of central dir + fwrite($fh, pack('V', $before_cd)); // offset to start of central dir + fwrite($fh, pack('v', mb_strlen($zipComments,'8bit'))); // .zip file comment length + fwrite($fh, $zipComments); - return true; - } + return true; + } - protected function _writeEntry($fh, &$cdrec, $cfilename, $data) { - $zipSignature = "\x50\x4b\x03\x04"; // local file header signature - $dirSignature = "\x50\x4b\x01\x02"; // central dir header signature + protected function _writeEntry($fh, &$cdrec, $cfilename, $data) { + $zipSignature = "\x50\x4b\x03\x04"; // local file header signature + $dirSignature = "\x50\x4b\x01\x02"; // central dir header signature - $e = []; - $e['uncsize'] = mb_strlen($data, '8bit'); + $e = []; + $e['uncsize'] = mb_strlen($data, '8bit'); - // 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 = $data; - } else{ // otherwise, compress it - $zdata = gzcompress($data); - $zdata = substr(substr($zdata, 0, - 4 ), 2); // fix crc bug (thanks to Eric Mueller) - $e['comsize'] = mb_strlen($zdata, '8bit'); - $e['vneeded'] = 10; - $e['cmethod'] = 8; - } + // 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 = $data; + } else{ // otherwise, compress it + $zdata = gzcompress($data); + $zdata = substr(substr($zdata, 0, - 4 ), 2); // fix crc bug (thanks to Eric Mueller) + $e['comsize'] = mb_strlen($zdata, '8bit'); + $e['vneeded'] = 10; + $e['cmethod'] = 8; + } - $e['bitflag'] = 0; - $e['crc_32'] = crc32($data); + $e['bitflag'] = 0; + $e['crc_32'] = crc32($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); + // 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"); + # 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); + $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', mb_strlen($cfilename, '8bit'))); // file_name_length - fwrite($fh, pack('s', 0)); // extra_field_length - fwrite($fh, $cfilename); // file_name - // ignoring extra_field - fwrite($fh, $zdata); + 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', mb_strlen($cfilename, '8bit'))); // 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'] = ''; + // 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', mb_strlen($cfilename,'8bit')); // file name length - $cdrec .= pack('v', 0); // extra field length - $cdrec .= pack('v', mb_strlen($e['comments'],'8bit')); // 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']; - } + $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', mb_strlen($cfilename,'8bit')); // file name length + $cdrec .= pack('v', 0); // extra field length + $cdrec .= pack('v', mb_strlen($e['comments'],'8bit')); // 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']; + } - protected function _sheetToXML($idx, $template) { - // locale floats fr_FR 1.234,56 -> 1234.56 - $_loc = setlocale(LC_NUMERIC, 0); - setlocale(LC_NUMERIC,'C'); - $COLS = []; - $ROWS = []; - if ( count($this->sheets[$idx]['rows']) ) { - $COLS[] = ''; - $CUR_ROW = 0; - $COL = []; - foreach( $this->sheets[$idx]['rows'] as $r ) { - $CUR_ROW++; - $row = ''; - $CUR_COL = 0; - foreach( $r as $v ) { - $CUR_COL++; - if ( !isset($COL[ $CUR_COL ])) { - $COL[ $CUR_COL ] = 0; - } - if ( $v === null || $v === '' ) { - continue; - } + protected function _sheetToXML($idx, $template) { + // locale floats fr_FR 1.234,56 -> 1234.56 + $_loc = setlocale(LC_NUMERIC, 0); + setlocale(LC_NUMERIC,'C'); + $COLS = []; + $ROWS = []; + if ( count($this->sheets[$idx]['rows']) ) { + $COLS[] = ''; + $CUR_ROW = 0; + $COL = []; + foreach( $this->sheets[$idx]['rows'] as $r ) { + $CUR_ROW++; + $row = ''; + $CUR_COL = 0; + foreach( $r as $v ) { + $CUR_COL++; + if ( !isset($COL[ $CUR_COL ])) { + $COL[ $CUR_COL ] = 0; + } + if ( $v === null || $v === '' ) { + continue; + } - $cname = $this->num2name($CUR_COL) . $CUR_ROW; + $cname = $this->num2name($CUR_COL) . $CUR_ROW; - $ct = $cv = null; - $N = $F = $A = 0; + $ct = $cv = null; + $N = $F = $A = 0; - if ( is_string($v) ) { + if ( is_string($v) ) { - if ( $v[0] === "\0" ) { // RAW value as string - $v = substr($v,1); - $vl = mb_strlen( $v ); - } else { - if ( strpos( $v, '<' ) !== false ) { // tags? - if ( strpos( $v, '' ) !== false ) { - $F += self::F_BOLD; - } - if ( strpos( $v, '' ) !== false ) { - $F += self::F_ITALIC; - } - if ( strpos( $v, '' ) !== false ) { - $F += self::F_UNDERLINE; - } - if ( strpos( $v, '' ) !== false ) { - $F += self::F_STRIKE; - } - if ( strpos( $v, '' ) !== false ) { - $A += self::A_LEFT; - } - if ( strpos( $v, '
' ) !== false ) { - $A += self::A_CENTER; - } - if ( strpos( $v, '' ) !== false ) { - $A += self::A_RIGHT; - } - if ( preg_match( '/(.*?)<\/a>/i', $v, $m ) ) { - $h = explode( '#', $m[1] ); - $this->sheets[ $idx ]['hyperlinks'][] = ['ID' => 'rId' . ( count( $this->sheets[ $idx ]['hyperlinks'] ) + 1 ), 'R' => $cname, 'H' => $h[0], 'L' => isset( $h[1] ) ? $h[1] : '']; - $F = self::F_HYPERLINK; // Hyperlink - } - if ( preg_match( '/(.*?)<\/a>/i', $v, $m ) ) { - $this->sheets[ $idx ]['hyperlinks'][] = ['ID' => 'rId' . ( count( $this->sheets[ $idx ]['hyperlinks'] ) + 1 ), 'R' => $cname, 'H' => $m[1], 'L' => '']; - $F = self::F_HYPERLINK; // mailto hyperlink - } - $v = strip_tags( $v ); - } // tags - $vl = mb_strlen( $v ); - if ( $v === '0' || preg_match( '/^[-+]?[1-9]\d{0,14}$/', $v ) ) { // Integer as General - $cv = ltrim( $v, '+' ); - if ( $vl > 10 ) { - $N = self::N_INT; // [1] 0 - } - } elseif ( preg_match( '/^[-+]?(0|[1-9]\d*)\.(\d+)$/', $v, $m ) ) { - $cv = ltrim( $v, '+' ); - if ( strlen( $m[2] ) < 3 ) { - $N = self::N_DEC; - } - } elseif ( preg_match( '/^([-+]?\d+)%$/', $v, $m ) ) { - $cv = round( $m[1] / 100, 2 ); - $N = self::N_PERCENT_INT; // [9] 0% - } elseif ( preg_match( '/^([-+]?\d+\.\d+)%$/', $v, $m ) ) { - $cv = round( $m[1] / 100, 4 ); - $N = self::N_PRECENT_DEC; // [10] 0.00% - } elseif ( preg_match( '/^(\d\d\d\d)-(\d\d)-(\d\d)$/', $v, $m ) ) { - $cv = $this->date2excel( $m[1], $m[2], $m[3] ); - $N = self::N_DATE; // [14] mm-dd-yy - } elseif ( preg_match( '/^(\d\d)\/(\d\d)\/(\d\d\d\d)$/', $v, $m ) ) { - $cv = $this->date2excel( $m[3], $m[2], $m[1] ); - $N = self::N_DATE; // [14] mm-dd-yy - } elseif ( preg_match( '/^(\d\d):(\d\d):(\d\d)$/', $v, $m ) ) { - $cv = $this->date2excel( 0, 0, 0, $m[1], $m[2], $m[3] ); - $N = self::N_TIME; // time - } elseif ( preg_match( '/^(\d\d\d\d)-(\d\d)-(\d\d) (\d\d):(\d\d):(\d\d)$/', $v, $m ) ) { - $cv = $this->date2excel( $m[1], $m[2], $m[3], $m[4], $m[5], $m[6] ); - $N = ((int) $m[1] === 0) ? self::N_TIME : self::N_DATETIME; // [22] m/d/yy h:mm - } elseif ( preg_match( '/^(\d\d)\/(\d\d)\/(\d\d\d\d) (\d\d):(\d\d):(\d\d)$/', $v, $m ) ) { - $cv = $this->date2excel( $m[3], $m[2], $m[1], $m[4], $m[5], $m[6] ); - $N = self::N_DATETIME; // [22] m/d/yy h:mm - } elseif ( preg_match( '/^[0-9+-.]+$/', $v ) ) { // Long ? - $A = self::A_RIGHT; - } elseif ( preg_match( '/^https?:\/\/\S+$/i', $v ) ) { - $h = explode( '#', $v ); - $this->sheets[ $idx ]['hyperlinks'][] = ['ID' => 'rId' . ( count( $this->sheets[ $idx ]['hyperlinks'] ) + 1 ), 'R' => $cname, 'H' => $h[0], 'L' => isset( $h[1] ) ? $h[1] : '']; - $F = self::F_HYPERLINK; // Hyperlink - } elseif ( preg_match( "/^[a-zA-Z0-9_\.\-]+@([a-zA-Z0-9][a-zA-Z0-9\-]*\.)+[a-zA-Z]{2,}$/", $v ) ) { - $this->sheets[ $idx ]['hyperlinks'][] = ['ID' => 'rId' . ( count( $this->sheets[ $idx ]['hyperlinks'] ) + 1 ), 'R' => $cname, 'H' => 'mailto:' . $v, 'L' => '']; - $F = self::F_HYPERLINK; // Hyperlink - } + if ( $v[0] === "\0" ) { // RAW value as string + $v = substr($v,1); + $vl = mb_strlen( $v ); + } else { + if ( strpos( $v, '<' ) !== false ) { // tags? + if ( strpos( $v, '' ) !== false ) { + $F += self::F_BOLD; + } + if ( strpos( $v, '' ) !== false ) { + $F += self::F_ITALIC; + } + if ( strpos( $v, '' ) !== false ) { + $F += self::F_UNDERLINE; + } + if ( strpos( $v, '' ) !== false ) { + $F += self::F_STRIKE; + } + if ( strpos( $v, '' ) !== false ) { + $A += self::A_LEFT; + } + if ( strpos( $v, '
' ) !== false ) { + $A += self::A_CENTER; + } + if ( strpos( $v, '' ) !== false ) { + $A += self::A_RIGHT; + } + if ( preg_match( '/(.*?)<\/a>/i', $v, $m ) ) { + $h = explode( '#', $m[1] ); + $this->sheets[ $idx ]['hyperlinks'][] = ['ID' => 'rId' . ( count( $this->sheets[ $idx ]['hyperlinks'] ) + 1 ), 'R' => $cname, 'H' => $h[0], 'L' => isset( $h[1] ) ? $h[1] : '']; + $F = self::F_HYPERLINK; // Hyperlink + } + if ( preg_match( '/(.*?)<\/a>/i', $v, $m ) ) { + $this->sheets[ $idx ]['hyperlinks'][] = ['ID' => 'rId' . ( count( $this->sheets[ $idx ]['hyperlinks'] ) + 1 ), 'R' => $cname, 'H' => $m[1], 'L' => '']; + $F = self::F_HYPERLINK; // mailto hyperlink + } + $v = strip_tags( $v ); + } // tags + $vl = mb_strlen( $v ); + if ( $v === '0' || preg_match( '/^[-+]?[1-9]\d{0,14}$/', $v ) ) { // Integer as General + $cv = ltrim( $v, '+' ); + if ( $vl > 10 ) { + $N = self::N_INT; // [1] 0 + } + } elseif ( preg_match( '/^[-+]?(0|[1-9]\d*)\.(\d+)$/', $v, $m ) ) { + $cv = ltrim( $v, '+' ); + if ( strlen( $m[2] ) < 3 ) { + $N = self::N_DEC; + } + } elseif ( preg_match( '/^([-+]?\d+)%$/', $v, $m ) ) { + $cv = round( $m[1] / 100, 2 ); + $N = self::N_PERCENT_INT; // [9] 0% + } elseif ( preg_match( '/^([-+]?\d+\.\d+)%$/', $v, $m ) ) { + $cv = round( $m[1] / 100, 4 ); + $N = self::N_PRECENT_DEC; // [10] 0.00% + } elseif ( preg_match( '/^(\d\d\d\d)-(\d\d)-(\d\d)$/', $v, $m ) ) { + $cv = $this->date2excel( $m[1], $m[2], $m[3] ); + $N = self::N_DATE; // [14] mm-dd-yy + } elseif ( preg_match( '/^(\d\d)\/(\d\d)\/(\d\d\d\d)$/', $v, $m ) ) { + $cv = $this->date2excel( $m[3], $m[2], $m[1] ); + $N = self::N_DATE; // [14] mm-dd-yy + } elseif ( preg_match( '/^(\d\d):(\d\d):(\d\d)$/', $v, $m ) ) { + $cv = $this->date2excel( 0, 0, 0, $m[1], $m[2], $m[3] ); + $N = self::N_TIME; // time + } elseif ( preg_match( '/^(\d\d\d\d)-(\d\d)-(\d\d) (\d\d):(\d\d):(\d\d)$/', $v, $m ) ) { + $cv = $this->date2excel( $m[1], $m[2], $m[3], $m[4], $m[5], $m[6] ); + $N = ((int) $m[1] === 0) ? self::N_TIME : self::N_DATETIME; // [22] m/d/yy h:mm + } elseif ( preg_match( '/^(\d\d)\/(\d\d)\/(\d\d\d\d) (\d\d):(\d\d):(\d\d)$/', $v, $m ) ) { + $cv = $this->date2excel( $m[3], $m[2], $m[1], $m[4], $m[5], $m[6] ); + $N = self::N_DATETIME; // [22] m/d/yy h:mm + } elseif ( preg_match( '/^[0-9+-.]+$/', $v ) ) { // Long ? + $A = self::A_RIGHT; + } elseif ( preg_match( '/^https?:\/\/\S+$/i', $v ) ) { + $h = explode( '#', $v ); + $this->sheets[ $idx ]['hyperlinks'][] = ['ID' => 'rId' . ( count( $this->sheets[ $idx ]['hyperlinks'] ) + 1 ), 'R' => $cname, 'H' => $h[0], 'L' => isset( $h[1] ) ? $h[1] : '']; + $F = self::F_HYPERLINK; // Hyperlink + } elseif ( preg_match( "/^[a-zA-Z0-9_\.\-]+@([a-zA-Z0-9][a-zA-Z0-9\-]*\.)+[a-zA-Z]{2,}$/", $v ) ) { + $this->sheets[ $idx ]['hyperlinks'][] = ['ID' => 'rId' . ( count( $this->sheets[ $idx ]['hyperlinks'] ) + 1 ), 'R' => $cname, 'H' => 'mailto:' . $v, 'L' => '']; + $F = self::F_HYPERLINK; // Hyperlink + } if ( ($N === self::N_DATE || $N === self::N_DATETIME) && $cv < 0 ) { $cv = null; $N = 0; } - } - if ( !$cv) { + } + if ( !$cv) { - $v = $this->esc( $v ); + $v = $this->esc( $v ); - if ( mb_strlen( $v ) > 160 ) { - $ct = 'inlineStr'; - $cv = $v; - } else { - $ct = 's'; // shared string - $cv = false; - $skey = '~' . $v; - if ( isset( $this->SI_KEYS[ $skey ] ) ) { - $cv = $this->SI_KEYS[ $skey ]; - } - if ( $cv === false ) { - $this->SI[] = $v; - $cv = count( $this->SI ) - 1; - $this->SI_KEYS[ $skey ] = $cv; - } - } - } - } elseif ( is_int( $v ) ) { - $vl = mb_strlen( (string) $v ); - $cv = $v; - } elseif ( is_float( $v ) ) { - $vl = mb_strlen( (string) $v ); - $cv = $v; - } elseif ( $v instanceof DateTime ) { - $vl = 16; - $cv = $this->date2excel( $v->format('Y'), $v->format('m'), $v->format('d'), $v->format('H'), $v->format('i'), $v->format('s') ); - $N = self::N_DATETIME; // [22] m/d/yy h:mm - } else { - continue; - } + if ( mb_strlen( $v ) > 160 ) { + $ct = 'inlineStr'; + $cv = $v; + } else { + $ct = 's'; // shared string + $cv = false; + $skey = '~' . $v; + if ( isset( $this->SI_KEYS[ $skey ] ) ) { + $cv = $this->SI_KEYS[ $skey ]; + } + if ( $cv === false ) { + $this->SI[] = $v; + $cv = count( $this->SI ) - 1; + $this->SI_KEYS[ $skey ] = $cv; + } + } + } + } elseif ( is_int( $v ) ) { + $vl = mb_strlen( (string) $v ); + $cv = $v; + } elseif ( is_float( $v ) ) { + $vl = mb_strlen( (string) $v ); + $cv = $v; + } elseif ( $v instanceof \DateTime ) { + $vl = 16; + $cv = $this->date2excel( $v->format('Y'), $v->format('m'), $v->format('d'), $v->format('H'), $v->format('i'), $v->format('s') ); + $N = self::N_DATETIME; // [22] m/d/yy h:mm + } else { + continue; + } - $COL[ $CUR_COL ] = max( $vl, $COL[ $CUR_COL ] ); + $COL[ $CUR_COL ] = max( $vl, $COL[ $CUR_COL ] ); - $cs = 0; - if ( $N + $F + $A > 0 ) { + $cs = 0; + if ( $N + $F + $A > 0 ) { - if ( isset($this->F_KEYS[ $F ] ) ) { - $cf = $this->F_KEYS[ $F ]; - } else { - $cf = count($this->F); - $this->F_KEYS[$F] = $cf; - $this->F[] = $F; - } - $NFA = 'N' . $N . 'F' . $cf . 'A' . $A; - if ( isset( $this->XF_KEYS[ $NFA ] ) ) { - $cs = $this->XF_KEYS[ $NFA ]; - } - if ( $cs === 0 ) { - $cs = count( $this->XF ); - $this->XF_KEYS[ $NFA ] = $cs; - $this->XF[] = [$N, $cf, $A]; - } - } + if ( isset($this->F_KEYS[ $F ] ) ) { + $cf = $this->F_KEYS[ $F ]; + } else { + $cf = count($this->F); + $this->F_KEYS[$F] = $cf; + $this->F[] = $F; + } + $NFA = 'N' . $N . 'F' . $cf . 'A' . $A; + if ( isset( $this->XF_KEYS[ $NFA ] ) ) { + $cs = $this->XF_KEYS[ $NFA ]; + } + if ( $cs === 0 ) { + $cs = count( $this->XF ); + $this->XF_KEYS[ $NFA ] = $cs; + $this->XF[] = [$N, $cf, $A]; + } + } - $row .= '' - .($ct === 'inlineStr' ? ''.$cv.'' : '' . $cv . '')."\r\n"; - } - $ROWS[] = $row . "\r\n"; - } - foreach ( $COL as $k => $max ) { - $COLS[] = ''; - } - $COLS[] = ''; - $REF = 'A1:'.$this->num2name(count($COLS)) . $CUR_ROW; - } else { - $ROWS[] = '0'; - $REF = 'A1:A1'; - } - $HYPERLINKS = []; - if ( count( $this->sheets[$idx]['hyperlinks']) ) { - $HYPERLINKS[] = ''; - foreach ( $this->sheets[$idx]['hyperlinks'] as $h ) { - $HYPERLINKS[] = ''; - } - $HYPERLINKS[] = ''; - } - //restore locale - setlocale(LC_NUMERIC, $_loc); + $row .= '' + .($ct === 'inlineStr' ? ''.$cv.'' : '' . $cv . '')."\r\n"; + } + $ROWS[] = $row . "\r\n"; + } + foreach ( $COL as $k => $max ) { + $COLS[] = ''; + } + $COLS[] = ''; + $REF = 'A1:'.$this->num2name(count($COLS)) . $CUR_ROW; + } else { + $ROWS[] = '0'; + $REF = 'A1:A1'; + } + $HYPERLINKS = []; + if ( count( $this->sheets[$idx]['hyperlinks']) ) { + $HYPERLINKS[] = ''; + foreach ( $this->sheets[$idx]['hyperlinks'] as $h ) { + $HYPERLINKS[] = ''; + } + $HYPERLINKS[] = ''; + } + //restore locale + setlocale(LC_NUMERIC, $_loc); - return str_replace(['{REF}','{COLS}','{ROWS}','{HYPERLINKS}'], - [ $REF, implode("\r\n", $COLS), implode("\r\n",$ROWS), implode("\r\n", $HYPERLINKS) ], - $template ); - } + return str_replace(['{REF}','{COLS}','{ROWS}','{HYPERLINKS}'], + [ $REF, implode("\r\n", $COLS), implode("\r\n",$ROWS), implode("\r\n", $HYPERLINKS) ], + $template ); + } - public function num2name($num) { - $numeric = ($num - 1) % 26; - $letter = chr( 65 + $numeric ); - $num2 = (int) ( ($num-1) / 26 ); - if ( $num2 > 0 ) { - return $this->num2name( $num2 ) . $letter; - } - return $letter; - } + public function num2name($num) { + $numeric = ($num - 1) % 26; + $letter = chr( 65 + $numeric ); + $num2 = (int) ( ($num-1) / 26 ); + if ( $num2 > 0 ) { + return $this->num2name( $num2 ) . $letter; + } + return $letter; + } - public function date2excel($year, $month, $day, $hours=0, $minutes=0, $seconds=0) { + public function date2excel($year, $month, $day, $hours=0, $minutes=0, $seconds=0) { - $excelTime = (($hours * 3600) + ($minutes * 60) + $seconds) / 86400; + $excelTime = (($hours * 3600) + ($minutes * 60) + $seconds) / 86400; - if ( (int) $year === 0 ) { - return $excelTime; + if ( (int) $year === 0 ) { + return $excelTime; } - // self::CALENDAR_WINDOWS_1900 - $excel1900isLeapYear = True; - if (($year === 1900) && ($month <= 2)) { $excel1900isLeapYear = False; } - $myExcelBaseDate = 2415020; + // self::CALENDAR_WINDOWS_1900 + $excel1900isLeapYear = True; + if (($year === 1900) && ($month <= 2)) { $excel1900isLeapYear = False; } + $myExcelBaseDate = 2415020; - // Julian base date Adjustment - if ($month > 2) { - $month -= 3; - } else { - $month += 9; - --$year; - } - $century = substr($year,0,2); - $decade = substr($year,2,2); - // Calculate the Julian Date, then subtract the Excel base date (JD 2415020 = 31-Dec-1899 Giving Excel Date of 0) - $excelDate = floor((146097 * $century) / 4) + floor((1461 * $decade) / 4) + floor((153 * $month + 2) / 5) + $day + 1721119 - $myExcelBaseDate + $excel1900isLeapYear; + // Julian base date Adjustment + if ($month > 2) { + $month -= 3; + } else { + $month += 9; + --$year; + } + $century = substr($year,0,2); + $decade = substr($year,2,2); + // Calculate the Julian Date, then subtract the Excel base date (JD 2415020 = 31-Dec-1899 Giving Excel Date of 0) + $excelDate = floor((146097 * $century) / 4) + floor((1461 * $decade) / 4) + floor((153 * $month + 2) / 5) + $day + 1721119 - $myExcelBaseDate + $excel1900isLeapYear; - return (float) $excelDate + $excelTime; - } - public function setDefaultFont( $name ) { - $this->defaultFont = $name; - return $this; - } - public function setDefaultFontSize( $size ) { - $this->defaultFontSize = $size; - return $this; - } - public function esc( $str ) { - // XML UTF-8: #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF] - // but we use fast version - return str_replace( ['&', '<', '>', "\x00","\x03","\x0B"], ['&', '<', '>', '', '', ''], $str ); - } -} + return (float) $excelDate + $excelTime; + } + public function setDefaultFont( $name ) { + $this->defaultFont = $name; + return $this; + } + public function setDefaultFontSize( $size ) { + $this->defaultFontSize = $size; + return $this; + } + public function esc( $str ) { + // XML UTF-8: #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF] + // but we use fast version + return str_replace( ['&', '<', '>', "\x00","\x03","\x0B"], ['&', '<', '>', '', '', ''], $str ); + } +} \ No newline at end of file