PluginProbe
TablePress – Tables in WordPress made easy / 3.4
TablePress – Tables in WordPress made easy v3.4
3.4 3.3.4 3.3.3 3.3.2 3.3.1 trunk 1.12 1.14 1.9.2 2.0.4 2.1.7 2.1.8 2.2 2.2.1 2.2.2 2.2.3 2.2.4 2.2.5 2.3 2.3.1 2.3.2 2.4 2.4.1 2.4.2 2.4.3 All 45 releases
← All changes | libraries/simplexlsx.class.php +83 -51 2.3.1 → 3.4 View file →
@@ -1,9 +1,9 @@
1 1 <?php
2 2 /**
3 - * Excel 2007-2019/Office 365 Reader Class
3 + * Excel 2007-2019/Office 365 Reader class
4 4 *
5 - * Based on SimpleXLSX v1.0.21 by Sergey Shuchkin.
5 + * Based on SimpleXLSX v1.1.19 by Sergey Shuchkin.
6 6 * @link https://github.com/shuchkin/simplexlsx/
7 7 *
8 8 * @package TablePress
9 9 * @subpackage Import
@@ -15,9 +15,10 @@
15 15
16 16 use SimpleXMLElement;
17 17
18 18 /**
19 - * PHP Excel 2007-2013/Office 365 Reader Class
19 + * PHP Excel 2007-2013/Office 365 Reader class
20 + *
20 21 * @package TablePress
21 22 * @subpackage Import
22 23 * @author Sergey Shuchkin, Tobias Bäthge
23 24 * @since 1.1.0
@@ -159,9 +160,9 @@
159 160
160 161 if ($is_data) {
161 162 $this->package['filename'] = 'default.xlsx';
162 163 $this->package['mtime'] = time();
163 - $this->package['size'] = SimpleXLSX::strlen($filename);
164 + $this->package['size'] = self::strlen($filename);
164 165
165 166 $vZ = $filename;
166 167 } else {
167 168 if (!is_readable($filename)) {
@@ -229,25 +230,44 @@
229 230 $mF = $aP['EFL'];
230 231
231 232 // Special case : value block after the compressed data
232 233 if ($aP['GPF'] & 0x0008) {
233 - $aP1 = unpack('V1CRC/V1CS/V1UCS', SimpleXLSX::substr($vZ, -12));
234 + // Signed ZIP64 descriptor:
235 + // signature + CRC32 + 64-bit compressed size + 64-bit uncompressed size
236 + if (self::substr($vZ, -24, 4) === "\x50\x4b\x07\x08") {
237 + $aP1 = unpack(
238 + 'V1CRC/V1CSLow/V1CSHigh/V1UCSLow/V1UCSHigh',
239 + self::substr($vZ, -20)
240 + );
234 241
235 - $aP['CRC'] = $aP1['CRC'];
236 - $aP['CS'] = $aP1['CS'];
237 - $aP['UCS'] = $aP1['UCS'];
238 - // 2013-08-10
239 - $vZ = SimpleXLSX::substr($vZ, 0, -12);
240 - if (SimpleXLSX::substr($vZ, -4) === "\x50\x4b\x07\x08") {
241 - $vZ = SimpleXLSX::substr($vZ, 0, -4);
242 - }
242 + if ((int)$aP1['CSHigh'] !== 0 || (int)$aP1['UCSHigh'] !== 0) {
243 + $aI['E'] = 6;
244 + $aI['EM'] = 'ZIP64 entry is too large to process.';
245 + }
246 +
247 + $aP['CRC'] = $aP1['CRC'];
248 + $aP['CS'] = $aP1['CSLow'];
249 + $aP['UCS'] = $aP1['UCSLow'];
250 + $vZ = self::substr($vZ, 0, -24);
251 + } else {
252 + $aP1 = unpack('V1CRC/V1CS/V1UCS', self::substr($vZ, -12));
253 +
254 + $aP['CRC'] = $aP1['CRC'];
255 + $aP['CS'] = $aP1['CS'];
256 + $aP['UCS'] = $aP1['UCS'];
257 + // 2013-08-10
258 + $vZ = self::substr($vZ, 0, -12);
259 + if (self::substr($vZ, -4) === "\x50\x4b\x07\x08") {
260 + $vZ = self::substr($vZ, 0, -4);
261 + }
262 + }
243 263 }
244 264
245 265 // Getting stored filename
246 - $aI['N'] = SimpleXLSX::substr($vZ, 26, $nF);
266 + $aI['N'] = self::substr($vZ, 26, $nF);
247 267 $aI['N'] = str_replace('\\', '/', $aI['N']);
248 268
249 - if (SimpleXLSX::substr($aI['N'], -1) === '/') {
269 + if (self::substr($aI['N'], -1) === '/') {
250 270 // is a directory entry - will be skipped
251 271 continue;
252 272 }
253 273
@@ -255,11 +275,11 @@
255 275 $aI['P'] = dirname($aI['N']);
256 276 $aI['P'] = ($aI['P'] === '.') ? '' : $aI['P'];
257 277 $aI['N'] = basename($aI['N']);
258 278
259 - $vZ = SimpleXLSX::substr($vZ, 26 + $nF + $mF);
279 + $vZ = self::substr($vZ, 26 + $nF + $mF);
260 280
261 - if ($aP['CS'] > 0 && (SimpleXLSX::strlen($vZ) !== (int)$aP['CS'])) { // check only if availabled
281 + if ($aP['CS'] > 0 && (self::strlen($vZ) !== (int)$aP['CS'])) { // check only if availabled
262 282 $aI['E'] = 1;
263 283 $aI['EM'] = 'Compressed size is not equal with the value in header information.';
264 284 }
265 285 // } elseif ( $bE ) {
@@ -351,9 +371,9 @@
351 371 // Read relations and search for officeDocument
352 372 if ($relations = $this->getEntryXML('_rels/.rels')) {
353 373 foreach ($relations->Relationship as $rel) {
354 374 $rel_type = basename(trim((string)$rel['Type'])); // officeDocument
355 - $rel_target = SimpleXLSX::getTarget('', (string)$rel['Target']); // /xl/workbook.xml or xl/workbook.xml
375 + $rel_target = self::getTarget('', (string)$rel['Target']); // /xl/workbook.xml or xl/workbook.xml
356 376
357 377 if ($rel_type === 'officeDocument'
358 378 && $workbook = $this->getEntryXML($rel_target)
359 379 ) {
@@ -377,9 +397,9 @@
377 397 if ($workbookRelations = $this->getEntryXML(dirname($rel_target) . '/_rels/workbook.xml.rels')) {
378 398 // Loop relations for workbook and extract sheets...
379 399 foreach ($workbookRelations->Relationship as $workbookRelation) {
380 400 $wrel_type = basename(trim((string)$workbookRelation['Type'])); // worksheet
381 - $wrel_target = SimpleXLSX::getTarget(dirname($rel_target), (string)$workbookRelation['Target']);
401 + $wrel_target = self::getTarget(dirname($rel_target), (string)$workbookRelation['Target']);
382 402 if (!$this->entryExists($wrel_target)) {
383 403 continue;
384 404 }
385 405
@@ -400,9 +420,9 @@
400 420 foreach ($sharedStrings->si as $val) {
401 421 if (isset($val->t)) {
402 422 $this->sharedstrings[] = (string)$val->t;
403 423 } elseif (isset($val->r)) {
404 - $this->sharedstrings[] = SimpleXLSX::parseRichText($val);
424 + $this->sharedstrings[] = self::parseRichText($val);
405 425 }
406 426 }
407 427 }
408 428 } elseif ($wrel_type === 'styles') {
@@ -476,9 +496,10 @@
476 496 $this->deleteEntry($name); // economy memory
477 497 // dirty remove namespace prefixes and empty rows
478 498 $entry_xml = preg_replace('/xmlns[^=]*="[^"]*"/i', '', $entry_xml); // remove namespaces
479 499 $entry_xml .= ' '; // force run garbage collector
480 - $entry_xml = preg_replace('/[a-zA-Z0-9]+:([a-zA-Z0-9]+="[^"]+")/', '$1', $entry_xml); // remove namespaced attrs
500 + // remove namespaced attrs
501 + $entry_xml = preg_replace('/[a-zA-Z0-9]+:([a-zA-Z0-9]+="[^"]+")/', '$1', $entry_xml);
481 502 $entry_xml .= ' ';
482 503 $entry_xml = preg_replace('/<[a-zA-Z0-9]+:([^>]+)>/', '<$1>', $entry_xml); // fix namespaced openned tags
483 504 $entry_xml .= ' ';
484 505 $entry_xml = preg_replace('/<\/[a-zA-Z0-9]+:([^>]+)>/', '</$1>', $entry_xml); // fix namespaced closed tags
@@ -485,8 +506,9 @@
485 506 $entry_xml .= ' ';
486 507
487 508 if (strpos($name, '/sheet')) { // dirty skip empty rows
488 509 // remove <row...> <c /><c /></row>
510 + $cnt = $cnt2 = $cnt3 = null;
489 511 $entry_xml = preg_replace('/<row[^>]+>\s*(<c[^\/]+\/>\s*)+<\/row>/', '', $entry_xml, -1, $cnt);
490 512 $entry_xml .= ' ';
491 513 // remove <row />
492 514 $entry_xml = preg_replace('/<row[^\/>]*\/>/', '', $entry_xml, -1, $cnt2);
@@ -540,12 +562,12 @@
540 562
541 563 public function getEntryData($name)
542 564 {
543 565 $name = ltrim(str_replace('\\', '/', $name), '/');
544 - $dir = SimpleXLSX::strtoupper(dirname($name));
545 - $name = SimpleXLSX::strtoupper(basename($name));
566 + $dir = self::strtoupper(dirname($name));
567 + $name = self::strtoupper(basename($name));
546 568 foreach ($this->package['entries'] as &$entry) {
547 - if (SimpleXLSX::strtoupper($entry['path']) === $dir && SimpleXLSX::strtoupper($entry['name']) === $name) {
569 + if (self::strtoupper($entry['path']) === $dir && self::strtoupper($entry['name']) === $name) {
548 570 if ($entry['error']) {
549 571 return false;
550 572 }
551 573 switch ($entry['cm']) {
@@ -572,9 +594,9 @@
572 594 $entry['cm'] = -1;
573 595 if ($entry['data'] === false) {
574 596 $entry['error'] = 2;
575 597 $entry['error_msg'] = 'Decompression of data failed.';
576 - } elseif ($entry['ucs'] > 0 && (SimpleXLSX::strlen($entry['data']) !== (int)$entry['ucs'])) {
598 + } elseif ($entry['ucs'] > 0 && (self::strlen($entry['data']) !== (int)$entry['ucs'])) {
577 599 $entry['error'] = 3;
578 600 $entry['error_msg'] = 'Uncompressed size is not equal with the value in header information.';
579 601 } elseif (crc32($entry['data']) !== $entry['crc']) {
580 602 $entry['error'] = 4;
@@ -592,12 +614,12 @@
592 614 }
593 615 public function deleteEntry($name)
594 616 {
595 617 $name = ltrim(str_replace('\\', '/', $name), '/');
596 - $dir = SimpleXLSX::strtoupper(dirname($name));
597 - $name = SimpleXLSX::strtoupper(basename($name));
618 + $dir = self::strtoupper(dirname($name));
619 + $name = self::strtoupper(basename($name));
598 620 foreach ($this->package['entries'] as $k => $entry) {
599 - if (SimpleXLSX::strtoupper($entry['path']) === $dir && SimpleXLSX::strtoupper($entry['name']) === $name) {
621 + if (self::strtoupper($entry['path']) === $dir && self::strtoupper($entry['name']) === $name) {
600 622 unset($this->package['entries'][$k]);
601 623 return true;
602 624 }
603 625 }
@@ -616,12 +638,12 @@
616 638
617 639 public function entryExists($name)
618 640 {
619 641 // 0.6.6
620 - $dir = SimpleXLSX::strtoupper(dirname($name));
621 - $name = SimpleXLSX::strtoupper(basename($name));
642 + $dir = self::strtoupper(dirname($name));
643 + $name = self::strtoupper(basename($name));
622 644 foreach ($this->package['entries'] as $entry) {
623 - if (SimpleXLSX::strtoupper($entry['path']) === $dir && SimpleXLSX::strtoupper($entry['name']) === $name) {
645 + if (self::strtoupper($entry['path']) === $dir && self::strtoupper($entry['name']) === $name) {
624 646 return true;
625 647 }
626 648 }
627 649
@@ -708,9 +730,9 @@
708 730 /* @var SimpleXMLElement $ws */
709 731
710 732 $ref = (string)$ws->dimension['ref'];
711 733
712 - if (SimpleXLSX::strpos($ref, ':') !== false) {
734 + if (self::strpos($ref, ':') !== false) {
713 735 $d = explode(':', $ref);
714 736 $idx = $this->getIndex($d[1]);
715 737
716 738 return [$idx[0] + 1, $idx[1] + 1];
@@ -756,14 +778,15 @@
756 778 }
757 779
758 780 public function getIndex($cell = 'A1')
759 781 {
782 + $m = null;
760 783
761 784 if (preg_match('/([A-Z]+)(\d+)/', $cell, $m)) {
762 785 $col = $m[1];
763 786 $row = $m[2];
764 787
765 - $colLen = SimpleXLSX::strlen($col);
788 + $colLen = self::strlen($col);
766 789 $index = 0;
767 790
768 791 for ($i = $colLen - 1; $i >= 0; $i--) {
769 792 $index += (ord($col[$i]) - 64) * pow(26, $colLen - $i - 1);
@@ -786,9 +809,9 @@
786 809 $s = (int)$cell['s'];
787 810 if ($s > 0 && isset($this->cellFormats[$s])) {
788 811 if (array_key_exists('format', $this->cellFormats[$s])) {
789 812 $format = $this->cellFormats[$s]['format'];
790 - if (preg_match('/[mM]/', preg_replace('/\"[^"]+\"/', '', $format))) { // [mm]onth,AM|PM
813 + if ($format && preg_match('/[mM]/', preg_replace('/\"[^"]+\"/', '', $format))) { // [mm]onth,AM|PM
791 814 $dataType = 'D';
792 815 }
793 816 } else {
794 817 $dataType = 'n';
@@ -813,22 +836,15 @@
813 836 break;
814 837
815 838 case 'b':
816 839 // Value is boolean
817 - $value = (string)$cell->v;
818 - if ($value === '0') {
819 - $value = false;
820 - } elseif ($value === '1') {
821 - $value = true;
822 - } else {
823 - $value = (bool)$cell->v;
824 - }
840 + $value = self::boolean((string)$cell->v);
825 841
826 842 break;
827 843
828 844 case 'inlineStr':
829 845 // Value is rich text inline
830 - $value = SimpleXLSX::parseRichText($cell->is);
846 + $value = self::parseRichText($cell->is);
831 847
832 848 break;
833 849
834 850 case 'e':
@@ -840,9 +856,10 @@
840 856
841 857 case 'D':
842 858 // Date as float
843 859 if (!empty($cell->v)) {
844 - $value = $this->datetimeFormat ? gmdate($this->datetimeFormat, $this->unixstamp((float)$cell->v)) : (float)$cell->v;
860 + $value = $this->datetimeFormat ?
861 + gmdate($this->datetimeFormat, $this->unixstamp((float)$cell->v)) : (float)$cell->v;
845 862 }
846 863 break;
847 864
848 865 case 'd':
@@ -916,9 +933,12 @@
916 933
917 934 if ($x === 0 && $c['height']) {
918 935 $css .= 'height: '.round($c['height'] * 1.3333).'px;';
919 936 }
920 - $s .= '<'.$tag.' style="'.$css.'" nowrap>' . ($c['value'] === '' ? '&nbsp' : htmlspecialchars($c['value'], ENT_QUOTES)) . '</'.$tag.'>';
937 + $v = htmlspecialchars($c['value'], ENT_QUOTES);
938 + $v = preg_replace('/\R/', "<br>\r\n", $v);
939 + $s .= '<'.$tag.' style="'.$css.'" nowrap>'
940 + . ($v === '' ? '&nbsp' : $v) . '</'.$tag.'>';
921 941 $x++;
922 942 }
923 943 $s .= "</tr>\r\n";
924 944 $y++;
@@ -1030,9 +1050,9 @@
1030 1050 if (($ws = $this->worksheet($worksheetIndex)) === false) {
1031 1051 return false;
1032 1052 }
1033 1053 if (is_array($cell)) {
1034 - $cell = SimpleXLSX::num2name($cell[0]) . $cell[1];// [3,21] -> D21
1054 + $cell = self::num2name($cell[0]) . $cell[1];// [3,21] -> D21
1035 1055 }
1036 1056 if (is_string($cell)) {
1037 1057 $result = $ws->sheetData->xpath("row/c[@r='" . $cell . "']");
1038 1058 if (count($result)) {
@@ -1079,9 +1099,10 @@
1079 1099 return isset($this->sheetMetaData[$worksheetIndex]) ? $this->sheetMetaData[$worksheetIndex] : false;
1080 1100 }
1081 1101 public function isHiddenSheet($worksheetIndex)
1082 1102 {
1083 - return isset($this->sheetMetaData[$worksheetIndex]['state']) && $this->sheetMetaData[$worksheetIndex]['state'] === 'hidden';
1103 + return isset($this->sheetMetaData[$worksheetIndex]['state'])
1104 + && $this->sheetMetaData[$worksheetIndex]['state'] === 'hidden';
1084 1105 }
1085 1106
1086 1107 public function getStyles()
1087 1108 {
@@ -1101,9 +1122,9 @@
1101 1122 public static function getTarget($base, $target)
1102 1123 {
1103 1124 $target = trim($target);
1104 1125 if (strpos($target, '/') === 0) {
1105 - return SimpleXLSX::substr($target, 1);
1126 + return self::substr($target, 1);
1106 1127 }
1107 1128 $target = ($base ? $base . '/' : '') . $target;
1108 1129 // a/b/../c -> a/c
1109 1130 $parts = explode('/', $target);
@@ -1141,9 +1162,9 @@
1141 1162 $numeric = ($num - 1) % 26;
1142 1163 $letter = chr(65 + $numeric);
1143 1164 $num2 = (int)(($num - 1) / 26);
1144 1165 if ($num2 > 0) {
1145 - return SimpleXLSX::num2name($num2) . $letter;
1166 + return self::num2name($num2) . $letter;
1146 1167 }
1147 1168 return $letter;
1148 1169 }
1149 1170
@@ -1153,12 +1174,23 @@
1153 1174 }
1154 1175
1155 1176 public static function substr($str, $start, $length = null)
1156 1177 {
1157 - return (ini_get('mbstring.func_overload') & 2) ? mb_substr($str, $start, ($length === null) ? mb_strlen($str, '8bit') : $length, '8bit') : substr($str, $start, ($length === null) ? strlen($str) : $length);
1178 + return (ini_get('mbstring.func_overload') & 2) ?
1179 + mb_substr($str, $start, ($length === null) ? mb_strlen($str, '8bit') : $length, '8bit')
1180 + : substr($str, $start, ($length === null) ? strlen($str) : $length);
1158 1181 }
1159 1182
1160 1183 public static function strpos($haystack, $needle, $offset = 0)
1161 1184 {
1162 - return (ini_get('mbstring.func_overload') & 2) ? mb_strpos($haystack, $needle, $offset, '8bit') : strpos($haystack, $needle, $offset);
1185 + return (ini_get('mbstring.func_overload') & 2) ?
1186 + mb_strpos($haystack, $needle, $offset, '8bit') : strpos($haystack, $needle, $offset);
1187 + }
1188 + public static function boolean($value)
1189 + {
1190 + if (is_numeric($value)) {
1191 + return (bool) $value;
1192 + }
1193 +
1194 + return $value === 'true' || $value === 'TRUE';
1163 1195 }
1164 1196 }