├── LICENSE
├── README.md
└── xlsxwriter.class.php
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2013 Mark Jones
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the "Software"), to deal in
7 | the Software without restriction, including without limitation the rights to
8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software is furnished to do so,
10 | subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | PHP_XLSXWriter_plus
2 | ==============
3 |
4 | This library is designed to be lightweight, and have relatively low memory usage. This is the fork of https://github.com/mk-j/PHP_XLSXWriter
5 |
6 | It is designed to output an Excel spreadsheet in with (Office 2007+) xlsx format, with just basic features supported:
7 | * assumes input is valid UTF-8
8 | * multiple worksheets
9 | * supports cell formats:
10 | ```
11 | // 1 0
12 | // 2 0.00
13 | // 3 #,##0
14 | // 4 #,##0.00
15 | // 5 $#,##0_);($#,##0)
16 | // 6 $#,##0_);[Red]($#,##0)
17 | // 7 $#,##0.00_);($#,##0.00)
18 | // 8 $#,##0.00_);[Red]($#,##0.00)
19 | // 9 0%
20 | // 10 0.00%
21 | // 11 0.00E+00
22 | // 12 # ?/?
23 | // 13 # ??/??
24 | // 14 m/d/yyyy
25 | // 15 d-mmm-yy
26 | // 16 d-mmm
27 | // 17 mmm-yy
28 | // 18 h:mm AM/PM
29 | // 19 h:mm:ss AM/PM
30 | // 20 h:mm
31 | // 21 h:mm:ss
32 | // 22 m/d/yyyy h:mm
33 | // 37 #,##0_);(#,##0)
34 | // 38 #,##0_);[Red](#,##0)
35 | // 39 #,##0.00_);(#,##0.00)
36 | // 40 #,##0.00_);[Red](#,##0.00)
37 | // 45 mm:ss
38 | // 46 [h]:mm:ss
39 | // 47 mm:ss.0
40 | // 48 ##0.0E+0
41 | // 49 @
42 | ```
43 | * supports styling cells
44 |
45 |
46 | Simple example:
47 | ```php
48 | $data = array(
49 | array('year','month','amount'),
50 | array('2003','1','220'),
51 | array('2003','2','153.5'),
52 | );
53 |
54 | $writer = new XLSXWriter();
55 | $writer->writeSheet($data);
56 | $writer->writeToFile('output.xlsx');
57 | ```
58 |
59 | Multiple Sheets:
60 | ```php
61 | $data1 = array(
62 | array('5','3'),
63 | array('1','6'),
64 | );
65 | $data2 = array(
66 | array('2','7','9'),
67 | array('4','8','0'),
68 | );
69 |
70 | $writer = new XLSXWriter();
71 | $writer->setAuthor('Doc Author');
72 | $writer->writeSheet($data1);
73 | $writer->writeSheet($data2);
74 | echo $writer->writeToString();
75 | ```
76 |
77 | Cell Formatting:
78 | ```php
79 | $header = array(
80 | 'create_date'=>'string',
81 | 'quantity'=>'string',
82 | 'product_id'=>'string',
83 | 'amount'=>'string',
84 | 'description'=>'string',
85 | );
86 | $data = array(
87 | array('2013-01-01',1,27,'44.00','twig'),
88 | array('2013-01-05',1,'=C1','-44.00','refund'),
89 | );
90 |
91 | $writer = new XLSXWriter();
92 | $writer->writeSheet($data,'Sheet1', $header, $style);
93 | $writer->writeToFile('example.xlsx');
94 | ```
95 |
96 | Cell Styling
97 | ```php
98 | $writer->setFontName('MS Sans Serif'); //default document font name
99 | $writer->setFontSize(8); //default document font size
100 | $writer->setWrapText(true); //default document wrap cells
101 | $writer->setVerticalAlign('top'); //default document vertical align
102 | $writer->setHorizontalAlign('left'); //default document horizontal alilgn
103 | $writer->setStartRow(10); //set start data filling row
104 | $writer->setStartCol(0); //set start data filling column
105 |
106 | //set styles
107 | $writer->writeSheet($data, 'Sheet1', $header,
108 | array (
109 | array( // in each style element you can use or 'cells', or 'rows' or 'columns'.
110 | 'font' => array(
111 | 'name' => 'Times New Roman',
112 | 'size' => '11',
113 | 'color' => '0000FF',
114 | 'bold' => true,
115 | 'italic' => true,
116 | 'underline' => true),
117 | 'border' => array(
118 | 'style' => 'thin',
119 | 'color' => 'A0A0A0'),
120 | 'fill' => array(
121 | 'color' => 'F0F0F0'),
122 | 'cells' => array( //for 1 cell - array is not nessesary, use - 'cells' => 'C3'
123 | 'E1',
124 | 'E2'),
125 | 'wrapText' => true,
126 | 'verticalAlign' => 'top',
127 | 'horizontalAlign' => 'left',
128 | 'format' => 5
129 | ),
130 | array(
131 | 'fill' => array(
132 | 'color' => 'F09900'),
133 | 'columns' => '2' //for only one and firs column dont use 'columns' => '0', use 'columns' => array('0')
134 | ),
135 | array(
136 | 'fill' => array(
137 | 'color' => 'F000F0'),
138 | 'rows' => array(
139 | '0','1') //for only one and firs row dont use 'rows' => '0', use 'rows' => array('0')
140 | )
141 | array(
142 | 'fill' => array(
143 | 'color' => 'F000F0'),
144 | 'allfilleddata' => true //for all filled data cells - can be used without: columns, rows, cells!
145 | )
146 | )
147 | );
148 | ```
--------------------------------------------------------------------------------
/xlsxwriter.class.php:
--------------------------------------------------------------------------------
1 | author=$author; }
48 | public function setFontName($defaultFontName) { $this->defaultFontName=$defaultFontName; }
49 | public function setFontSize($defaultFontSize) { $this->defaultFontSize=$defaultFontSize; }
50 | public function setWrapText($defaultWrapText) { $this->defaultWrapText=$defaultWrapText; }
51 | public function setVerticalAlign($defaultVerticalAlign) { $this->defaultVerticalAlign=$defaultVerticalAlign; }
52 | public function setHorizontalAlign($defaultHorizontalAlign) { $this->defaultHorizontalAlign=$defaultHorizontalAlign; }
53 | private function setStyle($defaultStyle) { $this->defaultStyle=$defaultStyle; }
54 | public function setStartRow($defaultStartRow) { $this->defaultStartRow=($defaultStartRow > 0) ? ((int)$defaultStartRow - 1) : 0; }
55 | public function setStartCol($defaultStartCol) { $this->defaultStartCol=($defaultStartCol > 0) ? ((int)$defaultStartCol - 1) : 0; }
56 |
57 | public function __destruct()
58 | {
59 | if (!empty($this->temp_files)) {
60 | foreach($this->temp_files as $temp_file) {
61 | @unlink($temp_file);
62 | }
63 | }
64 | }
65 |
66 | protected function tempFilename()
67 | {
68 | $filename = tempnam("/tmp", "xlsx_writer_");
69 | $this->temp_files[] = $filename;
70 | return $filename;
71 | }
72 |
73 | public function writeToStdOut()
74 | {
75 | $temp_file = $this->tempFilename();
76 | self::writeToFile($temp_file);
77 | readfile($temp_file);
78 | }
79 |
80 | public function writeToString()
81 | {
82 | $temp_file = $this->tempFilename();
83 | self::writeToFile($temp_file);
84 | $string = file_get_contents($temp_file);
85 | return $string;
86 | }
87 |
88 | public function writeToFile($filename)
89 | {
90 | @unlink($filename);//if the zip already exists, overwrite it
91 | $zip = new ZipArchive();
92 | if (empty($this->sheets_meta)) { self::log("Error in ".__CLASS__."::".__FUNCTION__.", no worksheets defined."); return; }
93 | if (!$zip->open($filename, ZipArchive::CREATE)) { self::log("Error in ".__CLASS__."::".__FUNCTION__.", unable to create zip."); return; }
94 |
95 | $zip->addEmptyDir("docProps/");
96 | $zip->addFromString("docProps/app.xml" , self::buildAppXML() );
97 | $zip->addFromString("docProps/core.xml", self::buildCoreXML());
98 |
99 | $zip->addEmptyDir("_rels/");
100 | $zip->addFromString("_rels/.rels", self::buildRelationshipsXML());
101 |
102 | $zip->addEmptyDir("xl/worksheets/");
103 | foreach($this->sheets_meta as $sheet_meta) {
104 | $zip->addFile($sheet_meta['filename'], "xl/worksheets/".$sheet_meta['xmlname'] );
105 | }
106 | if (!empty($this->shared_strings)) {
107 | $zip->addFile($this->writeSharedStringsXML(), "xl/sharedStrings.xml" ); //$zip->addFromString("xl/sharedStrings.xml", self::buildSharedStringsXML() );
108 | }
109 | $zip->addFromString("xl/workbook.xml" , self::buildWorkbookXML() );
110 | $zip->addFile($this->writeStylesXML(), "xl/styles.xml" ); //$zip->addFromString("xl/styles.xml" , self::buildStylesXML() );
111 | $zip->addFromString("[Content_Types].xml" , self::buildContentTypesXML() );
112 |
113 | $zip->addEmptyDir("xl/_rels/");
114 | $zip->addFromString("xl/_rels/workbook.xml.rels", self::buildWorkbookRelsXML() );
115 | $zip->close();
116 | }
117 |
118 |
119 | public function writeSheet(array $data, $sheet_name='', array $header_types=array(), array $styles )
120 | {
121 | for ($i = 0; $i < count($styles); $i++) {
122 | $styles[$i] += array('sheet' => $sheet_name);
123 | }
124 | $this->setStyle(array_merge((array)$this->defaultStyle, (array)$styles));
125 |
126 | $data = empty($data) ? array( array('') ) : $data;
127 |
128 | $sheet_filename = $this->tempFilename();
129 | $sheet_default = 'Sheet'.(count($this->sheets_meta)+1);
130 | $sheet_name = !empty($sheet_name) ? $sheet_name : $sheet_default;
131 | $this->sheets_meta[] = array('filename'=>$sheet_filename, 'sheetname'=>$sheet_name ,'xmlname'=>strtolower($sheet_default).".xml" );
132 |
133 | $header_offset = empty($header_types) ? 0 : $this->defaultStartRow + 1;
134 | $row_count = count($data) + $header_offset;
135 | $column_count = count($data[self::array_first_key($data)]);
136 | $max_cell = self::xlsCell( $row_count-1, $column_count-1 );
137 |
138 | $tabselected = count($this->sheets_meta)==1 ? 'true' : 'false';//only first sheet is selected
139 | $cell_formats_arr = empty($header_types) ? array_fill(0, $column_count, 'string') : array_values($header_types);
140 | $header_row = empty($header_types) ? array() : array_keys($header_types);
141 |
142 | $fd = fopen($sheet_filename, "w+");
143 | if ($fd===false) { self::log("write failed in ".__CLASS__."::".__FUNCTION__."."); return; }
144 |
145 | fwrite($fd,''."\n");
146 | fwrite($fd,'');
147 | fwrite($fd, '');
148 | fwrite($fd, '');
149 | fwrite($fd, '');
150 | fwrite($fd, '');
151 | fwrite($fd, '');
152 | fwrite($fd, '');
153 | fwrite($fd, '');
154 | fwrite($fd, '');
155 | fwrite($fd, '');
156 | fwrite($fd, '');
157 | fwrite($fd, '');
158 | fwrite($fd, '');
159 | fwrite($fd, '');
160 | if (!empty($header_row))
161 | {
162 | fwrite($fd, '');
163 | foreach($header_row as $k=>$v)
164 | {
165 | $this->writeCell($fd, $this->defaultStartRow + 0, $this->defaultStartCol + $k, $v, $sheet_name);
166 | }
167 | fwrite($fd, '
');
168 | }
169 | foreach($data as $i=>$row)
170 | {
171 | fwrite($fd, '');
172 | foreach($row as $k=>$v)
173 | {
174 | $this->writeCell($fd, $i+$header_offset, $this->defaultStartCol + $k, $v, $sheet_name);
175 | }
176 | fwrite($fd, '
');
177 | }
178 | fwrite($fd, '');
179 | fwrite($fd, '');
180 | fwrite($fd, '');
181 | fwrite($fd, '');
182 | fwrite($fd, '');
183 | fwrite($fd, '&C&"Times New Roman,Regular"&12&A');
184 | fwrite($fd, '&C&"Times New Roman,Regular"&12Page &P');
185 | fwrite($fd, '');
186 | fwrite($fd,'');
187 | fclose($fd);
188 | }
189 |
190 | protected function writeCell($fd, $row_number, $column_number, $value, $sheet_name)
191 | {
192 | $cell = self::xlsCell($row_number, $column_number);
193 | $s = '0';
194 | if ($this->defaultStyle) {
195 | foreach ($this->defaultStyle as $key => $style) {
196 | if (isset($style['sheet'])) {
197 | if ($style['sheet'] == $sheet_name) {
198 | if (isset($style['allfilleddata'])) {
199 | $s = $key + 1;
200 | } else {
201 | if (isset($style['columns'])) {
202 | if (is_array($style['columns'])) {
203 | if (in_array($column_number, $style['columns'])) $s = $key + 1;
204 | } else {
205 | if ($column_number == $style['columns']) $s = $key + 1;
206 | }
207 | } elseif (isset($style['rows'])) {
208 | if (is_array($style['rows'])) {
209 | if (in_array($row_number, $style['rows'])) $s = $key + 1;
210 | } else {
211 | if ($row_number == $style['rows']) $s = $key + 1;
212 | }
213 | } elseif (isset($style['cells'])) {
214 | if (is_array($style['cells'])) {
215 | if (in_array($cell, $style['cells'])) $s = $key + 1;
216 | } else {
217 | if ($cell == $style['cells']) $s = $key + 1;
218 | }
219 | }
220 | }
221 | }
222 | }
223 | }
224 | }
225 | if (is_numeric($value)) {
226 | fwrite($fd,''.($value*1).'');//int,float, etc
227 | } else if ($cell_format=='date') {
228 | fwrite($fd,''.intval(self::convert_date_time($value)).'');
229 | } else if ($cell_format=='datetime') {
230 | fwrite($fd,''.self::convert_date_time($value).'');
231 | } else if ($value==''){
232 | fwrite($fd,'');
233 | } else if ($value{0}=='='){
234 | fwrite($fd,''.self::xmlspecialchars($value).'');
235 | } else if ($value!==''){
236 | fwrite($fd,''.self::xmlspecialchars($this->setSharedString($value)).'');
237 | }
238 | }
239 |
240 | protected function writeStylesXML()
241 | {
242 | $tempfile = $this->tempFilename();
243 | $fd = fopen($tempfile, "w+");
244 | if ($fd===false) { self::log("write failed in ".__CLASS__."::".__FUNCTION__."."); return; }
245 | fwrite($fd, ''."\n");
246 | fwrite($fd, '');
247 | if ($this->defaultStyle) {
248 | foreach ($this->defaultStyle as $style) {
249 | if (isset($style['sheet'])) {
250 | if (isset($style['font'])) $this->fontsCount++;
251 | }
252 | }
253 | }
254 | fwrite($fd, '');
255 | fwrite($fd, ' ');
256 | fwrite($fd, ' ');
257 | fwrite($fd, ' ');
258 | fwrite($fd, ' ');
259 | fwrite($fd, ' ');
260 | if ($this->defaultFontName == 'MS Sans Serif') {
261 | fwrite($fd, ' ');
262 | } else if ($this->defaultFontName == 'Calibri') {
263 | fwrite($fd, ' ');
264 | } else {
265 | fwrite($fd, ' ');
266 | }
267 | fwrite($fd, ' ');
268 | if ($this->defaultStyle) {
269 | foreach ($this->defaultStyle as $style) {
270 | if (isset($style['sheet'])) {
271 | if (isset($style['font'])) {
272 | if (isset($style['font']['name'])) $this->fontName = $style['font']['name'];
273 | if (isset($style['font']['size'])) $this->fontSize = $style['font']['size'];
274 | if (isset($style['font']['color'])) $this->fontColor = $style['font']['color'];
275 | if ($style['font']['bold']) $this->fontStyles .= '';
276 | if ($style['font']['italic']) $this->fontStyles .= '';
277 | if ($style['font']['underline']) $this->fontStyles .= '';
278 |
279 | fwrite($fd, ' ');
280 | if ($this->fontStyles) fwrite($fd, ' '.$this->fontStyles);
281 | fwrite($fd, ' ');
282 | if ($this->fontColor) {
283 | fwrite($fd, ' ');
284 | } else {
285 | fwrite($fd, ' ');
286 | }
287 | fwrite($fd, ' ');
288 | fwrite($fd, ' ');
289 | if ($this->fontName == 'MS Sans Serif') {
290 | fwrite($fd, ' ');
291 | } else if ($this->fontName == 'Calibri') {
292 | fwrite($fd, ' ');
293 | } else {
294 | fwrite($fd, ' ');
295 | }
296 | fwrite($fd, ' ');
297 | }
298 | $this->fontStyles = '';
299 | }
300 | }
301 | }
302 | fwrite($fd, '');
303 | if ($this->defaultStyle) {
304 | foreach ($this->defaultStyle as $style) {
305 | if (isset($style['sheet'])) {
306 | if (isset($style['fill'])) $this->fillsCount++;
307 | }
308 | }
309 | }
310 | fwrite($fd, '');
311 | fwrite($fd, ' ');
312 | fwrite($fd, ' ');
313 | if ($this->defaultStyle) {
314 | foreach ($this->defaultStyle as $style) {
315 | if (isset($style['sheet'])) {
316 | if (isset($style['fill'])) {
317 | if (isset($style['fill']['color'])) $this->fillColor = $style['fill']['color'];
318 | fwrite($fd, ' ');
319 | fwrite($fd, ' ');
320 | fwrite($fd, ' ');
321 | fwrite($fd, ' ');
322 | fwrite($fd, ' ');
323 | fwrite($fd, ' ');
324 | }
325 | }
326 | }
327 | }
328 | fwrite($fd, '');
329 | if ($this->defaultStyle) {
330 | foreach ($this->defaultStyle as $style) {
331 | if (isset($style['sheet'])) {
332 | if (isset($style['border'])) $this->bordersCount++;
333 | }
334 | }
335 | }
336 | fwrite($fd, '');
337 | fwrite($fd, ' ');
338 | fwrite($fd, ' ');
339 | fwrite($fd, ' ');
340 | if ($this->defaultStyle) {
341 | foreach ($this->defaultStyle as $style) {
342 | if (isset($style['sheet'])) {
343 | if (isset($style['border'])) {
344 | if (isset($style['border']['style'])) $this->bordersStyle = ' style="'.$style['border']['style'].'"';
345 | if (isset($style['border']['color'])) $this->bordersColor = '';
346 | fwrite($fd, ' ');
347 | fwrite($fd, ' bordersStyle.'>'.$this->bordersColor.'');
348 | fwrite($fd, ' bordersStyle.'>'.$this->bordersColor.'');
349 | fwrite($fd, ' bordersStyle.'>'.$this->bordersColor.'');
350 | fwrite($fd, ' bordersStyle.'>'.$this->bordersColor.'');
351 | fwrite($fd, ' ');
352 | fwrite($fd, ' ');
353 | }
354 | }
355 | }
356 | }
357 | fwrite($fd, '');
358 | fwrite($fd, '');
359 | fwrite($fd, '');
360 | fwrite($fd, '');
361 | $this->stylesCount += count($this->defaultStyle);
362 | fwrite($fd, '');
363 | $this->defaultWrapText = ($this->defaultWrapText) ? '1' : '0';
364 | fwrite($fd, '');
365 | if ($this->defaultStyle) {
366 | foreach ($this->defaultStyle as $style) {
367 | if (isset($style['sheet'])) {
368 | if (isset($style['font'])) {
369 | $font_Id = $this->fontId += 1;
370 | } else {
371 | $font_Id = 0;
372 | }
373 | if (isset($style['fill'])) {
374 | $fill_Id = $this->fillId += 1;
375 | } else {
376 | $fill_Id = 0;
377 | }
378 | if (isset($style['border'])) {
379 | $border_Id = $this->borderId += 1;
380 | } else {
381 | $border_Id = 0;
382 | }
383 | if (isset($style['wrapText'])) {
384 | $wrapText = ($style['wrapText']) ? '1' : '0';
385 | } else {
386 | $wrapText = $this->defaultWrapText;
387 | }
388 |
389 | $format_Id = (isset($style['format'])) ? $style['format'] : '0';
390 |
391 | if (isset($style['verticalAlign'])) {
392 | $verticalAlign = $style['verticalAlign'];
393 | } else {
394 | $verticalAlign = $this->defaultVerticalAlign;
395 | }
396 | if (isset($style['horizontalAlign'])) {
397 | $horizontalAlign = $style['horizontalAlign'];
398 | } else {
399 | $horizontalAlign = $this->defaultHorizontalAlign;
400 | }
401 | fwrite($fd, '');
402 | fwrite($fd, '');
403 | fwrite($fd, '');
404 | }
405 | }
406 | }
407 | fwrite($fd, '');
408 | fwrite($fd, '');
409 | fwrite($fd, '');
410 | fwrite($fd, '');
411 | fwrite($fd, '');
412 | fwrite($fd, '');
413 | fwrite($fd, '');
414 | fwrite($fd, '');
415 | fwrite($fd, '');
416 | fwrite($fd, '');
417 | fwrite($fd, '');
418 | fwrite($fd, '');
419 | fclose($fd);
420 | return $tempfile;
421 | }
422 |
423 | protected function setSharedString($v)
424 | {
425 | if (isset($this->shared_strings[$v]))
426 | {
427 | $string_value = $this->shared_strings[$v];
428 | }
429 | else
430 | {
431 | $string_value = count($this->shared_strings);
432 | $this->shared_strings[$v] = $string_value;
433 | }
434 | $this->shared_string_count++;//non-unique count
435 | return $string_value;
436 | }
437 |
438 | protected function writeSharedStringsXML()
439 | {
440 | $tempfile = $this->tempFilename();
441 | $fd = fopen($tempfile, "w+");
442 | if ($fd===false) { self::log("write failed in ".__CLASS__."::".__FUNCTION__."."); return; }
443 |
444 | fwrite($fd,''."\n");
445 | fwrite($fd,'');
446 | foreach($this->shared_strings as $s=>$c)
447 | {
448 | fwrite($fd,''.self::xmlspecialchars($s).'');
449 | }
450 | fwrite($fd, '');
451 | fclose($fd);
452 | return $tempfile;
453 | }
454 |
455 | protected function buildAppXML()
456 | {
457 | $app_xml="";
458 | $app_xml.=''."\n";
459 | $app_xml.='0';
460 | return $app_xml;
461 | }
462 |
463 | protected function buildCoreXML()
464 | {
465 | $core_xml="";
466 | $core_xml.=''."\n";
467 | $core_xml.='';
468 | $core_xml.=''.date("Y-m-d\TH:i:s.00\Z").'';//$date_time = '2013-07-25T15:54:37.00Z';
469 | $core_xml.=''.self::xmlspecialchars($this->author).'';
470 | $core_xml.='0';
471 | $core_xml.='';
472 | return $core_xml;
473 | }
474 |
475 | protected function buildRelationshipsXML()
476 | {
477 | $rels_xml="";
478 | $rels_xml.=''."\n";
479 | $rels_xml.='';
480 | $rels_xml.='';
481 | $rels_xml.='';
482 | $rels_xml.='';
483 | $rels_xml.="\n";
484 | $rels_xml.='';
485 | return $rels_xml;
486 | }
487 |
488 | protected function buildWorkbookXML()
489 | {
490 | $workbook_xml="";
491 | $workbook_xml.=''."\n";
492 | $workbook_xml.='';
493 | $workbook_xml.='';
494 | $workbook_xml.='';
495 | $workbook_xml.='';
496 | foreach($this->sheets_meta as $i=>$sheet_meta) {
497 | $workbook_xml.='';
498 | }
499 | $workbook_xml.='';
500 | $workbook_xml.='';
501 | return $workbook_xml;
502 | }
503 |
504 | protected function buildWorkbookRelsXML()
505 | {
506 | $wkbkrels_xml="";
507 | $wkbkrels_xml.=''."\n";
508 | $wkbkrels_xml.='';
509 | $wkbkrels_xml.='';
510 | foreach($this->sheets_meta as $i=>$sheet_meta) {
511 | $wkbkrels_xml.='';
512 | }
513 | if (!empty($this->shared_strings)) {
514 | $wkbkrels_xml.='';
515 | }
516 | $wkbkrels_xml.="\n";
517 | $wkbkrels_xml.='';
518 | return $wkbkrels_xml;
519 | }
520 |
521 | protected function buildContentTypesXML()
522 | {
523 | $content_types_xml="";
524 | $content_types_xml.=''."\n";
525 | $content_types_xml.='';
526 | $content_types_xml.='';
527 | $content_types_xml.='';
528 | foreach($this->sheets_meta as $i=>$sheet_meta) {
529 | $content_types_xml.='';
530 | }
531 | if (!empty($this->shared_strings)) {
532 | $content_types_xml.='';
533 | }
534 | $content_types_xml.='';
535 | $content_types_xml.='';
536 | $content_types_xml.='';
537 | $content_types_xml.='';
538 | $content_types_xml.="\n";
539 | $content_types_xml.='';
540 | return $content_types_xml;
541 | }
542 |
543 | //------------------------------------------------------------------
544 | /*
545 | * @param $row_number int, zero based
546 | * @param $column_number int, zero based
547 | * @return Cell label/coordinates, ex: A1, C3, AA42
548 | * */
549 | public static function xlsCell($row_number, $column_number)
550 | {
551 | $n = $column_number;
552 | for($r = ""; $n >= 0; $n = intval($n / 26) - 1) {
553 | $r = chr($n%26 + 0x41) . $r;
554 | }
555 | return $r . ($row_number+1);
556 | }
557 | //------------------------------------------------------------------
558 | public static function log($string)
559 | {
560 | file_put_contents("php://stderr", date("Y-m-d H:i:s:").rtrim(is_array($string) ? json_encode($string) : $string)."\n");
561 | }
562 | //------------------------------------------------------------------
563 | public static function xmlspecialchars($val)
564 | {
565 | return str_replace("'", "'", htmlspecialchars($val));
566 | }
567 | //------------------------------------------------------------------
568 | public static function array_first_key(array $arr)
569 | {
570 | reset($arr);
571 | $first_key = key($arr);
572 | return $first_key;
573 | }
574 | //------------------------------------------------------------------
575 | public static function convert_date_time($date_input) //thanks to Excel::Writer::XLSX::Worksheet.pm (perl)
576 | {
577 | $days = 0; # Number of days since epoch
578 | $seconds = 0; # Time expressed as fraction of 24h hours in seconds
579 | $year=$month=$day=0;
580 | $hour=$min =$sec=0;
581 |
582 | $date_time = $date_input;
583 | if (preg_match("/(\d{4})\-(\d{2})\-(\d{2})/", $date_time, $matches))
584 | {
585 | list($junk,$year,$month,$day) = $matches;
586 | }
587 | if (preg_match("/(\d{2}):(\d{2}):(\d{2})/", $date_time, $matches))
588 | {
589 | list($junk,$hour,$min,$sec) = $matches;
590 | $seconds = ( $hour * 60 * 60 + $min * 60 + $sec ) / ( 24 * 60 * 60 );
591 | }
592 |
593 | //using 1900 as epoch, not 1904, ignoring 1904 special case
594 |
595 | # Special cases for Excel.
596 | if ("$year-$month-$day"=='1899-12-31') return $seconds ; # Excel 1900 epoch
597 | if ("$year-$month-$day"=='1900-01-00') return $seconds ; # Excel 1900 epoch
598 | if ("$year-$month-$day"=='1900-02-29') return 60 + $seconds ; # Excel false leapday
599 |
600 | # We calculate the date by calculating the number of days since the epoch
601 | # and adjust for the number of leap days. We calculate the number of leap
602 | # days by normalising the year in relation to the epoch. Thus the year 2000
603 | # becomes 100 for 4 and 100 year leapdays and 400 for 400 year leapdays.
604 | $epoch = 1900;
605 | $offset = 0;
606 | $norm = 300;
607 | $range = $year - $epoch;
608 |
609 | # Set month days and check for leap year.
610 | $leap = (($year % 400 == 0) || (($year % 4 == 0) && ($year % 100)) ) ? 1 : 0;
611 | $mdays = array( 31, ($leap ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 );
612 |
613 | # Some boundary checks
614 | if($year < $epoch || $year > 9999) return 0;
615 | if($month < 1 || $month > 12) return 0;
616 | if($day < 1 || $day > $mdays[ $month - 1 ]) return 0;
617 |
618 | # Accumulate the number of days since the epoch.
619 | $days = $day; # Add days for current month
620 | $days += array_sum( array_slice($mdays, 0, $month-1 ) ); # Add days for past months
621 | $days += $range * 365; # Add days for past years
622 | $days += intval( ( $range ) / 4 ); # Add leapdays
623 | $days -= intval( ( $range + $offset ) / 100 ); # Subtract 100 year leapdays
624 | $days += intval( ( $range + $offset + $norm ) / 400 ); # Add 400 year leapdays
625 | $days -= $leap; # Already counted above
626 |
627 | # Adjust for Excel erroneously treating 1900 as a leap year.
628 | if ($days > 59) { $days++;}
629 |
630 | return $days + $seconds;
631 | }
632 | //------------------------------------------------------------------
633 | }
--------------------------------------------------------------------------------