PluginProbe
TablePress – Tables in WordPress made easy / 3.0
TablePress – Tables in WordPress made easy v3.0
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 2.4.4 All 44 releases
← All changes | libraries/simplexlsx.class.php +132 -165 2.33.0 View file →
@@ -1,9 +1,9 @@
1 1 <?php
2 2 /**
3 3 * Excel 2007-2019/Office 365 Reader Class
4 4 *
5 - * Based on SimpleXLSX v1.0.19 by Sergey Shuchkin.
5 + * Based on SimpleXLSX v1.0.21 by Sergey Shuchkin.
6 6 * @link https://github.com/shuchkin/simplexlsx/
7 7 *
8 8 * @package TablePress
9 9 * @subpackage Import
@@ -78,18 +78,18 @@
78 78 public $activeSheet = 0;
79 79 public $rowsExReader;
80 80
81 81 /* @var SimpleXMLElement[] $sheets */
82 - protected $sheets;
83 - protected $sheetFiles = [];
84 - protected $sheetMetaData = [];
82 + public $sheets;
83 + public $sheetFiles = [];
84 + public $sheetMetaData = [];
85 + public $sheetRels = [];
85 86 // scheme
86 87 public $styles;
87 - protected $hyperlinks;
88 88 /* @var array[] $package */
89 - protected $package;
90 - protected $sharedstrings;
91 - protected $date1904 = 0;
89 + public $package;
90 + public $sharedstrings;
91 + public $date1904 = 0;
92 92
93 93
94 94 /*
95 95 private $date_formats = array(
@@ -128,10 +128,10 @@
128 128 0x2c => '$%1.2f', //"$#,##0.00;($#,##0.00)",
129 129 0x30 => '%1.0f'); //"##0.0E0";
130 130 // }}}
131 131 */
132 - protected $errno = 0;
133 - protected $error = false;
132 + public $errno = 0;
133 + public $error = false;
134 134 /**
135 135 * @var false|SimpleXMLElement
136 136 */
137 137 public $theme;
@@ -148,20 +148,20 @@
148 148 'size' => 0,
149 149 'comment' => '',
150 150 'entries' => []
151 151 ];
152 - if ($filename && $this->_unzip($filename, $is_data)) {
153 - $this->_parse();
152 + if ($filename && $this->unzip($filename, $is_data)) {
153 + $this->parseEntries();
154 154 }
155 155 }
156 156
157 - protected function _unzip($filename, $is_data = false)
157 + public function unzip($filename, $is_data = false)
158 158 {
159 159
160 160 if ($is_data) {
161 161 $this->package['filename'] = 'default.xlsx';
162 162 $this->package['mtime'] = time();
163 - $this->package['size'] = $this->_strlen($filename);
163 + $this->package['size'] = SimpleXLSX::strlen($filename);
164 164
165 165 $vZ = $filename;
166 166 } else {
167 167 if (!is_readable($filename)) {
@@ -229,25 +229,25 @@
229 229 $mF = $aP['EFL'];
230 230
231 231 // Special case : value block after the compressed data
232 232 if ($aP['GPF'] & 0x0008) {
233 - $aP1 = unpack('V1CRC/V1CS/V1UCS', $this->_substr($vZ, -12));
233 + $aP1 = unpack('V1CRC/V1CS/V1UCS', SimpleXLSX::substr($vZ, -12));
234 234
235 235 $aP['CRC'] = $aP1['CRC'];
236 236 $aP['CS'] = $aP1['CS'];
237 237 $aP['UCS'] = $aP1['UCS'];
238 238 // 2013-08-10
239 - $vZ = $this->_substr($vZ, 0, -12);
240 - if ($this->_substr($vZ, -4) === "\x50\x4b\x07\x08") {
241 - $vZ = $this->_substr($vZ, 0, -4);
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 }
243 243 }
244 244
245 245 // Getting stored filename
246 - $aI['N'] = $this->_substr($vZ, 26, $nF);
246 + $aI['N'] = SimpleXLSX::substr($vZ, 26, $nF);
247 247 $aI['N'] = str_replace('\\', '/', $aI['N']);
248 248
249 - if ($this->_substr($aI['N'], -1) === '/') {
249 + if (SimpleXLSX::substr($aI['N'], -1) === '/') {
250 250 // is a directory entry - will be skipped
251 251 continue;
252 252 }
253 253
@@ -255,11 +255,11 @@
255 255 $aI['P'] = dirname($aI['N']);
256 256 $aI['P'] = ($aI['P'] === '.') ? '' : $aI['P'];
257 257 $aI['N'] = basename($aI['N']);
258 258
259 - $vZ = $this->_substr($vZ, 26 + $nF + $mF);
259 + $vZ = SimpleXLSX::substr($vZ, 26 + $nF + $mF);
260 260
261 - if ($aP['CS'] > 0 && ($this->_strlen($vZ) !== (int)$aP['CS'])) { // check only if availabled
261 + if ($aP['CS'] > 0 && (SimpleXLSX::strlen($vZ) !== (int)$aP['CS'])) { // check only if availabled
262 262 $aI['E'] = 1;
263 263 $aI['EM'] = 'Compressed size is not equal with the value in header information.';
264 264 }
265 265 // } elseif ( $bE ) {
@@ -326,12 +326,8 @@
326 326
327 327 return true;
328 328 }
329 329
330 - protected function _strlen($str)
331 - {
332 - return (ini_get('mbstring.func_overload') & 2) ? mb_strlen($str, '8bit') : strlen($str);
333 - }
334 330
335 331 public function error($num = null, $str = null)
336 332 {
337 333 if ($num) {
@@ -344,15 +340,10 @@
344 340
345 341 return $this->error;
346 342 }
347 343
348 - protected function _substr($str, $start, $length = null)
344 + public function parseEntries()
349 345 {
350 - 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);
351 - }
352 -
353 - protected function _parse()
354 - {
355 346 // Document data holders
356 347 $this->sharedstrings = [];
357 348 $this->sheets = [];
358 349 // $this->styles = array();
@@ -360,11 +351,13 @@
360 351 // Read relations and search for officeDocument
361 352 if ($relations = $this->getEntryXML('_rels/.rels')) {
362 353 foreach ($relations->Relationship as $rel) {
363 354 $rel_type = basename(trim((string)$rel['Type'])); // officeDocument
364 - $rel_target = $this->_getTarget('', (string)$rel['Target']); // /xl/workbook.xml or xl/workbook.xml
355 + $rel_target = SimpleXLSX::getTarget('', (string)$rel['Target']); // /xl/workbook.xml or xl/workbook.xml
365 356
366 - if ($rel_type === 'officeDocument' && $workbook = $this->getEntryXML($rel_target)) {
357 + if ($rel_type === 'officeDocument'
358 + && $workbook = $this->getEntryXML($rel_target)
359 + ) {
367 360 $index_rId = []; // [0 => rId1]
368 361
369 362 $index = 0;
370 363 foreach ($workbook->sheets->sheet as $s) {
@@ -384,32 +377,37 @@
384 377 if ($workbookRelations = $this->getEntryXML(dirname($rel_target) . '/_rels/workbook.xml.rels')) {
385 378 // Loop relations for workbook and extract sheets...
386 379 foreach ($workbookRelations->Relationship as $workbookRelation) {
387 380 $wrel_type = basename(trim((string)$workbookRelation['Type'])); // worksheet
388 - $wrel_path = $this->_getTarget(dirname($rel_target), (string)$workbookRelation['Target']);
389 - if (!$this->entryExists($wrel_path)) {
381 + $wrel_target = SimpleXLSX::getTarget(dirname($rel_target), (string)$workbookRelation['Target']);
382 + if (!$this->entryExists($wrel_target)) {
390 383 continue;
391 384 }
392 385
393 -
394 386 if ($wrel_type === 'worksheet') { // Sheets
395 - if ($sheet = $this->getEntryXML($wrel_path)) {
387 + if ($sheet = $this->getEntryXML($wrel_target)) {
396 388 $index = array_search((string)$workbookRelation['Id'], $index_rId, true);
397 389 $this->sheets[$index] = $sheet;
398 - $this->sheetFiles[$index] = $wrel_path;
390 + $this->sheetFiles[$index] = $wrel_target;
391 + $srel_d = dirname($wrel_target);
392 + $srel_f = basename($wrel_target);
393 + $srel_file = $srel_d . '/_rels/' . $srel_f . '.rels';
394 + if ($this->entryExists($srel_file)) {
395 + $this->sheetRels[$index] = $this->getEntryXML($srel_file);
396 + }
399 397 }
400 398 } elseif ($wrel_type === 'sharedStrings') {
401 - if ($sharedStrings = $this->getEntryXML($wrel_path)) {
399 + if ($sharedStrings = $this->getEntryXML($wrel_target)) {
402 400 foreach ($sharedStrings->si as $val) {
403 401 if (isset($val->t)) {
404 402 $this->sharedstrings[] = (string)$val->t;
405 403 } elseif (isset($val->r)) {
406 - $this->sharedstrings[] = $this->_parseRichText($val);
404 + $this->sharedstrings[] = SimpleXLSX::parseRichText($val);
407 405 }
408 406 }
409 407 }
410 408 } elseif ($wrel_type === 'styles') {
411 - $this->styles = $this->getEntryXML($wrel_path);
409 + $this->styles = $this->getEntryXML($wrel_target);
412 410
413 411 // number formats
414 412 $this->nf = [];
415 413 if (isset($this->styles->numFmts->numFmt)) {
@@ -438,20 +436,24 @@
438 436 $this->cellFormats[] = $x;
439 437 }
440 438 }
441 439 } elseif ($wrel_type === 'theme') {
442 - $this->theme = $this->getEntryXML($wrel_path);
440 + $this->theme = $this->getEntryXML($wrel_target);
443 441 }
444 442 }
445 443
446 - break;
444 +// break;
447 445 }
448 446 // reptile hack :: find active sheet from workbook.xml
449 - foreach ($workbook->bookViews->workbookView as $s) {
450 - if (!empty($s['activeTab'])) {
451 - $this->activeSheet = (int)$s['activeTab'];
447 + if ($workbook->bookViews->workbookView) {
448 + foreach ($workbook->bookViews->workbookView as $v) {
449 + if (!empty($v['activeTab'])) {
450 + $this->activeSheet = (int)$v['activeTab'];
451 + }
452 452 }
453 453 }
454 +
455 + break;
454 456 }
455 457 }
456 458 }
457 459
@@ -538,12 +540,12 @@
538 540
539 541 public function getEntryData($name)
540 542 {
541 543 $name = ltrim(str_replace('\\', '/', $name), '/');
542 - $dir = $this->_strtoupper(dirname($name));
543 - $name = $this->_strtoupper(basename($name));
544 + $dir = SimpleXLSX::strtoupper(dirname($name));
545 + $name = SimpleXLSX::strtoupper(basename($name));
544 546 foreach ($this->package['entries'] as &$entry) {
545 - if ($this->_strtoupper($entry['path']) === $dir && $this->_strtoupper($entry['name']) === $name) {
547 + if (SimpleXLSX::strtoupper($entry['path']) === $dir && SimpleXLSX::strtoupper($entry['name']) === $name) {
546 548 if ($entry['error']) {
547 549 return false;
548 550 }
549 551 switch ($entry['cm']) {
@@ -570,9 +572,9 @@
570 572 $entry['cm'] = -1;
571 573 if ($entry['data'] === false) {
572 574 $entry['error'] = 2;
573 575 $entry['error_msg'] = 'Decompression of data failed.';
574 - } elseif ($entry['ucs'] > 0 && ($this->_strlen($entry['data']) !== (int)$entry['ucs'])) {
576 + } elseif ($entry['ucs'] > 0 && (SimpleXLSX::strlen($entry['data']) !== (int)$entry['ucs'])) {
575 577 $entry['error'] = 3;
576 578 $entry['error_msg'] = 'Uncompressed size is not equal with the value in header information.';
577 579 } elseif (crc32($entry['data']) !== $entry['crc']) {
578 580 $entry['error'] = 4;
@@ -590,12 +592,12 @@
590 592 }
591 593 public function deleteEntry($name)
592 594 {
593 595 $name = ltrim(str_replace('\\', '/', $name), '/');
594 - $dir = $this->_strtoupper(dirname($name));
595 - $name = $this->_strtoupper(basename($name));
596 + $dir = SimpleXLSX::strtoupper(dirname($name));
597 + $name = SimpleXLSX::strtoupper(basename($name));
596 598 foreach ($this->package['entries'] as $k => $entry) {
597 - if ($this->_strtoupper($entry['path']) === $dir && $this->_strtoupper($entry['name']) === $name) {
599 + if (SimpleXLSX::strtoupper($entry['path']) === $dir && SimpleXLSX::strtoupper($entry['name']) === $name) {
598 600 unset($this->package['entries'][$k]);
599 601 return true;
600 602 }
601 603 }
@@ -601,36 +603,13 @@
601 603 }
602 604 return false;
603 605 }
604 606
605 - protected function _strtoupper($str)
607 + public static function strtoupper($str)
606 608 {
607 609 return (ini_get('mbstring.func_overload') & 2) ? mb_strtoupper($str, '8bit') : strtoupper($str);
608 610 }
609 611
610 - protected function _getTarget($base, $target)
611 - {
612 - $target = trim($target);
613 - if (strpos($target, '/') === 0) {
614 - return $this->_substr($target, 1);
615 - }
616 - $target = ($base ? $base . '/' : '') . $target;
617 - // a/b/../c -> a/c
618 - $parts = explode('/', $target);
619 - $abs = [];
620 - foreach ($parts as $p) {
621 - if ('.' === $p) {
622 - continue;
623 - }
624 - if ('..' === $p) {
625 - array_pop($abs);
626 - } else {
627 - $abs[] = $p;
628 - }
629 - }
630 - return implode('/', $abs);
631 - }
632 -
633 612 /*
634 613 * @param string $name Filename in archive
635 614 * @return SimpleXMLElement|bool
636 615 */
@@ -637,12 +616,12 @@
637 616
638 617 public function entryExists($name)
639 618 {
640 619 // 0.6.6
641 - $dir = $this->_strtoupper(dirname($name));
642 - $name = $this->_strtoupper(basename($name));
620 + $dir = SimpleXLSX::strtoupper(dirname($name));
621 + $name = SimpleXLSX::strtoupper(basename($name));
643 622 foreach ($this->package['entries'] as $entry) {
644 - if ($this->_strtoupper($entry['path']) === $dir && $this->_strtoupper($entry['name']) === $name) {
623 + if (SimpleXLSX::strtoupper($entry['path']) === $dir && SimpleXLSX::strtoupper($entry['name']) === $name) {
645 624 return true;
646 625 }
647 626 }
648 627
@@ -648,23 +627,8 @@
648 627
649 628 return false;
650 629 }
651 630
652 - protected function _parseRichText($is = null)
653 - {
654 - $value = [];
655 -
656 - if (isset($is->t)) {
657 - $value[] = (string)$is->t;
658 - } elseif (isset($is->r)) {
659 - foreach ($is->r as $run) {
660 - $value[] = (string)$run->t;
661 - }
662 - }
663 -
664 - return implode('', $value);
665 - }
666 -
667 631 public static function parseFile($filename, $debug = false)
668 632 {
669 633 return self::parse($filename, false, $debug);
670 634 }
@@ -672,10 +636,10 @@
672 636 public static function parse($filename, $is_data = false, $debug = false)
673 637 {
674 638 $xlsx = new self();
675 639 $xlsx->debug = $debug;
676 - if ($xlsx->_unzip($filename, $is_data)) {
677 - $xlsx->_parse();
640 + if ($xlsx->unzip($filename, $is_data)) {
641 + $xlsx->parseEntries();
678 642 }
679 643 if ($xlsx->success()) {
680 644 return $xlsx;
681 645 }
@@ -719,49 +683,10 @@
719 683
720 684
721 685 public function worksheet($worksheetIndex = 0)
722 686 {
723 -
724 -
725 687 if (isset($this->sheets[$worksheetIndex])) {
726 - $ws = $this->sheets[$worksheetIndex];
727 -
728 - if (!isset($this->hyperlinks[$worksheetIndex]) && isset($ws->hyperlinks)) {
729 - $this->hyperlinks[$worksheetIndex] = [];
730 - $sheet_rels = str_replace('worksheets', 'worksheets/_rels', $this->sheetFiles[$worksheetIndex]) . '.rels';
731 - $link_ids = [];
732 -
733 - if ($rels = $this->getEntryXML($sheet_rels)) {
734 - // hyperlink
735 -// $rel_base = dirname( $sheet_rels );
736 - foreach ($rels->Relationship as $rel) {
737 - $rel_type = basename(trim((string)$rel['Type']));
738 - if ($rel_type === 'hyperlink') {
739 - $rel_id = (string)$rel['Id'];
740 - $rel_target = (string)$rel['Target'];
741 - $link_ids[$rel_id] = $rel_target;
742 - }
743 - }
744 - }
745 - foreach ($ws->hyperlinks->hyperlink as $hyperlink) {
746 - $ref = (string)$hyperlink['ref'];
747 - if ($this->_strpos($ref, ':') > 0) { // A1:A8 -> A1
748 - $ref = explode(':', $ref);
749 - $ref = $ref[0];
750 - }
751 -// $this->hyperlinks[ $worksheetIndex ][ $ref ] = (string) $hyperlink['display'];
752 - $loc = (string)$hyperlink['location'];
753 - $id = (string)$hyperlink['id'];
754 - if ($id) {
755 - $href = $link_ids[$id] . ($loc ? '#' . $loc : '');
756 - } else {
757 - $href = $loc;
758 - }
759 - $this->hyperlinks[$worksheetIndex][$ref] = $href;
760 - }
761 - }
762 -
763 - return $ws;
688 + return $this->sheets[$worksheetIndex];
764 689 }
765 690 $this->error(6, 'Worksheet not found ' . $worksheetIndex);
766 691
767 692 return false;
@@ -766,13 +691,8 @@
766 691
767 692 return false;
768 693 }
769 694
770 - protected function _strpos($haystack, $needle, $offset = 0)
771 - {
772 - return (ini_get('mbstring.func_overload') & 2) ? mb_strpos($haystack, $needle, $offset, '8bit') : strpos($haystack, $needle, $offset);
773 - }
774 -
775 695 /**
776 696 * returns [numCols,numRows] of worksheet
777 697 *
778 698 * @param int $worksheetIndex
@@ -788,9 +708,9 @@
788 708 /* @var SimpleXMLElement $ws */
789 709
790 710 $ref = (string)$ws->dimension['ref'];
791 711
792 - if ($this->_strpos($ref, ':') !== false) {
712 + if (SimpleXLSX::strpos($ref, ':') !== false) {
793 713 $d = explode(':', $ref);
794 714 $idx = $this->getIndex($d[1]);
795 715
796 716 return [$idx[0] + 1, $idx[1] + 1];
@@ -841,9 +761,9 @@
841 761 if (preg_match('/([A-Z]+)(\d+)/', $cell, $m)) {
842 762 $col = $m[1];
843 763 $row = $m[2];
844 764
845 - $colLen = $this->_strlen($col);
765 + $colLen = SimpleXLSX::strlen($col);
846 766 $index = 0;
847 767
848 768 for ($i = $colLen - 1; $i >= 0; $i--) {
849 769 $index += (ord($col[$i]) - 64) * pow(26, $colLen - $i - 1);
@@ -866,9 +786,9 @@
866 786 $s = (int)$cell['s'];
867 787 if ($s > 0 && isset($this->cellFormats[$s])) {
868 788 if (array_key_exists('format', $this->cellFormats[$s])) {
869 789 $format = $this->cellFormats[$s]['format'];
870 - if (preg_match('/[mM]/', preg_replace('/\"[^"]+\"/', '', $format))) { // [mm]onth,AM|PM
790 + if ($format && preg_match('/[mM]/', preg_replace('/\"[^"]+\"/', '', $format))) { // [mm]onth,AM|PM
871 791 $dataType = 'D';
872 792 }
873 793 } else {
874 794 $dataType = 'n';
@@ -906,9 +826,9 @@
906 826 break;
907 827
908 828 case 'inlineStr':
909 829 // Value is rich text inline
910 - $value = $this->_parseRichText($cell->is);
830 + $value = SimpleXLSX::parseRichText($cell->is);
911 831
912 832 break;
913 833
914 834 case 'e':
@@ -964,14 +884,8 @@
964 884
965 885 return (int)$t;
966 886 }
967 887
968 - public function href($worksheetIndex, $cell)
969 - {
970 - $ref = (string)$cell['r'];
971 - return isset($this->hyperlinks[$worksheetIndex][$ref]) ? $this->hyperlinks[$worksheetIndex][$ref] : '';
972 - }
973 -
974 888 public function toHTML($worksheetIndex = 0)
975 889 {
976 890 $s = '<table class=excel>';
977 891 foreach ($this->readRows($worksheetIndex) as $r) {
@@ -1116,9 +1030,9 @@
1116 1030 if (($ws = $this->worksheet($worksheetIndex)) === false) {
1117 1031 return false;
1118 1032 }
1119 1033 if (is_array($cell)) {
1120 - $cell = $this->_num2name($cell[0]) . $cell[1];// [3,21] -> D21
1034 + $cell = SimpleXLSX::num2name($cell[0]) . $cell[1];// [3,21] -> D21
1121 1035 }
1122 1036 if (is_string($cell)) {
1123 1037 $result = $ws->sheetData->xpath("row/c[@r='" . $cell . "']");
1124 1038 if (count($result)) {
@@ -1128,19 +1042,8 @@
1128 1042
1129 1043 return null;
1130 1044 }
1131 1045
1132 - protected function _num2name($num)
1133 - {
1134 - $numeric = ($num - 1) % 26;
1135 - $letter = chr(65 + $numeric);
1136 - $num2 = (int)(($num - 1) / 26);
1137 - if ($num2 > 0) {
1138 - return $this->_num2name($num2) . $letter;
1139 - }
1140 - return $letter;
1141 - }
1142 -
1143 1046 public function getSheets()
1144 1047 {
1145 1048 return $this->sheets;
1146 1049 }
@@ -1192,6 +1095,70 @@
1192 1095
1193 1096 public function setDateTimeFormat($value)
1194 1097 {
1195 1098 $this->datetimeFormat = is_string($value) ? $value : false;
1099 + }
1100 +
1101 + public static function getTarget($base, $target)
1102 + {
1103 + $target = trim($target);
1104 + if (strpos($target, '/') === 0) {
1105 + return SimpleXLSX::substr($target, 1);
1106 + }
1107 + $target = ($base ? $base . '/' : '') . $target;
1108 + // a/b/../c -> a/c
1109 + $parts = explode('/', $target);
1110 + $abs = [];
1111 + foreach ($parts as $p) {
1112 + if ('.' === $p) {
1113 + continue;
1114 + }
1115 + if ('..' === $p) {
1116 + array_pop($abs);
1117 + } else {
1118 + $abs[] = $p;
1119 + }
1120 + }
1121 + return implode('/', $abs);
1122 + }
1123 +
1124 + public static function parseRichText($is = null)
1125 + {
1126 + $value = [];
1127 +
1128 + if (isset($is->t)) {
1129 + $value[] = (string)$is->t;
1130 + } elseif (isset($is->r)) {
1131 + foreach ($is->r as $run) {
1132 + $value[] = (string)$run->t;
1133 + }
1134 + }
1135 +
1136 + return implode('', $value);
1137 + }
1138 +
1139 + public static function num2name($num)
1140 + {
1141 + $numeric = ($num - 1) % 26;
1142 + $letter = chr(65 + $numeric);
1143 + $num2 = (int)(($num - 1) / 26);
1144 + if ($num2 > 0) {
1145 + return SimpleXLSX::num2name($num2) . $letter;
1146 + }
1147 + return $letter;
1148 + }
1149 +
1150 + public static function strlen($str)
1151 + {
1152 + return (ini_get('mbstring.func_overload') & 2) ? mb_strlen($str, '8bit') : strlen($str);
1153 + }
1154 +
1155 + public static function substr($str, $start, $length = null)
1156 + {
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);
1158 + }
1159 +
1160 + public static function strpos($haystack, $needle, $offset = 0)
1161 + {
1162 + return (ini_get('mbstring.func_overload') & 2) ? mb_strpos($haystack, $needle, $offset, '8bit') : strpos($haystack, $needle, $offset);
1196 1163 }
1197 1164 }