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