From 47d7260c437921913cc7f6c85716f415df10409d Mon Sep 17 00:00:00 2001 From: Alex Milde Date: Thu, 16 Feb 2017 01:42:07 +0100 Subject: [PATCH 1/5] Ignore images with missing data when reading xlsx Ignore images with missing data when reading xlsx Fixes #94, closes #95 --- src/PhpSpreadsheet/Reader/Xlsx.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/PhpSpreadsheet/Reader/Xlsx.php b/src/PhpSpreadsheet/Reader/Xlsx.php index cb787e67..fa100980 100644 --- a/src/PhpSpreadsheet/Reader/Xlsx.php +++ b/src/PhpSpreadsheet/Reader/Xlsx.php @@ -1484,6 +1484,11 @@ class Xlsx extends BaseReader implements IReader foreach ($shapes as $idx => $shape) { $shape->registerXPathNamespace('v', 'urn:schemas-microsoft-com:vml'); $imageData = $shape->xpath('//v:imagedata'); + + if (!$imageData) { + continue; + } + $imageData = $imageData[$idx]; $imageData = $imageData->attributes('urn:schemas-microsoft-com:office:office'); From ce8ba1fa66a714dda2d38cc51e1d21bdebfce5d8 Mon Sep 17 00:00:00 2001 From: Adrien Crivelli Date: Thu, 16 Feb 2017 10:42:54 +0900 Subject: [PATCH 2/5] Drop obsolete PHP 5.2 specific code --- src/PhpSpreadsheet/Shared/File.php | 34 ------------------------------ 1 file changed, 34 deletions(-) diff --git a/src/PhpSpreadsheet/Shared/File.php b/src/PhpSpreadsheet/Shared/File.php index e536fd12..8d0f1a59 100644 --- a/src/PhpSpreadsheet/Shared/File.php +++ b/src/PhpSpreadsheet/Shared/File.php @@ -142,40 +142,6 @@ class File } } - // sys_get_temp_dir is only available since PHP 5.2.1 - // http://php.net/manual/en/function.sys-get-temp-dir.php#94119 - if (!function_exists('sys_get_temp_dir')) { - if ($temp = getenv('TMP')) { - if ((!empty($temp)) && (file_exists($temp))) { - return realpath($temp); - } - } - if ($temp = getenv('TEMP')) { - if ((!empty($temp)) && (file_exists($temp))) { - return realpath($temp); - } - } - if ($temp = getenv('TMPDIR')) { - if ((!empty($temp)) && (file_exists($temp))) { - return realpath($temp); - } - } - - // trick for creating a file in system's temporary dir - // without knowing the path of the system's temporary dir - $temp = tempnam(__FILE__, ''); - if (file_exists($temp)) { - unlink($temp); - - return realpath(dirname($temp)); - } - - return null; - } - - // use ordinary built-in PHP function - // There should be no problem with the 5.2.4 Suhosin realpath() bug, because this line should only - // be called if we're running 5.2.1 or earlier return realpath(sys_get_temp_dir()); } From 4ae95e5f7c66ae1830b3acba319164b976f5df09 Mon Sep 17 00:00:00 2001 From: Adrien Crivelli Date: Thu, 16 Feb 2017 11:01:35 +0900 Subject: [PATCH 3/5] Drop obsolete method check existence --- src/PhpSpreadsheet/Chart/DataSeriesValues.php | 2 +- src/PhpSpreadsheet/Shared/XMLWriter.php | 10 +++------- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/PhpSpreadsheet/Chart/DataSeriesValues.php b/src/PhpSpreadsheet/Chart/DataSeriesValues.php index b752c3c2..d1e92df1 100644 --- a/src/PhpSpreadsheet/Chart/DataSeriesValues.php +++ b/src/PhpSpreadsheet/Chart/DataSeriesValues.php @@ -79,8 +79,8 @@ class DataSeriesValues /** * Create a new DataSeriesValues object. * - * @param string $dataSource * @param mixed $dataType + * @param string $dataSource * @param null|mixed $formatCode * @param mixed $pointCount * @param mixed $dataValues diff --git a/src/PhpSpreadsheet/Shared/XMLWriter.php b/src/PhpSpreadsheet/Shared/XMLWriter.php index 3a5cc301..8390c765 100644 --- a/src/PhpSpreadsheet/Shared/XMLWriter.php +++ b/src/PhpSpreadsheet/Shared/XMLWriter.php @@ -103,9 +103,9 @@ class XMLWriter extends \XMLWriter } /** - * Fallback method for writeRaw, introduced in PHP 5.2. + * Wrapper method for writeRaw. * - * @param string $text + * @param string|string[] $text * * @return bool */ @@ -115,10 +115,6 @@ class XMLWriter extends \XMLWriter $text = implode("\n", $text); } - if (method_exists($this, 'writeRaw')) { - return $this->writeRaw(htmlspecialchars($text)); - } - - return $this->text($text); + return $this->writeRaw(htmlspecialchars($text)); } } From 1a52e23f08aa8ad687dcb24d2fae68f80b044726 Mon Sep 17 00:00:00 2001 From: Adrien Crivelli Date: Thu, 16 Feb 2017 11:15:22 +0900 Subject: [PATCH 4/5] Remove obsolete math polyfills --- src/PhpSpreadsheet/Calculation/Functions.php | 26 -------------------- 1 file changed, 26 deletions(-) diff --git a/src/PhpSpreadsheet/Calculation/Functions.php b/src/PhpSpreadsheet/Calculation/Functions.php index c5ffef52..b5a5252a 100644 --- a/src/PhpSpreadsheet/Calculation/Functions.php +++ b/src/PhpSpreadsheet/Calculation/Functions.php @@ -673,32 +673,6 @@ class Functions } } -// -// There are a few mathematical functions that aren't available on all versions of PHP for all platforms -// These functions aren't available in Windows implementations of PHP prior to version 5.3.0 -// So we test if they do exist for this version of PHP/operating platform; and if not we create them -// -if (!function_exists('acosh')) { - function acosh($x) - { - return 2 * log(sqrt(($x + 1) / 2) + sqrt(($x - 1) / 2)); - } // function acosh() -} - -if (!function_exists('asinh')) { - function asinh($x) - { - return log($x + sqrt(1 + $x * $x)); - } // function asinh() -} - -if (!function_exists('atanh')) { - function atanh($x) - { - return (log(1 + $x) - log(1 - $x)) / 2; - } // function atanh() -} - // // Strangely, PHP doesn't have a mb_str_replace multibyte function // As we'll only ever use this function with UTF-8 characters, we can simply "hard-code" the character set From 7b90bb9394fea8682c4b1d710b3804cd9046ed81 Mon Sep 17 00:00:00 2001 From: Adrien Crivelli Date: Thu, 16 Feb 2017 11:53:52 +0900 Subject: [PATCH 5/5] Drop checks for mbstring existence Since mbstring is now a hard dependency enforced by composer, it is no longer necessary to check for its presence and implement fallbacks. --- src/PhpSpreadsheet/Calculation/Functions.php | 34 --- src/PhpSpreadsheet/Calculation/TextData.php | 70 ++---- src/PhpSpreadsheet/Shared/StringHelper.php | 202 +++++------------- .../PhpSpreadsheetTests/Shared/StringTest.php | 6 - 4 files changed, 73 insertions(+), 239 deletions(-) diff --git a/src/PhpSpreadsheet/Calculation/Functions.php b/src/PhpSpreadsheet/Calculation/Functions.php index b5a5252a..88346ed0 100644 --- a/src/PhpSpreadsheet/Calculation/Functions.php +++ b/src/PhpSpreadsheet/Calculation/Functions.php @@ -672,37 +672,3 @@ class Functions return $value; } } - -// -// Strangely, PHP doesn't have a mb_str_replace multibyte function -// As we'll only ever use this function with UTF-8 characters, we can simply "hard-code" the character set -// -if ((!function_exists('mb_str_replace')) && - (function_exists('mb_substr')) && (function_exists('mb_strlen')) && (function_exists('mb_strpos')) -) { - function mb_str_replace($search, $replace, $subject) - { - if (is_array($subject)) { - $ret = []; - foreach ($subject as $key => $val) { - $ret[$key] = mb_str_replace($search, $replace, $val); - } - - return $ret; - } - - foreach ((array) $search as $key => $s) { - if ($s == '' && $s !== 0) { - continue; - } - $r = !is_array($replace) ? $replace : (isset($replace[$key]) ? $replace[$key] : ''); - $pos = mb_strpos($subject, $s, 0, 'UTF-8'); - while ($pos !== false) { - $subject = mb_substr($subject, 0, $pos, 'UTF-8') . $r . mb_substr($subject, $pos + mb_strlen($s, 'UTF-8'), null, 'UTF-8'); - $pos = mb_strpos($subject, $s, $pos + mb_strlen($r, 'UTF-8'), 'UTF-8'); - } - } - - return $subject; - } -} diff --git a/src/PhpSpreadsheet/Calculation/TextData.php b/src/PhpSpreadsheet/Calculation/TextData.php index 62df7e3e..abf05d95 100644 --- a/src/PhpSpreadsheet/Calculation/TextData.php +++ b/src/PhpSpreadsheet/Calculation/TextData.php @@ -124,18 +124,11 @@ class TextData } $character = $characters; - if ((function_exists('mb_strlen')) && (function_exists('mb_substr'))) { - if (mb_strlen($characters, 'UTF-8') > 1) { - $character = mb_substr($characters, 0, 1, 'UTF-8'); - } - - return self::unicodeToOrd($character); - } - if (strlen($characters) > 0) { - $character = substr($characters, 0, 1); + if (mb_strlen($characters, 'UTF-8') > 1) { + $character = mb_substr($characters, 0, 1, 'UTF-8'); } - return ord($character); + return self::unicodeToOrd($character); } /** @@ -225,11 +218,8 @@ class TextData if (\PhpOffice\PhpSpreadsheet\Shared\StringHelper::countCharacters($needle) == 0) { return $offset; } - if (function_exists('mb_strpos')) { - $pos = mb_strpos($haystack, $needle, --$offset, 'UTF-8'); - } else { - $pos = strpos($haystack, $needle, --$offset); - } + + $pos = mb_strpos($haystack, $needle, --$offset, 'UTF-8'); if ($pos !== false) { return ++$pos; } @@ -263,11 +253,8 @@ class TextData if (\PhpOffice\PhpSpreadsheet\Shared\StringHelper::countCharacters($needle) == 0) { return $offset; } - if (function_exists('mb_stripos')) { - $pos = mb_stripos($haystack, $needle, --$offset, 'UTF-8'); - } else { - $pos = stripos($haystack, $needle, --$offset); - } + + $pos = mb_stripos($haystack, $needle, --$offset, 'UTF-8'); if ($pos !== false) { return ++$pos; } @@ -330,11 +317,7 @@ class TextData $value = ($value) ? \PhpOffice\PhpSpreadsheet\Calculation::getTRUE() : \PhpOffice\PhpSpreadsheet\Calculation::getFALSE(); } - if (function_exists('mb_substr')) { - return mb_substr($value, 0, $chars, 'UTF-8'); - } - - return substr($value, 0, $chars); + return mb_substr($value, 0, $chars, 'UTF-8'); } /** @@ -363,11 +346,8 @@ class TextData if (empty($chars)) { return ''; } - if (function_exists('mb_substr')) { - return mb_substr($value, --$start, $chars, 'UTF-8'); - } - return substr($value, --$start, $chars); + return mb_substr($value, --$start, $chars, 'UTF-8'); } /** @@ -391,11 +371,7 @@ class TextData $value = ($value) ? \PhpOffice\PhpSpreadsheet\Calculation::getTRUE() : \PhpOffice\PhpSpreadsheet\Calculation::getFALSE(); } - if ((function_exists('mb_substr')) && (function_exists('mb_strlen'))) { - return mb_substr($value, mb_strlen($value, 'UTF-8') - $chars, $chars, 'UTF-8'); - } - - return substr($value, strlen($value) - $chars); + return mb_substr($value, mb_strlen($value, 'UTF-8') - $chars, $chars, 'UTF-8'); } /** @@ -413,11 +389,7 @@ class TextData $value = ($value) ? \PhpOffice\PhpSpreadsheet\Calculation::getTRUE() : \PhpOffice\PhpSpreadsheet\Calculation::getFALSE(); } - if (function_exists('mb_strlen')) { - return mb_strlen($value, 'UTF-8'); - } - - return strlen($value); + return mb_strlen($value, 'UTF-8'); } /** @@ -521,30 +493,20 @@ class TextData $instance = floor(Functions::flattenSingleValue($instance)); if ($instance == 0) { - if (function_exists('mb_str_replace')) { - return mb_str_replace($fromText, $toText, $text); - } - - return str_replace($fromText, $toText, $text); + return \PhpOffice\PhpSpreadsheet\Shared\StringHelper::mbStrReplace($fromText, $toText, $text); } + $pos = -1; while ($instance > 0) { - if (function_exists('mb_strpos')) { - $pos = mb_strpos($text, $fromText, $pos + 1, 'UTF-8'); - } else { - $pos = strpos($text, $fromText, $pos + 1); - } + $pos = mb_strpos($text, $fromText, $pos + 1, 'UTF-8'); if ($pos === false) { break; } --$instance; } - if ($pos !== false) { - if (function_exists('mb_strlen')) { - return self::REPLACE($text, ++$pos, mb_strlen($fromText, 'UTF-8'), $toText); - } - return self::REPLACE($text, ++$pos, strlen($fromText), $toText); + if ($pos !== false) { + return self::REPLACE($text, ++$pos, mb_strlen($fromText, 'UTF-8'), $toText); } return $text; diff --git a/src/PhpSpreadsheet/Shared/StringHelper.php b/src/PhpSpreadsheet/Shared/StringHelper.php index 1084db68..299a9897 100644 --- a/src/PhpSpreadsheet/Shared/StringHelper.php +++ b/src/PhpSpreadsheet/Shared/StringHelper.php @@ -66,13 +66,6 @@ class StringHelper */ private static $currencyCode; - /** - * Is mbstring extension avalable? - * - * @var bool - */ - private static $isMbstringEnabled; - /** * Is iconv extension avalable? * @@ -259,23 +252,6 @@ class StringHelper ]; } - /** - * Get whether mbstring extension is available. - * - * @return bool - */ - public static function getIsMbstringEnabled() - { - if (isset(self::$isMbstringEnabled)) { - return self::$isMbstringEnabled; - } - - self::$isMbstringEnabled = function_exists('mb_convert_encoding') ? - true : false; - - return self::$isMbstringEnabled; - } - /** * Get whether iconv extension is available. * @@ -387,13 +363,8 @@ class StringHelper return $value; } - if (self::getIsMbstringEnabled()) { - $value = mb_convert_encoding($value, 'UTF-8', 'UTF-8'); + $value = mb_convert_encoding($value, 'UTF-8', 'UTF-8'); - return $value; - } - - // else, no conversion return $value; } @@ -444,9 +415,7 @@ class StringHelper $ln = self::countCharacters($value, 'UTF-8'); // option flags if (empty($arrcRuns)) { - $opt = (self::getIsIconvEnabled() || self::getIsMbstringEnabled()) ? - 0x0001 : 0x0000; - $data = pack('CC', $ln, $opt); + $data = pack('CC', $ln, 0x0001); // characters $data .= self::convertEncoding($value, 'UTF-16LE', 'UTF-8'); } else { @@ -479,20 +448,16 @@ class StringHelper // character count $ln = self::countCharacters($value, 'UTF-8'); - // option flags - $opt = (self::getIsIconvEnabled() || self::getIsMbstringEnabled()) ? - 0x0001 : 0x0000; - // characters $chars = self::convertEncoding($value, 'UTF-16LE', 'UTF-8'); - $data = pack('vC', $ln, $opt) . $chars; + $data = pack('vC', $ln, 0x0001) . $chars; return $data; } /** - * Convert string from one encoding to another. First try mbstring, then iconv, finally strlen. + * Convert string from one encoding to another. * * @param string $value * @param string $to Encoding to convert to, e.g. 'UTF-8' @@ -506,68 +471,11 @@ class StringHelper return iconv($from, $to . '//IGNORE//TRANSLIT', $value); } - if (self::getIsMbstringEnabled()) { - return mb_convert_encoding($value, $to, $from); - } - - if ($from == 'UTF-16LE') { - return self::utf16Decode($value, false); - } elseif ($from == 'UTF-16BE') { - return self::utf16Decode($value); - } - // else, no conversion - return $value; + return mb_convert_encoding($value, $to, $from); } /** - * Decode UTF-16 encoded strings. - * - * Can handle both BOM'ed data and un-BOM'ed data. - * Assumes Big-Endian byte order if no BOM is available. - * This function was taken from http://php.net/manual/en/function.utf8-decode.php - * and $bom_be parameter added. - * - * @param string $str uTF-16 encoded data to decode - * @param mixed $bom_be - * - * @return string uTF-8 / ISO encoded data - * - * @version 0.2 / 2010-05-13 - * - * @author Rasmus Andersson {@link http://rasmusandersson.se/} - * @author vadik56 - */ - public static function utf16Decode($str, $bom_be = true) - { - if (strlen($str) < 2) { - return $str; - } - $c0 = ord($str[0]); - $c1 = ord($str[1]); - if ($c0 == 0xfe && $c1 == 0xff) { - $str = substr($str, 2); - } elseif ($c0 == 0xff && $c1 == 0xfe) { - $str = substr($str, 2); - $bom_be = false; - } - $len = strlen($str); - $newstr = ''; - for ($i = 0; $i < $len; $i += 2) { - if ($bom_be) { - $val = ord($str[$i]) << 4; - $val += ord($str[$i + 1]); - } else { - $val = ord($str[$i + 1]) << 4; - $val += ord($str[$i]); - } - $newstr .= ($val == 0x228) ? "\n" : chr($val); - } - - return $newstr; - } - - /** - * Get character count. First try mbstring, then iconv, finally strlen. + * Get character count. * * @param string $value * @param string $enc Encoding @@ -576,20 +484,11 @@ class StringHelper */ public static function countCharacters($value, $enc = 'UTF-8') { - if (self::getIsMbstringEnabled()) { - return mb_strlen($value, $enc); - } - - if (self::getIsIconvEnabled()) { - return iconv_strlen($value, $enc); - } - - // else strlen - return strlen($value); + return mb_strlen($value, $enc); } /** - * Get a substring of a UTF-8 encoded string. First try mbstring, then iconv, finally strlen. + * Get a substring of a UTF-8 encoded string. * * @param string $pValue UTF-8 encoded string * @param int $pStart Start offset @@ -599,16 +498,7 @@ class StringHelper */ public static function substring($pValue = '', $pStart = 0, $pLength = 0) { - if (self::getIsMbstringEnabled()) { - return mb_substr($pValue, $pStart, $pLength, 'UTF-8'); - } - - if (self::getIsIconvEnabled()) { - return iconv_substr($pValue, $pStart, $pLength, 'UTF-8'); - } - - // else substr - return substr($pValue, $pStart, $pLength); + return mb_substr($pValue, $pStart, $pLength, 'UTF-8'); } /** @@ -620,11 +510,7 @@ class StringHelper */ public static function strToUpper($pValue = '') { - if (function_exists('mb_convert_case')) { - return mb_convert_case($pValue, MB_CASE_UPPER, 'UTF-8'); - } - - return strtoupper($pValue); + return mb_convert_case($pValue, MB_CASE_UPPER, 'UTF-8'); } /** @@ -636,11 +522,7 @@ class StringHelper */ public static function strToLower($pValue = '') { - if (function_exists('mb_convert_case')) { - return mb_convert_case($pValue, MB_CASE_LOWER, 'UTF-8'); - } - - return strtolower($pValue); + return mb_convert_case($pValue, MB_CASE_LOWER, 'UTF-8'); } /** @@ -653,11 +535,7 @@ class StringHelper */ public static function strToTitle($pValue = '') { - if (function_exists('mb_convert_case')) { - return mb_convert_case($pValue, MB_CASE_TITLE, 'UTF-8'); - } - - return ucwords($pValue); + return mb_convert_case($pValue, MB_CASE_TITLE, 'UTF-8'); } public static function mbIsUpper($char) @@ -672,6 +550,44 @@ class StringHelper return preg_split('/(? $val) { + $ret[$key] = self::mbStrReplace($search, $replace, $val); + } + + return $ret; + } + + foreach ((array) $search as $key => $s) { + if ($s == '' && $s !== 0) { + continue; + } + $r = !is_array($replace) ? $replace : (isset($replace[$key]) ? $replace[$key] : ''); + $pos = mb_strpos($subject, $s, 0, 'UTF-8'); + while ($pos !== false) { + $subject = mb_substr($subject, 0, $pos, 'UTF-8') . $r . mb_substr($subject, $pos + mb_strlen($s, 'UTF-8'), null, 'UTF-8'); + $pos = mb_strpos($subject, $s, $pos + mb_strlen($r, 'UTF-8'), 'UTF-8'); + } + } + + return $subject; + } + /** * Reverse the case of a string, so that all uppercase characters become lowercase * and all lowercase characters become uppercase. @@ -682,20 +598,16 @@ class StringHelper */ public static function strCaseReverse($pValue = '') { - if (self::getIsMbstringEnabled()) { - $characters = self::mbStrSplit($pValue); - foreach ($characters as &$character) { - if (self::mbIsUpper($character)) { - $character = mb_strtolower($character, 'UTF-8'); - } else { - $character = mb_strtoupper($character, 'UTF-8'); - } + $characters = self::mbStrSplit($pValue); + foreach ($characters as &$character) { + if (self::mbIsUpper($character)) { + $character = mb_strtolower($character, 'UTF-8'); + } else { + $character = mb_strtoupper($character, 'UTF-8'); } - - return implode('', $characters); } - return strtolower($pValue) ^ strtoupper($pValue) ^ $pValue; + return implode('', $characters); } /** diff --git a/tests/PhpSpreadsheetTests/Shared/StringTest.php b/tests/PhpSpreadsheetTests/Shared/StringTest.php index ac87c7ac..83643127 100644 --- a/tests/PhpSpreadsheetTests/Shared/StringTest.php +++ b/tests/PhpSpreadsheetTests/Shared/StringTest.php @@ -14,12 +14,6 @@ class StringTest extends \PHPUnit_Framework_TestCase StringHelper::setCurrencyCode(null); } - public function testGetIsMbStringEnabled() - { - $result = StringHelper::getIsMbstringEnabled(); - $this->assertTrue($result); - } - public function testGetIsIconvEnabled() { $result = StringHelper::getIsIconvEnabled();