Browse Source

Update to phpspreadsheet 1.8.2

Laurent Destailleur 4 years ago
parent
commit
76c3229c97
61 changed files with 2555 additions and 1124 deletions
  1. 1 1
      COPYRIGHT
  2. 57 0
      composer.lock
  3. 19 6
      htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/Calculation.php
  4. 54 0
      htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/Logical.php
  5. 23 11
      htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/LookupRef.php
  6. 3 2
      htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/MathTrig.php
  7. 1 0
      htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/functionlist.txt
  8. 2 0
      htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Cell/AdvancedValueBinder.php
  9. 1 1
      htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Cell/Cell.php
  10. 1 3
      htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Cell/Coordinate.php
  11. 2 0
      htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Cell/DefaultValueBinder.php
  12. 31 0
      htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Cell/StringValueBinder.php
  13. 2 2
      htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/Axis.php
  14. 2 2
      htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/GridLines.php
  15. 8 8
      htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/Layout.php
  16. 3 3
      htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Collection/Cells.php
  17. 1 1
      htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Document/Properties.php
  18. 6 85
      htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/BaseReader.php
  19. 13 13
      htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Csv.php
  20. 1 1
      htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Gnumeric.php
  21. 309 19
      htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Html.php
  22. 106 0
      htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/IReader.php
  23. 16 100
      htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Ods.php
  24. 136 0
      htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Ods/Properties.php
  25. 60 31
      htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Security/XmlScanner.php
  26. 1 1
      htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Slk.php
  27. 1 1
      htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xls.php
  28. 113 688
      htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xlsx.php
  29. 144 0
      htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xlsx/AutoFilter.php
  30. 19 0
      htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xlsx/BaseParserClass.php
  31. 204 0
      htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xlsx/ColumnAndRowAttributes.php
  32. 92 0
      htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xlsx/ConditionalStyles.php
  33. 50 0
      htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xlsx/DataValidations.php
  34. 58 0
      htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xlsx/Hyperlinks.php
  35. 150 0
      htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xlsx/PageSetup.php
  36. 91 0
      htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xlsx/Properties.php
  37. 124 0
      htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xlsx/SheetViewOptions.php
  38. 127 0
      htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xlsx/SheetViews.php
  39. 265 0
      htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xlsx/Styles.php
  40. 1 1
      htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xml.php
  41. 13 13
      htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/ReferenceHelper.php
  42. 42 0
      htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Settings.php
  43. 13 12
      htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Shared/Date.php
  44. 21 15
      htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Shared/OLE.php
  45. 3 1
      htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Shared/Trend/ExponentialBestFit.php
  46. 3 1
      htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Shared/Trend/LinearBestFit.php
  47. 3 1
      htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Shared/Trend/LogarithmicBestFit.php
  48. 3 1
      htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Shared/Trend/PolynomialBestFit.php
  49. 3 1
      htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Shared/Trend/PowerBestFit.php
  50. 1 1
      htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Spreadsheet.php
  51. 19 1
      htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/NumberFormat.php
  52. 2 2
      htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Worksheet/Dimension.php
  53. 10 0
      htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Worksheet/RowCellIterator.php
  54. 2 2
      htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Worksheet/Worksheet.php
  55. 0 55
      htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/BaseWriter.php
  56. 69 0
      htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/IWriter.php
  57. 16 17
      htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Xls/Parser.php
  58. 4 6
      htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Xls/Workbook.php
  59. 13 2
      htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Xlsx.php
  60. 2 2
      htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Xlsx/Workbook.php
  61. 15 11
      htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php

+ 1 - 1
COPYRIGHT

@@ -23,7 +23,7 @@ PEAR Mail_MIME         1.8.9         BSD                         Yes
 ParseDown              1.6           MIT License                 Yes             Markdown parser
 ParseDown              1.6           MIT License                 Yes             Markdown parser
 PCLZip                 2.8.4         LGPL-3+                     Yes             Library to zip/unzip files             
 PCLZip                 2.8.4         LGPL-3+                     Yes             Library to zip/unzip files             
 PHPDebugBar            1.15.1        MIT License	             Yes             Used only by the module "debugbar" for developers
 PHPDebugBar            1.15.1        MIT License	             Yes             Used only by the module "debugbar" for developers
-PHPSpreadSheet         ?             LGPL-2.1+                   Yes             Read/Write XLS files, read ODS files
+PHPSpreadSheet         1.8.2         LGPL-2.1+                   Yes             Read/Write XLS files, read ODS files
 php-iban               1.4.7         LGPL-3+                     Yes             Parse and validate IBAN (and IIBAN) bank account information in PHP
 php-iban               1.4.7         LGPL-3+                     Yes             Parse and validate IBAN (and IIBAN) bank account information in PHP
 PHPoAuthLib            0.8.2         MIT License                 Yes             Library to provide oauth1 and oauth2 to different service
 PHPoAuthLib            0.8.2         MIT License                 Yes             Library to provide oauth1 and oauth2 to different service
 PHPPrintIPP            1.3           GPL-2+                      Yes             Library to send print IPP requests
 PHPPrintIPP            1.3           GPL-2+                      Yes             Library to send print IPP requests

+ 57 - 0
composer.lock

@@ -328,6 +328,63 @@
             },
             },
             "time": "2020-03-23T09:12:05+00:00"
             "time": "2020-03-23T09:12:05+00:00"
         },
         },
+ 		{
+            "name": "phpoffice/phpexcel",
+            "version": "1.8.2",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/PHPOffice/PHPExcel.git",
+                "reference": "1441011fb7ecdd8cc689878f54f8b58a6805f870"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/PHPOffice/PHPExcel/zipball/1441011fb7ecdd8cc689878f54f8b58a6805f870",
+                "reference": "1441011fb7ecdd8cc689878f54f8b58a6805f870",
+                "shasum": ""
+            },
+            "require": {
+                "ext-mbstring": "*",
+                "ext-xml": "*",
+                "ext-xmlwriter": "*",
+                "php": "^5.2|^7.0"
+            },
+            "require-dev": {
+                "squizlabs/php_codesniffer": "2.*"
+            },
+            "type": "library",
+            "autoload": {
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "LGPL-2.1"
+            ],
+            "authors": [
+                {
+                    "name": "Maarten Balliauw",
+                    "homepage": "http://blog.maartenballiauw.be"
+                },
+                {
+                    "name": "Erik Tilt"
+                },
+                {
+                    "name": "Franck Lefevre",
+                    "homepage": "http://rootslabs.net"
+                },
+                {
+                    "name": "Mark Baker",
+                    "homepage": "http://markbakeruk.net"
+                }
+            ],
+            "description": "PHPExcel - OpenXML - Read, Create and Write Spreadsheet documents in PHP - Spreadsheet engine",
+            "homepage": "https://github.com/PHPOffice/PHPExcel",
+            "keywords": [
+                "OpenXML",
+                "excel",
+                "xlsx"
+            ],
+            "abandoned": "phpoffice/phpspreadsheet",
+            "time": "2018-11-22T23:07:24+00:00"
+        },        
         {
         {
             "name": "restler/framework",
             "name": "restler/framework",
             "version": "3.0.0-RC6",
             "version": "3.0.0-RC6",

+ 19 - 6
htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/Calculation.php

@@ -117,7 +117,7 @@ class Calculation
     /**
     /**
      * An array of the nested cell references accessed by the calculation engine, used for the debug log.
      * An array of the nested cell references accessed by the calculation engine, used for the debug log.
      *
      *
-     * @var array of string
+     * @var CyclicReferenceStack
      */
      */
     private $cyclicReferenceStack;
     private $cyclicReferenceStack;
 
 
@@ -1945,6 +1945,11 @@ class Calculation
             'functionCall' => [MathTrig::class, 'SUMXMY2'],
             'functionCall' => [MathTrig::class, 'SUMXMY2'],
             'argumentCount' => '2',
             'argumentCount' => '2',
         ],
         ],
+        'SWITCH' => [
+            'category' => Category::CATEGORY_LOGICAL,
+            'functionCall' => [Logical::class, 'statementSwitch'],
+            'argumentCount' => '3+',
+        ],
         'SYD' => [
         'SYD' => [
             'category' => Category::CATEGORY_FINANCIAL,
             'category' => Category::CATEGORY_FINANCIAL,
             'functionCall' => [Financial::class, 'SYD'],
             'functionCall' => [Financial::class, 'SYD'],
@@ -2207,8 +2212,8 @@ class Calculation
     private static function loadLocales()
     private static function loadLocales()
     {
     {
         $localeFileDirectory = __DIR__ . '/locale/';
         $localeFileDirectory = __DIR__ . '/locale/';
-        foreach (glob($localeFileDirectory . '/*', GLOB_ONLYDIR) as $filename) {
-            $filename = substr($filename, strlen($localeFileDirectory) + 1);
+        foreach (glob($localeFileDirectory . '*', GLOB_ONLYDIR) as $filename) {
+            $filename = substr($filename, strlen($localeFileDirectory));
             if ($filename != 'en') {
             if ($filename != 'en') {
                 self::$validLocaleLanguages[] = $filename;
                 self::$validLocaleLanguages[] = $filename;
             }
             }
@@ -2413,7 +2418,6 @@ class Calculation
         if (strpos($locale, '_') !== false) {
         if (strpos($locale, '_') !== false) {
             list($language) = explode('_', $locale);
             list($language) = explode('_', $locale);
         }
         }
-
         if (count(self::$validLocaleLanguages) == 1) {
         if (count(self::$validLocaleLanguages) == 1) {
             self::loadLocales();
             self::loadLocales();
         }
         }
@@ -2704,7 +2708,7 @@ class Calculation
      * @param Cell $pCell Cell to calculate
      * @param Cell $pCell Cell to calculate
      * @param bool $resetLog Flag indicating whether the debug log should be reset or not
      * @param bool $resetLog Flag indicating whether the debug log should be reset or not
      *
      *
-     * @throws Exception
+     * @throws \PhpOffice\PhpSpreadsheet\Exception
      *
      *
      * @return mixed
      * @return mixed
      */
      */
@@ -2808,7 +2812,7 @@ class Calculation
      * @param string $cellID Address of the cell to calculate
      * @param string $cellID Address of the cell to calculate
      * @param Cell $pCell Cell to calculate
      * @param Cell $pCell Cell to calculate
      *
      *
-     * @throws Exception
+     * @throws \PhpOffice\PhpSpreadsheet\Exception
      *
      *
      * @return mixed
      * @return mixed
      */
      */
@@ -2892,6 +2896,15 @@ class Calculation
     {
     {
         $cellValue = null;
         $cellValue = null;
 
 
+        //  Quote-Prefixed cell values cannot be formulae, but are treated as strings
+        if ($pCell !== null && $pCell->getStyle()->getQuotePrefix() === true) {
+            return self::wrapResult((string) $formula);
+        }
+
+        if (preg_match('/^=\s*cmd\s*\|/miu', $formula) !== 0) {
+            return self::wrapResult($formula);
+        }
+
         //    Basic validation that this is indeed a formula
         //    Basic validation that this is indeed a formula
         //    We simply return the cell value if not
         //    We simply return the cell value if not
         $formula = trim($formula);
         $formula = trim($formula);

+ 54 - 0
htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/Logical.php

@@ -273,6 +273,60 @@ class Logical
         return ($condition) ? $returnIfTrue : $returnIfFalse;
         return ($condition) ? $returnIfTrue : $returnIfFalse;
     }
     }
 
 
+    /**
+     * STATEMENT_SWITCH.
+     *
+     * Returns corresponding with first match (any data type such as a string, numeric, date, etc).
+     *
+     * Excel Function:
+     *        =SWITCH (expression, value1, result1, value2, result2, ... value_n, result_n [, default])
+     *
+     *        Expression
+     *              The expression to compare to a list of values.
+     *        value1, value2, ... value_n
+     *              A list of values that are compared to expression. The SWITCH function is looking for the first value that matches the expression.
+     *        result1, result2, ... result_n
+     *              A list of results. The SWITCH function returns the corresponding result when a value matches expression.
+     *         default
+     *              Optional. It is the default to return if expression does not match any of the values (value1, value2, ... value_n).
+     *
+     * @category Logical Functions
+     *
+     * @param mixed $arguments Statement arguments
+     *
+     * @return mixed The value of matched expression
+     */
+    public static function statementSwitch(...$arguments)
+    {
+        $result = Functions::VALUE();
+
+        if (count($arguments) > 0) {
+            $targetValue = Functions::flattenSingleValue($arguments[0]);
+            $argc = count($arguments) - 1;
+            $switchCount = floor($argc / 2);
+            $switchSatisfied = false;
+            $hasDefaultClause = $argc % 2 !== 0;
+            $defaultClause = $argc % 2 === 0 ? null : $arguments[count($arguments) - 1];
+
+            if ($switchCount) {
+                for ($index = 0; $index < $switchCount; ++$index) {
+                    if ($targetValue == $arguments[$index * 2 + 1]) {
+                        $result = $arguments[$index * 2 + 2];
+                        $switchSatisfied = true;
+
+                        break;
+                    }
+                }
+            }
+
+            if (!$switchSatisfied) {
+                $result = $hasDefaultClause ? $defaultClause : Functions::NA();
+            }
+        }
+
+        return $result;
+    }
+
     /**
     /**
      * IFERROR.
      * IFERROR.
      *
      *

+ 23 - 11
htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/LookupRef.php

@@ -4,6 +4,7 @@ namespace PhpOffice\PhpSpreadsheet\Calculation;
 
 
 use PhpOffice\PhpSpreadsheet\Cell\Cell;
 use PhpOffice\PhpSpreadsheet\Cell\Cell;
 use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
 use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
+use PhpOffice\PhpSpreadsheet\Shared\StringHelper;
 use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
 use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
 
 
 class LookupRef
 class LookupRef
@@ -473,8 +474,9 @@ class LookupRef
         $lookupValue = Functions::flattenSingleValue($lookupValue);
         $lookupValue = Functions::flattenSingleValue($lookupValue);
         $matchType = ($matchType === null) ? 1 : (int) Functions::flattenSingleValue($matchType);
         $matchType = ($matchType === null) ? 1 : (int) Functions::flattenSingleValue($matchType);
 
 
+        $initialLookupValue = $lookupValue;
         // MATCH is not case sensitive
         // MATCH is not case sensitive
-        $lookupValue = strtolower($lookupValue);
+        $lookupValue = StringHelper::strToLower($lookupValue);
 
 
         // Lookup_value type has to be number, text, or logical values
         // Lookup_value type has to be number, text, or logical values
         if ((!is_numeric($lookupValue)) && (!is_string($lookupValue)) && (!is_bool($lookupValue))) {
         if ((!is_numeric($lookupValue)) && (!is_string($lookupValue)) && (!is_bool($lookupValue))) {
@@ -502,7 +504,7 @@ class LookupRef
             }
             }
             // Convert strings to lowercase for case-insensitive testing
             // Convert strings to lowercase for case-insensitive testing
             if (is_string($lookupArrayValue)) {
             if (is_string($lookupArrayValue)) {
-                $lookupArray[$i] = strtolower($lookupArrayValue);
+                $lookupArray[$i] = StringHelper::strToLower($lookupArrayValue);
             }
             }
             if (($lookupArrayValue === null) && (($matchType == 1) || ($matchType == -1))) {
             if (($lookupArrayValue === null) && (($matchType == 1) || ($matchType == -1))) {
                 $lookupArray = array_slice($lookupArray, 0, $i - 1);
                 $lookupArray = array_slice($lookupArray, 0, $i - 1);
@@ -522,9 +524,13 @@ class LookupRef
 
 
         if ($matchType == 0 || $matchType == 1) {
         if ($matchType == 0 || $matchType == 1) {
             foreach ($lookupArray as $i => $lookupArrayValue) {
             foreach ($lookupArray as $i => $lookupArrayValue) {
-                if (($matchType == 0) && ($lookupArrayValue == $lookupValue)) {
+                $onlyNumeric = is_numeric($lookupArrayValue) && is_numeric($lookupValue);
+                $onlyNumericExactMatch = $onlyNumeric && $lookupArrayValue == $lookupValue;
+                $nonOnlyNumericExactMatch = !$onlyNumeric && $lookupArrayValue === $lookupValue;
+                $exactMatch = $onlyNumericExactMatch || $nonOnlyNumericExactMatch;
+                if (($matchType == 0) && $exactMatch) {
                     //    exact match
                     //    exact match
-                    return ++$i;
+                    return $i + 1;
                 } elseif (($matchType == 1) && ($lookupArrayValue <= $lookupValue)) {
                 } elseif (($matchType == 1) && ($lookupArrayValue <= $lookupValue)) {
                     $i = array_search($i, $keySet);
                     $i = array_search($i, $keySet);
 
 
@@ -661,7 +667,9 @@ class LookupRef
     {
     {
         reset($a);
         reset($a);
         $firstColumn = key($a);
         $firstColumn = key($a);
-        if (($aLower = strtolower($a[$firstColumn])) == ($bLower = strtolower($b[$firstColumn]))) {
+        $aLower = StringHelper::strToLower($a[$firstColumn]);
+        $bLower = StringHelper::strToLower($b[$firstColumn]);
+        if ($aLower == $bLower) {
             return 0;
             return 0;
         }
         }
 
 
@@ -707,11 +715,14 @@ class LookupRef
             uasort($lookup_array, ['self', 'vlookupSort']);
             uasort($lookup_array, ['self', 'vlookupSort']);
         }
         }
 
 
+        $lookupLower = StringHelper::strToLower($lookup_value);
         $rowNumber = $rowValue = false;
         $rowNumber = $rowValue = false;
         foreach ($lookup_array as $rowKey => $rowData) {
         foreach ($lookup_array as $rowKey => $rowData) {
+            $firstLower = StringHelper::strToLower($rowData[$firstColumn]);
+
             // break if we have passed possible keys
             // break if we have passed possible keys
             if ((is_numeric($lookup_value) && is_numeric($rowData[$firstColumn]) && ($rowData[$firstColumn] > $lookup_value)) ||
             if ((is_numeric($lookup_value) && is_numeric($rowData[$firstColumn]) && ($rowData[$firstColumn] > $lookup_value)) ||
-                (!is_numeric($lookup_value) && !is_numeric($rowData[$firstColumn]) && (strtolower($rowData[$firstColumn]) > strtolower($lookup_value)))) {
+                (!is_numeric($lookup_value) && !is_numeric($rowData[$firstColumn]) && ($firstLower > $lookupLower))) {
                 break;
                 break;
             }
             }
             // remember the last key, but only if datatypes match
             // remember the last key, but only if datatypes match
@@ -719,17 +730,15 @@ class LookupRef
                 (!is_numeric($lookup_value) && !is_numeric($rowData[$firstColumn]))) {
                 (!is_numeric($lookup_value) && !is_numeric($rowData[$firstColumn]))) {
                 if ($not_exact_match) {
                 if ($not_exact_match) {
                     $rowNumber = $rowKey;
                     $rowNumber = $rowKey;
-                    $rowValue = $rowData[$firstColumn];
 
 
                     continue;
                     continue;
-                } elseif ((strtolower($rowData[$firstColumn]) == strtolower($lookup_value))
+                } elseif (($firstLower == $lookupLower)
                     // Spreadsheets software returns first exact match,
                     // Spreadsheets software returns first exact match,
                     // we have sorted and we might have broken key orders
                     // we have sorted and we might have broken key orders
                     // we want the first one (by its initial index)
                     // we want the first one (by its initial index)
                     && (($rowNumber == false) || ($rowKey < $rowNumber))
                     && (($rowNumber == false) || ($rowKey < $rowNumber))
                 ) {
                 ) {
                     $rowNumber = $rowKey;
                     $rowNumber = $rowKey;
-                    $rowValue = $rowData[$firstColumn];
                 }
                 }
             }
             }
         }
         }
@@ -782,8 +791,11 @@ class LookupRef
             // break if we have passed possible keys
             // break if we have passed possible keys
             $bothNumeric = is_numeric($lookup_value) && is_numeric($rowData);
             $bothNumeric = is_numeric($lookup_value) && is_numeric($rowData);
             $bothNotNumeric = !is_numeric($lookup_value) && !is_numeric($rowData);
             $bothNotNumeric = !is_numeric($lookup_value) && !is_numeric($rowData);
+            $lookupLower = StringHelper::strToLower($lookup_value);
+            $rowDataLower = StringHelper::strToLower($rowData);
+
             if (($bothNumeric && $rowData > $lookup_value) ||
             if (($bothNumeric && $rowData > $lookup_value) ||
-                ($bothNotNumeric && strtolower($rowData) > strtolower($lookup_value))) {
+                ($bothNotNumeric && $rowDataLower > $lookupLower)) {
                 break;
                 break;
             }
             }
 
 
@@ -793,7 +805,7 @@ class LookupRef
                     $rowNumber = $rowKey;
                     $rowNumber = $rowKey;
 
 
                     continue;
                     continue;
-                } elseif (strtolower($rowData) === strtolower($lookup_value)
+                } elseif ($rowDataLower === $lookupLower
                     && ($rowNumber === null || $rowKey < $rowNumber)
                     && ($rowNumber === null || $rowKey < $rowNumber)
                 ) {
                 ) {
                     $rowNumber = $rowKey;
                     $rowNumber = $rowKey;

+ 3 - 2
htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/MathTrig.php

@@ -1224,11 +1224,12 @@ class MathTrig
             }
             }
 
 
             $testCondition = '=' . $arg . $condition;
             $testCondition = '=' . $arg . $condition;
+            $sumValue = array_key_exists($key, $sumArgs) ? $sumArgs[$key] : 0;
 
 
-            if (is_numeric($sumArgs[$key]) &&
+            if (is_numeric($sumValue) &&
                 Calculation::getInstance()->_calculateFormulaValue($testCondition)) {
                 Calculation::getInstance()->_calculateFormulaValue($testCondition)) {
                 // Is it a value within our criteria and only numeric can be added to the result
                 // Is it a value within our criteria and only numeric can be added to the result
-                $returnValue += $sumArgs[$key];
+                $returnValue += $sumValue;
             }
             }
         }
         }
 
 

+ 1 - 0
htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/functionlist.txt

@@ -337,6 +337,7 @@ SUMSQ
 SUMX2MY2
 SUMX2MY2
 SUMX2PY2
 SUMX2PY2
 SUMXMY2
 SUMXMY2
+SWITCH
 SYD
 SYD
 T
 T
 TAN
 TAN

+ 2 - 0
htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Cell/AdvancedValueBinder.php

@@ -16,6 +16,8 @@ class AdvancedValueBinder extends DefaultValueBinder implements IValueBinder
      * @param Cell $cell Cell to bind value to
      * @param Cell $cell Cell to bind value to
      * @param mixed $value Value to bind in cell
      * @param mixed $value Value to bind in cell
      *
      *
+     * @throws \PhpOffice\PhpSpreadsheet\Exception
+     *
      * @return bool
      * @return bool
      */
      */
     public function bindValue(Cell $cell, $value = null)
     public function bindValue(Cell $cell, $value = null)

+ 1 - 1
htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Cell/Cell.php

@@ -523,7 +523,7 @@ class Cell
     /**
     /**
      * If this cell is in a merge range, then return the range.
      * If this cell is in a merge range, then return the range.
      *
      *
-     * @return string
+     * @return false|string
      */
      */
     public function getMergeRange()
     public function getMergeRange()
     {
     {

+ 1 - 3
htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Cell/Coordinate.php

@@ -157,14 +157,12 @@ abstract class Coordinate
         }
         }
 
 
         // Build range
         // Build range
-        $imploded = [];
         $counter = count($pRange);
         $counter = count($pRange);
         for ($i = 0; $i < $counter; ++$i) {
         for ($i = 0; $i < $counter; ++$i) {
             $pRange[$i] = implode(':', $pRange[$i]);
             $pRange[$i] = implode(':', $pRange[$i]);
         }
         }
-        $imploded = implode(',', $pRange);
 
 
-        return $imploded;
+        return implode(',', $pRange);
     }
     }
 
 
     /**
     /**

+ 2 - 0
htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Cell/DefaultValueBinder.php

@@ -14,6 +14,8 @@ class DefaultValueBinder implements IValueBinder
      * @param Cell $cell Cell to bind value to
      * @param Cell $cell Cell to bind value to
      * @param mixed $value Value to bind in cell
      * @param mixed $value Value to bind in cell
      *
      *
+     * @throws \PhpOffice\PhpSpreadsheet\Exception
+     *
      * @return bool
      * @return bool
      */
      */
     public function bindValue(Cell $cell, $value)
     public function bindValue(Cell $cell, $value)

+ 31 - 0
htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Cell/StringValueBinder.php

@@ -0,0 +1,31 @@
+<?php
+
+namespace PhpOffice\PhpSpreadsheet\Cell;
+
+use PhpOffice\PhpSpreadsheet\Shared\StringHelper;
+
+class StringValueBinder implements IValueBinder
+{
+    /**
+     * Bind value to a cell.
+     *
+     * @param Cell $cell Cell to bind value to
+     * @param mixed $value Value to bind in cell
+     *
+     * @throws \PhpOffice\PhpSpreadsheet\Exception
+     *
+     * @return bool
+     */
+    public function bindValue(Cell $cell, $value)
+    {
+        // sanitize UTF-8 strings
+        if (is_string($value)) {
+            $value = StringHelper::sanitizeUTF8($value);
+        }
+
+        $cell->setValueExplicit((string) $value, DataType::TYPE_STRING);
+
+        // Done!
+        return true;
+    }
+}

+ 2 - 2
htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/Axis.php

@@ -365,10 +365,10 @@ class Axis extends Properties
     }
     }
 
 
     /**
     /**
-     * Set Shadow Properties from Maped Values.
+     * Set Shadow Properties from Mapped Values.
      *
      *
      * @param array $properties_map
      * @param array $properties_map
-     * @param * $reference
+     * @param mixed &$reference
      *
      *
      * @return Axis
      * @return Axis
      */
      */

+ 2 - 2
htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/GridLines.php

@@ -319,7 +319,7 @@ class GridLines extends Properties
      * Set Shadow Properties Values.
      * Set Shadow Properties Values.
      *
      *
      * @param array $properties_map
      * @param array $properties_map
-     * @param * $reference
+     * @param mixed &$reference
      *
      *
      * @return GridLines
      * @return GridLines
      */
      */
@@ -439,7 +439,7 @@ class GridLines extends Properties
     {
     {
         if ($size !== null) {
         if ($size !== null) {
             $this->activateObject();
             $this->activateObject();
-            $softEdges['size'] = (string) $this->getExcelPointsWidth($size);
+            $this->softEdges['size'] = (string) $this->getExcelPointsWidth($size);
         }
         }
     }
     }
 
 

+ 8 - 8
htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/Layout.php

@@ -175,13 +175,13 @@ class Layout
     /**
     /**
      * Set X-Mode.
      * Set X-Mode.
      *
      *
-     * @param X-Mode $value
+     * @param string $value
      *
      *
      * @return Layout
      * @return Layout
      */
      */
     public function setXMode($value)
     public function setXMode($value)
     {
     {
-        $this->xMode = $value;
+        $this->xMode = (string) $value;
 
 
         return $this;
         return $this;
     }
     }
@@ -199,13 +199,13 @@ class Layout
     /**
     /**
      * Set Y-Mode.
      * Set Y-Mode.
      *
      *
-     * @param Y-Mode $value
+     * @param string $value
      *
      *
      * @return Layout
      * @return Layout
      */
      */
     public function setYMode($value)
     public function setYMode($value)
     {
     {
-        $this->yMode = $value;
+        $this->yMode = (string) $value;
 
 
         return $this;
         return $this;
     }
     }
@@ -223,13 +223,13 @@ class Layout
     /**
     /**
      * Set X-Position.
      * Set X-Position.
      *
      *
-     * @param X-Position $value
+     * @param float $value
      *
      *
      * @return Layout
      * @return Layout
      */
      */
     public function setXPosition($value)
     public function setXPosition($value)
     {
     {
-        $this->xPos = $value;
+        $this->xPos = (float) $value;
 
 
         return $this;
         return $this;
     }
     }
@@ -247,13 +247,13 @@ class Layout
     /**
     /**
      * Set Y-Position.
      * Set Y-Position.
      *
      *
-     * @param Y-Position $value
+     * @param float $value
      *
      *
      * @return Layout
      * @return Layout
      */
      */
     public function setYPosition($value)
     public function setYPosition($value)
     {
     {
-        $this->yPos = $value;
+        $this->yPos = (float) $value;
 
 
         return $this;
         return $this;
     }
     }

+ 3 - 3
htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Collection/Cells.php

@@ -241,7 +241,7 @@ class Cells
      */
      */
     public function getHighestColumn($row = null)
     public function getHighestColumn($row = null)
     {
     {
-        if ($row == null) {
+        if ($row === null) {
             $colRow = $this->getHighestRowAndColumn();
             $colRow = $this->getHighestRowAndColumn();
 
 
             return $colRow['column'];
             return $colRow['column'];
@@ -259,7 +259,7 @@ class Cells
             $columnList[] = Coordinate::columnIndexFromString($c);
             $columnList[] = Coordinate::columnIndexFromString($c);
         }
         }
 
 
-        return Coordinate::stringFromColumnIndex(max($columnList) + 1);
+        return Coordinate::stringFromColumnIndex(max($columnList));
     }
     }
 
 
     /**
     /**
@@ -272,7 +272,7 @@ class Cells
      */
      */
     public function getHighestRow($column = null)
     public function getHighestRow($column = null)
     {
     {
-        if ($column == null) {
+        if ($column === null) {
             $colRow = $this->getHighestRowAndColumn();
             $colRow = $this->getHighestRowAndColumn();
 
 
             return $colRow['row'];
             return $colRow['row'];

+ 1 - 1
htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Document/Properties.php

@@ -418,7 +418,7 @@ class Properties
      *
      *
      * @param string $propertyName
      * @param string $propertyName
      *
      *
-     * @return string
+     * @return mixed
      */
      */
     public function getCustomPropertyValue($propertyName)
     public function getCustomPropertyValue($propertyName)
     {
     {

+ 6 - 85
htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/BaseReader.php

@@ -55,27 +55,16 @@ abstract class BaseReader implements IReader
      */
      */
     protected $securityScanner;
     protected $securityScanner;
 
 
-    /**
-     * Read data only?
-     *        If this is true, then the Reader will only read data values for cells, it will not read any formatting information.
-     *        If false (the default) it will read data and formatting.
-     *
-     * @return bool
-     */
+    public function __construct()
+    {
+        $this->readFilter = new DefaultReadFilter();
+    }
+
     public function getReadDataOnly()
     public function getReadDataOnly()
     {
     {
         return $this->readDataOnly;
         return $this->readDataOnly;
     }
     }
 
 
-    /**
-     * Set read data only
-     *        Set to true, to advise the Reader only to read data values for cells, and to ignore any formatting information.
-     *        Set to false (the default) to advise the Reader to read both data and formatting for cells.
-     *
-     * @param bool $pValue
-     *
-     * @return IReader
-     */
     public function setReadDataOnly($pValue)
     public function setReadDataOnly($pValue)
     {
     {
         $this->readDataOnly = (bool) $pValue;
         $this->readDataOnly = (bool) $pValue;
@@ -83,27 +72,11 @@ abstract class BaseReader implements IReader
         return $this;
         return $this;
     }
     }
 
 
-    /**
-     * Read empty cells?
-     *        If this is true (the default), then the Reader will read data values for all cells, irrespective of value.
-     *        If false it will not read data for cells containing a null value or an empty string.
-     *
-     * @return bool
-     */
     public function getReadEmptyCells()
     public function getReadEmptyCells()
     {
     {
         return $this->readEmptyCells;
         return $this->readEmptyCells;
     }
     }
 
 
-    /**
-     * Set read empty cells
-     *        Set to true (the default) to advise the Reader read data values for all cells, irrespective of value.
-     *        Set to false to advise the Reader to ignore cells containing a null value or an empty string.
-     *
-     * @param bool $pValue
-     *
-     * @return IReader
-     */
     public function setReadEmptyCells($pValue)
     public function setReadEmptyCells($pValue)
     {
     {
         $this->readEmptyCells = (bool) $pValue;
         $this->readEmptyCells = (bool) $pValue;
@@ -111,29 +84,11 @@ abstract class BaseReader implements IReader
         return $this;
         return $this;
     }
     }
 
 
-    /**
-     * Read charts in workbook?
-     *        If this is true, then the Reader will include any charts that exist in the workbook.
-     *      Note that a ReadDataOnly value of false overrides, and charts won't be read regardless of the IncludeCharts value.
-     *        If false (the default) it will ignore any charts defined in the workbook file.
-     *
-     * @return bool
-     */
     public function getIncludeCharts()
     public function getIncludeCharts()
     {
     {
         return $this->includeCharts;
         return $this->includeCharts;
     }
     }
 
 
-    /**
-     * Set read charts in workbook
-     *        Set to true, to advise the Reader to include any charts that exist in the workbook.
-     *      Note that a ReadDataOnly value of false overrides, and charts won't be read regardless of the IncludeCharts value.
-     *        Set to false (the default) to discard charts.
-     *
-     * @param bool $pValue
-     *
-     * @return IReader
-     */
     public function setIncludeCharts($pValue)
     public function setIncludeCharts($pValue)
     {
     {
         $this->includeCharts = (bool) $pValue;
         $this->includeCharts = (bool) $pValue;
@@ -141,27 +96,11 @@ abstract class BaseReader implements IReader
         return $this;
         return $this;
     }
     }
 
 
-    /**
-     * Get which sheets to load
-     * Returns either an array of worksheet names (the list of worksheets that should be loaded), or a null
-     *        indicating that all worksheets in the workbook should be loaded.
-     *
-     * @return mixed
-     */
     public function getLoadSheetsOnly()
     public function getLoadSheetsOnly()
     {
     {
         return $this->loadSheetsOnly;
         return $this->loadSheetsOnly;
     }
     }
 
 
-    /**
-     * Set which sheets to load.
-     *
-     * @param mixed $value
-     *        This should be either an array of worksheet names to be loaded, or a string containing a single worksheet name.
-     *        If NULL, then it tells the Reader to read all worksheets in the workbook
-     *
-     * @return IReader
-     */
     public function setLoadSheetsOnly($value)
     public function setLoadSheetsOnly($value)
     {
     {
         if ($value === null) {
         if ($value === null) {
@@ -173,12 +112,6 @@ abstract class BaseReader implements IReader
         return $this;
         return $this;
     }
     }
 
 
-    /**
-     * Set all sheets to load
-     *        Tells the Reader to load all worksheets from the workbook.
-     *
-     * @return IReader
-     */
     public function setLoadAllSheets()
     public function setLoadAllSheets()
     {
     {
         $this->loadSheetsOnly = null;
         $this->loadSheetsOnly = null;
@@ -186,23 +119,11 @@ abstract class BaseReader implements IReader
         return $this;
         return $this;
     }
     }
 
 
-    /**
-     * Read filter.
-     *
-     * @return IReadFilter
-     */
     public function getReadFilter()
     public function getReadFilter()
     {
     {
         return $this->readFilter;
         return $this->readFilter;
     }
     }
 
 
-    /**
-     * Set read filter.
-     *
-     * @param IReadFilter $pValue
-     *
-     * @return IReader
-     */
     public function setReadFilter(IReadFilter $pValue)
     public function setReadFilter(IReadFilter $pValue)
     {
     {
         $this->readFilter = $pValue;
         $this->readFilter = $pValue;
@@ -210,7 +131,7 @@ abstract class BaseReader implements IReader
         return $this;
         return $this;
     }
     }
 
 
-    public function getSecuritySCanner()
+    public function getSecurityScanner()
     {
     {
         if (property_exists($this, 'securityScanner')) {
         if (property_exists($this, 'securityScanner')) {
             return $this->securityScanner;
             return $this->securityScanner;

+ 13 - 13
htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Csv.php

@@ -62,7 +62,7 @@ class Csv extends BaseReader
      */
      */
     public function __construct()
     public function __construct()
     {
     {
-        $this->readFilter = new DefaultReadFilter();
+        parent::__construct();
     }
     }
 
 
     /**
     /**
@@ -143,7 +143,7 @@ class Csv extends BaseReader
             return;
             return;
         }
         }
 
 
-        return $this->skipBOM();
+        $this->skipBOM();
     }
     }
 
 
     /**
     /**
@@ -155,7 +155,7 @@ class Csv extends BaseReader
             return;
             return;
         }
         }
 
 
-        $potentialDelimiters = [',', ';', "\t", '|', ':', ' '];
+        $potentialDelimiters = [',', ';', "\t", '|', ':', ' ', '~'];
         $counts = [];
         $counts = [];
         foreach ($potentialDelimiters as $delimiter) {
         foreach ($potentialDelimiters as $delimiter) {
             $counts[$delimiter] = [];
             $counts[$delimiter] = [];
@@ -184,8 +184,9 @@ class Csv extends BaseReader
         // If number of lines is 0, nothing to infer : fall back to the default
         // If number of lines is 0, nothing to infer : fall back to the default
         if ($numberLines === 0) {
         if ($numberLines === 0) {
             $this->delimiter = reset($potentialDelimiters);
             $this->delimiter = reset($potentialDelimiters);
+            $this->skipBOM();
 
 
-            return $this->skipBOM();
+            return;
         }
         }
 
 
         // Calculate the mean square deviations for each delimiter (ignoring delimiters that haven't been found consistently)
         // Calculate the mean square deviations for each delimiter (ignoring delimiters that haven't been found consistently)
@@ -230,7 +231,7 @@ class Csv extends BaseReader
             $this->delimiter = reset($potentialDelimiters);
             $this->delimiter = reset($potentialDelimiters);
         }
         }
 
 
-        return $this->skipBOM();
+        $this->skipBOM();
     }
     }
 
 
     /**
     /**
@@ -254,15 +255,13 @@ class Csv extends BaseReader
         $line = $line . $newLine;
         $line = $line . $newLine;
 
 
         // Drop everything that is enclosed to avoid counting false positives in enclosures
         // Drop everything that is enclosed to avoid counting false positives in enclosures
-        $enclosure = preg_quote($this->enclosure, '/');
-        $line = preg_replace('/(' . $enclosure . '.*' . $enclosure . ')/U', '', $line);
+        $enclosure = '(?<!' . preg_quote($this->escapeCharacter, '/') . ')'
+            . preg_quote($this->enclosure, '/');
+        $line = preg_replace('/(' . $enclosure . '.*' . $enclosure . ')/Us', '', $line);
 
 
         // See if we have any enclosures left in the line
         // See if we have any enclosures left in the line
-        $matches = [];
-        preg_match('/(' . $enclosure . ')/', $line, $matches);
-
-        // if we still have an enclosure then we need to read the next line aswell
-        if (count($matches) > 0) {
+        // if we still have an enclosure then we need to read the next line as well
+        if (preg_match('/(' . $enclosure . ')/', $line) > 0) {
             $line = $this->getNextLine($line);
             $line = $this->getNextLine($line);
         }
         }
 
 
@@ -547,7 +546,8 @@ class Csv extends BaseReader
         fclose($this->fileHandle);
         fclose($this->fileHandle);
 
 
         // Trust file extension if any
         // Trust file extension if any
-        if (strtolower(pathinfo($pFilename, PATHINFO_EXTENSION)) === 'csv') {
+        $extension = strtolower(pathinfo($pFilename, PATHINFO_EXTENSION));
+        if (in_array($extension, ['csv', 'tsv'])) {
             return true;
             return true;
         }
         }
 
 

+ 1 - 1
htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Gnumeric.php

@@ -36,7 +36,7 @@ class Gnumeric extends BaseReader
      */
      */
     public function __construct()
     public function __construct()
     {
     {
-        $this->readFilter = new DefaultReadFilter();
+        parent::__construct();
         $this->referenceHelper = ReferenceHelper::getInstance();
         $this->referenceHelper = ReferenceHelper::getInstance();
         $this->securityScanner = XmlScanner::getInstance($this);
         $this->securityScanner = XmlScanner::getInstance($this);
     }
     }

+ 309 - 19
htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Html.php

@@ -12,6 +12,9 @@ use PhpOffice\PhpSpreadsheet\Spreadsheet;
 use PhpOffice\PhpSpreadsheet\Style\Border;
 use PhpOffice\PhpSpreadsheet\Style\Border;
 use PhpOffice\PhpSpreadsheet\Style\Color;
 use PhpOffice\PhpSpreadsheet\Style\Color;
 use PhpOffice\PhpSpreadsheet\Style\Fill;
 use PhpOffice\PhpSpreadsheet\Style\Fill;
+use PhpOffice\PhpSpreadsheet\Style\Font;
+use PhpOffice\PhpSpreadsheet\Style\Style;
+use PhpOffice\PhpSpreadsheet\Worksheet\Drawing;
 use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
 use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
 
 
 /** PhpSpreadsheet root directory */
 /** PhpSpreadsheet root directory */
@@ -96,6 +99,26 @@ class Html extends BaseReader
                 ],
                 ],
             ],
             ],
         ], //    Bottom border
         ], //    Bottom border
+        'strong' => [
+            'font' => [
+                'bold' => true,
+            ],
+        ], //    Bold
+        'b' => [
+            'font' => [
+                'bold' => true,
+            ],
+        ], //    Bold
+        'i' => [
+            'font' => [
+                'italic' => true,
+            ],
+        ], //    Italic
+        'em' => [
+            'font' => [
+                'italic' => true,
+            ],
+        ], //    Italic
     ];
     ];
 
 
     protected $rowspan = [];
     protected $rowspan = [];
@@ -105,7 +128,7 @@ class Html extends BaseReader
      */
      */
     public function __construct()
     public function __construct()
     {
     {
-        $this->readFilter = new DefaultReadFilter();
+        parent::__construct();
         $this->securityScanner = XmlScanner::getInstance($this);
         $this->securityScanner = XmlScanner::getInstance($this);
     }
     }
 
 
@@ -295,11 +318,9 @@ class Html extends BaseReader
                 switch ($child->nodeName) {
                 switch ($child->nodeName) {
                     case 'meta':
                     case 'meta':
                         foreach ($attributeArray as $attributeName => $attributeValue) {
                         foreach ($attributeArray as $attributeName => $attributeValue) {
-                            switch ($attributeName) {
-                                case 'content':
-                                    //    TODO
-                                    //    Extract character set, so we can convert to UTF-8 if required
-                                    break;
+                            // Extract character set, so we can convert to UTF-8 if required
+                            if ($attributeName === 'charset') {
+                                $this->setInputEncoding($attributeValue);
                             }
                             }
                         }
                         }
                         $this->processDomElement($child, $sheet, $row, $column, $cellContent);
                         $this->processDomElement($child, $sheet, $row, $column, $cellContent);
@@ -334,6 +355,10 @@ class Html extends BaseReader
                             $cellContent .= ' ';
                             $cellContent .= ' ';
                         }
                         }
 
 
+                        if (isset($this->formats[$child->nodeName])) {
+                            $sheet->getStyle($column . $row)->applyFromArray($this->formats[$child->nodeName]);
+                        }
+
                         break;
                         break;
                     case 'hr':
                     case 'hr':
                         $this->flushCell($sheet, $column, $row, $cellContent);
                         $this->flushCell($sheet, $column, $row, $cellContent);
@@ -423,6 +448,10 @@ class Html extends BaseReader
                             $column = 'A';
                             $column = 'A';
                         }
                         }
 
 
+                        break;
+                    case 'img':
+                        $this->insertImage($sheet, $column, $row, $attributeArray);
+
                         break;
                         break;
                     case 'table':
                     case 'table':
                         $this->flushCell($sheet, $column, $row, $cellContent);
                         $this->flushCell($sheet, $column, $row, $cellContent);
@@ -448,6 +477,11 @@ class Html extends BaseReader
                         $column = $this->getTableStartColumn();
                         $column = $this->getTableStartColumn();
                         $cellContent = '';
                         $cellContent = '';
                         $this->processDomElement($child, $sheet, $row, $column, $cellContent);
                         $this->processDomElement($child, $sheet, $row, $column, $cellContent);
+
+                        if (isset($attributeArray['height'])) {
+                            $sheet->getRowDimension($row)->setRowHeight($attributeArray['height']);
+                        }
+
                         ++$row;
                         ++$row;
 
 
                         break;
                         break;
@@ -501,6 +535,27 @@ class Html extends BaseReader
                                 ]
                                 ]
                             );
                             );
                         }
                         }
+
+                        if (isset($attributeArray['width'])) {
+                            $sheet->getColumnDimension($column)->setWidth($attributeArray['width']);
+                        }
+
+                        if (isset($attributeArray['height'])) {
+                            $sheet->getRowDimension($row)->setRowHeight($attributeArray['height']);
+                        }
+
+                        if (isset($attributeArray['align'])) {
+                            $sheet->getStyle($column . $row)->getAlignment()->setHorizontal($attributeArray['align']);
+                        }
+
+                        if (isset($attributeArray['valign'])) {
+                            $sheet->getStyle($column . $row)->getAlignment()->setVertical($attributeArray['valign']);
+                        }
+
+                        if (isset($attributeArray['data-format'])) {
+                            $sheet->getStyle($column . $row)->getNumberFormat()->setFormatCode($attributeArray['data-format']);
+                        }
+
                         ++$column;
                         ++$column;
 
 
                         break;
                         break;
@@ -608,36 +663,271 @@ class Html extends BaseReader
             return;
             return;
         }
         }
 
 
-        $supported_styles = ['background-color', 'color'];
+        $cellStyle = $sheet->getStyle($column . $row);
 
 
         // add color styles (background & text) from dom element,currently support : td & th, using ONLY inline css style with RGB color
         // add color styles (background & text) from dom element,currently support : td & th, using ONLY inline css style with RGB color
         $styles = explode(';', $attributeArray['style']);
         $styles = explode(';', $attributeArray['style']);
         foreach ($styles as $st) {
         foreach ($styles as $st) {
             $value = explode(':', $st);
             $value = explode(':', $st);
+            $styleName = isset($value[0]) ? trim($value[0]) : null;
+            $styleValue = isset($value[1]) ? trim($value[1]) : null;
 
 
-            if (empty(trim($value[0])) || !in_array(trim($value[0]), $supported_styles)) {
+            if (!$styleName) {
                 continue;
                 continue;
             }
             }
 
 
-            //check if has #, so we can get clean hex
-            if (substr(trim($value[1]), 0, 1) == '#') {
-                $style_color = substr(trim($value[1]), 1);
-            }
+            switch ($styleName) {
+                case 'background':
+                case 'background-color':
+                    $styleColor = $this->getStyleColor($styleValue);
 
 
-            if (empty($style_color)) {
-                continue;
-            }
+                    if (!$styleColor) {
+                        continue 2;
+                    }
 
 
-            switch (trim($value[0])) {
-                case 'background-color':
-                    $sheet->getStyle($column . $row)->applyFromArray(['fill' => ['fillType' => Fill::FILL_SOLID, 'color' => ['rgb' => "{$style_color}"]]]);
+                    $cellStyle->applyFromArray(['fill' => ['fillType' => Fill::FILL_SOLID, 'color' => ['rgb' => $styleColor]]]);
 
 
                     break;
                     break;
                 case 'color':
                 case 'color':
-                    $sheet->getStyle($column . $row)->applyFromArray(['font' => ['color' => ['rgb' => "{$style_color}"]]]);
+                    $styleColor = $this->getStyleColor($styleValue);
+
+                    if (!$styleColor) {
+                        continue 2;
+                    }
+
+                    $cellStyle->applyFromArray(['font' => ['color' => ['rgb' => $styleColor]]]);
+
+                    break;
+
+                case 'border':
+                    $this->setBorderStyle($cellStyle, $styleValue, 'allBorders');
+
+                    break;
+
+                case 'border-top':
+                    $this->setBorderStyle($cellStyle, $styleValue, 'top');
+
+                    break;
+
+                case 'border-bottom':
+                    $this->setBorderStyle($cellStyle, $styleValue, 'bottom');
+
+                    break;
+
+                case 'border-left':
+                    $this->setBorderStyle($cellStyle, $styleValue, 'left');
+
+                    break;
+
+                case 'border-right':
+                    $this->setBorderStyle($cellStyle, $styleValue, 'right');
+
+                    break;
+
+                case 'font-size':
+                    $cellStyle->getFont()->setSize(
+                        (float) $styleValue
+                    );
+
+                    break;
+
+                case 'font-weight':
+                    if ($styleValue === 'bold' || $styleValue >= 500) {
+                        $cellStyle->getFont()->setBold(true);
+                    }
+
+                    break;
+
+                case 'font-style':
+                    if ($styleValue === 'italic') {
+                        $cellStyle->getFont()->setItalic(true);
+                    }
+
+                    break;
+
+                case 'font-family':
+                    $cellStyle->getFont()->setName(str_replace('\'', '', $styleValue));
+
+                    break;
+
+                case 'text-decoration':
+                    switch ($styleValue) {
+                        case 'underline':
+                            $cellStyle->getFont()->setUnderline(Font::UNDERLINE_SINGLE);
+
+                            break;
+                        case 'line-through':
+                            $cellStyle->getFont()->setStrikethrough(true);
+
+                            break;
+                    }
+
+                    break;
+
+                case 'text-align':
+                    $cellStyle->getAlignment()->setHorizontal($styleValue);
+
+                    break;
+
+                case 'vertical-align':
+                    $cellStyle->getAlignment()->setVertical($styleValue);
+
+                    break;
+
+                case 'width':
+                    $sheet->getColumnDimension($column)->setWidth(
+                        str_replace('px', '', $styleValue)
+                    );
+
+                    break;
+
+                case 'height':
+                    $sheet->getRowDimension($row)->setRowHeight(
+                        str_replace('px', '', $styleValue)
+                    );
+
+                    break;
+
+                case 'word-wrap':
+                    $cellStyle->getAlignment()->setWrapText(
+                        $styleValue === 'break-word'
+                    );
+
+                    break;
+
+                case 'text-indent':
+                    $cellStyle->getAlignment()->setIndent(
+                        (int) str_replace(['px'], '', $styleValue)
+                    );
 
 
                     break;
                     break;
             }
             }
         }
         }
     }
     }
+
+    /**
+     * Check if has #, so we can get clean hex.
+     *
+     * @param $value
+     *
+     * @return null|string
+     */
+    public function getStyleColor($value)
+    {
+        if (strpos($value, '#') === 0) {
+            return substr($value, 1);
+        }
+
+        return null;
+    }
+
+    /**
+     * @param Worksheet $sheet
+     * @param string    $column
+     * @param int       $row
+     * @param array     $attributes
+     *
+     * @throws \PhpOffice\PhpSpreadsheet\Exception
+     */
+    private function insertImage(Worksheet $sheet, $column, $row, array $attributes)
+    {
+        if (!isset($attributes['src'])) {
+            return;
+        }
+
+        $src = urldecode($attributes['src']);
+        $width = isset($attributes['width']) ? (float) $attributes['width'] : null;
+        $height = isset($attributes['height']) ? (float) $attributes['height'] : null;
+        $name = isset($attributes['alt']) ? (float) $attributes['alt'] : null;
+
+        $drawing = new Drawing();
+        $drawing->setPath($src);
+        $drawing->setWorksheet($sheet);
+        $drawing->setCoordinates($column . $row);
+        $drawing->setOffsetX(0);
+        $drawing->setOffsetY(10);
+        $drawing->setResizeProportional(true);
+
+        if ($name) {
+            $drawing->setName($name);
+        }
+
+        if ($width) {
+            $drawing->setWidth((int) $width);
+        }
+
+        if ($height) {
+            $drawing->setHeight((int) $height);
+        }
+
+        $sheet->getColumnDimension($column)->setWidth(
+            $drawing->getWidth() / 6
+        );
+
+        $sheet->getRowDimension($row)->setRowHeight(
+            $drawing->getHeight() * 0.9
+        );
+    }
+
+    /**
+     * Map html border style to PhpSpreadsheet border style.
+     *
+     * @param  string $style
+     *
+     * @return null|string
+     */
+    public function getBorderStyle($style)
+    {
+        switch ($style) {
+            case 'solid':
+                return Border::BORDER_THIN;
+            case 'dashed':
+                return Border::BORDER_DASHED;
+            case 'dotted':
+                return Border::BORDER_DOTTED;
+            case 'medium':
+                return Border::BORDER_MEDIUM;
+            case 'thick':
+                return Border::BORDER_THICK;
+            case 'none':
+                return Border::BORDER_NONE;
+            case 'dash-dot':
+                return Border::BORDER_DASHDOT;
+            case 'dash-dot-dot':
+                return Border::BORDER_DASHDOTDOT;
+            case 'double':
+                return Border::BORDER_DOUBLE;
+            case 'hair':
+                return Border::BORDER_HAIR;
+            case 'medium-dash-dot':
+                return Border::BORDER_MEDIUMDASHDOT;
+            case 'medium-dash-dot-dot':
+                return Border::BORDER_MEDIUMDASHDOTDOT;
+            case 'medium-dashed':
+                return Border::BORDER_MEDIUMDASHED;
+            case 'slant-dash-dot':
+                return Border::BORDER_SLANTDASHDOT;
+        }
+
+        return null;
+    }
+
+    /**
+     * @param Style  $cellStyle
+     * @param string $styleValue
+     * @param string $type
+     */
+    private function setBorderStyle(Style $cellStyle, $styleValue, $type)
+    {
+        list(, $borderStyle, $color) = explode(' ', $styleValue);
+
+        $cellStyle->applyFromArray([
+            'borders' => [
+                $type => [
+                    'borderStyle' => $this->getBorderStyle($borderStyle),
+                    'color' => ['rgb' => $this->getStyleColor($color)],
+                ],
+            ],
+        ]);
+    }
 }
 }

+ 106 - 0
htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/IReader.php

@@ -18,6 +18,112 @@ interface IReader
      */
      */
     public function canRead($pFilename);
     public function canRead($pFilename);
 
 
+    /**
+     * Read data only?
+     *        If this is true, then the Reader will only read data values for cells, it will not read any formatting information.
+     *        If false (the default) it will read data and formatting.
+     *
+     * @return bool
+     */
+    public function getReadDataOnly();
+
+    /**
+     * Set read data only
+     *        Set to true, to advise the Reader only to read data values for cells, and to ignore any formatting information.
+     *        Set to false (the default) to advise the Reader to read both data and formatting for cells.
+     *
+     * @param bool $pValue
+     *
+     * @return IReader
+     */
+    public function setReadDataOnly($pValue);
+
+    /**
+     * Read empty cells?
+     *        If this is true (the default), then the Reader will read data values for all cells, irrespective of value.
+     *        If false it will not read data for cells containing a null value or an empty string.
+     *
+     * @return bool
+     */
+    public function getReadEmptyCells();
+
+    /**
+     * Set read empty cells
+     *        Set to true (the default) to advise the Reader read data values for all cells, irrespective of value.
+     *        Set to false to advise the Reader to ignore cells containing a null value or an empty string.
+     *
+     * @param bool $pValue
+     *
+     * @return IReader
+     */
+    public function setReadEmptyCells($pValue);
+
+    /**
+     * Read charts in workbook?
+     *        If this is true, then the Reader will include any charts that exist in the workbook.
+     *      Note that a ReadDataOnly value of false overrides, and charts won't be read regardless of the IncludeCharts value.
+     *        If false (the default) it will ignore any charts defined in the workbook file.
+     *
+     * @return bool
+     */
+    public function getIncludeCharts();
+
+    /**
+     * Set read charts in workbook
+     *        Set to true, to advise the Reader to include any charts that exist in the workbook.
+     *      Note that a ReadDataOnly value of false overrides, and charts won't be read regardless of the IncludeCharts value.
+     *        Set to false (the default) to discard charts.
+     *
+     * @param bool $pValue
+     *
+     * @return IReader
+     */
+    public function setIncludeCharts($pValue);
+
+    /**
+     * Get which sheets to load
+     * Returns either an array of worksheet names (the list of worksheets that should be loaded), or a null
+     *        indicating that all worksheets in the workbook should be loaded.
+     *
+     * @return mixed
+     */
+    public function getLoadSheetsOnly();
+
+    /**
+     * Set which sheets to load.
+     *
+     * @param mixed $value
+     *        This should be either an array of worksheet names to be loaded, or a string containing a single worksheet name.
+     *        If NULL, then it tells the Reader to read all worksheets in the workbook
+     *
+     * @return IReader
+     */
+    public function setLoadSheetsOnly($value);
+
+    /**
+     * Set all sheets to load
+     *        Tells the Reader to load all worksheets from the workbook.
+     *
+     * @return IReader
+     */
+    public function setLoadAllSheets();
+
+    /**
+     * Read filter.
+     *
+     * @return IReadFilter
+     */
+    public function getReadFilter();
+
+    /**
+     * Set read filter.
+     *
+     * @param IReadFilter $pValue
+     *
+     * @return IReader
+     */
+    public function setReadFilter(IReadFilter $pValue);
+
     /**
     /**
      * Loads PhpSpreadsheet from file.
      * Loads PhpSpreadsheet from file.
      *
      *

+ 16 - 100
htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Ods.php

@@ -7,7 +7,7 @@ use DateTimeZone;
 use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
 use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
 use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
 use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
 use PhpOffice\PhpSpreadsheet\Cell\DataType;
 use PhpOffice\PhpSpreadsheet\Cell\DataType;
-use PhpOffice\PhpSpreadsheet\Document\Properties;
+use PhpOffice\PhpSpreadsheet\Reader\Ods\Properties as DocumentProperties;
 use PhpOffice\PhpSpreadsheet\Reader\Security\XmlScanner;
 use PhpOffice\PhpSpreadsheet\Reader\Security\XmlScanner;
 use PhpOffice\PhpSpreadsheet\RichText\RichText;
 use PhpOffice\PhpSpreadsheet\RichText\RichText;
 use PhpOffice\PhpSpreadsheet\Settings;
 use PhpOffice\PhpSpreadsheet\Settings;
@@ -25,7 +25,7 @@ class Ods extends BaseReader
      */
      */
     public function __construct()
     public function __construct()
     {
     {
-        $this->readFilter = new DefaultReadFilter();
+        parent::__construct();
         $this->securityScanner = XmlScanner::getInstance($this);
         $this->securityScanner = XmlScanner::getInstance($this);
     }
     }
 
 
@@ -52,7 +52,7 @@ class Ods extends BaseReader
             $stat = $zip->statName('mimetype');
             $stat = $zip->statName('mimetype');
             if ($stat && ($stat['size'] <= 255)) {
             if ($stat && ($stat['size'] <= 255)) {
                 $mimeType = $zip->getFromName($stat['name']);
                 $mimeType = $zip->getFromName($stat['name']);
-            } elseif ($stat = $zip->statName('META-INF/manifest.xml')) {
+            } elseif ($zip->statName('META-INF/manifest.xml')) {
                 $xml = simplexml_load_string(
                 $xml = simplexml_load_string(
                     $this->securityScanner->scan($zip->getFromName('META-INF/manifest.xml')),
                     $this->securityScanner->scan($zip->getFromName('META-INF/manifest.xml')),
                     'SimpleXMLElement',
                     'SimpleXMLElement',
@@ -265,7 +265,7 @@ class Ods extends BaseReader
 
 
         $zip = new ZipArchive();
         $zip = new ZipArchive();
         if (!$zip->open($pFilename)) {
         if (!$zip->open($pFilename)) {
-            throw new Exception('Could not open ' . $pFilename . ' for reading! Error opening file.');
+            throw new Exception("Could not open {$pFilename} for reading! Error opening file.");
         }
         }
 
 
         // Meta
         // Meta
@@ -275,97 +275,13 @@ class Ods extends BaseReader
             'SimpleXMLElement',
             'SimpleXMLElement',
             Settings::getLibXmlLoaderOptions()
             Settings::getLibXmlLoaderOptions()
         );
         );
-        $namespacesMeta = $xml->getNamespaces(true);
+        if ($xml === false) {
+            throw new Exception('Unable to read data from {$pFilename}');
+        }
 
 
-        $docProps = $spreadsheet->getProperties();
-        $officeProperty = $xml->children($namespacesMeta['office']);
-        foreach ($officeProperty as $officePropertyData) {
-            $officePropertyDC = [];
-            if (isset($namespacesMeta['dc'])) {
-                $officePropertyDC = $officePropertyData->children($namespacesMeta['dc']);
-            }
-            foreach ($officePropertyDC as $propertyName => $propertyValue) {
-                $propertyValue = (string) $propertyValue;
-                switch ($propertyName) {
-                    case 'title':
-                        $docProps->setTitle($propertyValue);
-
-                        break;
-                    case 'subject':
-                        $docProps->setSubject($propertyValue);
-
-                        break;
-                    case 'creator':
-                        $docProps->setCreator($propertyValue);
-                        $docProps->setLastModifiedBy($propertyValue);
-
-                        break;
-                    case 'date':
-                        $creationDate = strtotime($propertyValue);
-                        $docProps->setCreated($creationDate);
-                        $docProps->setModified($creationDate);
-
-                        break;
-                    case 'description':
-                        $docProps->setDescription($propertyValue);
-
-                        break;
-                }
-            }
-            $officePropertyMeta = [];
-            if (isset($namespacesMeta['dc'])) {
-                $officePropertyMeta = $officePropertyData->children($namespacesMeta['meta']);
-            }
-            foreach ($officePropertyMeta as $propertyName => $propertyValue) {
-                $propertyValueAttributes = $propertyValue->attributes($namespacesMeta['meta']);
-                $propertyValue = (string) $propertyValue;
-                switch ($propertyName) {
-                    case 'initial-creator':
-                        $docProps->setCreator($propertyValue);
-
-                        break;
-                    case 'keyword':
-                        $docProps->setKeywords($propertyValue);
-
-                        break;
-                    case 'creation-date':
-                        $creationDate = strtotime($propertyValue);
-                        $docProps->setCreated($creationDate);
-
-                        break;
-                    case 'user-defined':
-                        $propertyValueType = Properties::PROPERTY_TYPE_STRING;
-                        foreach ($propertyValueAttributes as $key => $value) {
-                            if ($key == 'name') {
-                                $propertyValueName = (string) $value;
-                            } elseif ($key == 'value-type') {
-                                switch ($value) {
-                                    case 'date':
-                                        $propertyValue = Properties::convertProperty($propertyValue, 'date');
-                                        $propertyValueType = Properties::PROPERTY_TYPE_DATE;
-
-                                        break;
-                                    case 'boolean':
-                                        $propertyValue = Properties::convertProperty($propertyValue, 'bool');
-                                        $propertyValueType = Properties::PROPERTY_TYPE_BOOLEAN;
-
-                                        break;
-                                    case 'float':
-                                        $propertyValue = Properties::convertProperty($propertyValue, 'r4');
-                                        $propertyValueType = Properties::PROPERTY_TYPE_FLOAT;
-
-                                        break;
-                                    default:
-                                        $propertyValueType = Properties::PROPERTY_TYPE_STRING;
-                                }
-                            }
-                        }
-                        $docProps->setCustomProperty($propertyValueName, $propertyValue, $propertyValueType);
+        $namespacesMeta = $xml->getNamespaces(true);
 
 
-                        break;
-                }
-            }
-        }
+        (new DocumentProperties($spreadsheet))->load($xml, $namespacesMeta);
 
 
         // Content
         // Content
 
 
@@ -513,7 +429,7 @@ class Ods extends BaseReader
                                     foreach ($paragraphs as $pData) {
                                     foreach ($paragraphs as $pData) {
                                         $dataArray[] = $this->scanElementForText($pData);
                                         $dataArray[] = $this->scanElementForText($pData);
                                     }
                                     }
-                                    $allCellDataText = implode($dataArray, "\n");
+                                    $allCellDataText = implode("\n", $dataArray);
 
 
                                     $type = $cellData->getAttributeNS($officeNs, 'value-type');
                                     $type = $cellData->getAttributeNS($officeNs, 'value-type');
 
 
@@ -580,12 +496,12 @@ class Ods extends BaseReader
                                             );
                                             );
 
 
                                             $dataValue = Date::formattedPHPToExcel(
                                             $dataValue = Date::formattedPHPToExcel(
-                                                $year,
-                                                $month,
-                                                $day,
-                                                $hour,
-                                                $minute,
-                                                $second
+                                                (int) $year,
+                                                (int) $month,
+                                                (int) $day,
+                                                (int) $hour,
+                                                (int) $minute,
+                                                (int) $second
                                             );
                                             );
 
 
                                             if ($dataValue != floor($dataValue)) {
                                             if ($dataValue != floor($dataValue)) {

+ 136 - 0
htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Ods/Properties.php

@@ -0,0 +1,136 @@
+<?php
+
+namespace PhpOffice\PhpSpreadsheet\Reader\Ods;
+
+use PhpOffice\PhpSpreadsheet\Document\Properties as DocumentProperties;
+use PhpOffice\PhpSpreadsheet\Spreadsheet;
+
+class Properties
+{
+    private $spreadsheet;
+
+    public function __construct(Spreadsheet $spreadsheet)
+    {
+        $this->spreadsheet = $spreadsheet;
+    }
+
+    public function load(\SimpleXMLElement $xml, $namespacesMeta)
+    {
+        $docProps = $this->spreadsheet->getProperties();
+        $officeProperty = $xml->children($namespacesMeta['office']);
+        foreach ($officeProperty as $officePropertyData) {
+            /** @var \SimpleXMLElement $officePropertyData */
+            $officePropertiesDC = (object) [];
+            if (isset($namespacesMeta['dc'])) {
+                $officePropertiesDC = $officePropertyData->children($namespacesMeta['dc']);
+            }
+            $this->setCoreProperties($docProps, $officePropertiesDC);
+
+            $officePropertyMeta = (object) [];
+            if (isset($namespacesMeta['dc'])) {
+                $officePropertyMeta = $officePropertyData->children($namespacesMeta['meta']);
+            }
+            foreach ($officePropertyMeta as $propertyName => $propertyValue) {
+                $this->setMetaProperties($namespacesMeta, $propertyValue, $propertyName, $docProps);
+            }
+        }
+    }
+
+    private function setCoreProperties(DocumentProperties $docProps, \SimpleXMLElement $officePropertyDC)
+    {
+        foreach ($officePropertyDC as $propertyName => $propertyValue) {
+            $propertyValue = (string) $propertyValue;
+            switch ($propertyName) {
+                case 'title':
+                    $docProps->setTitle($propertyValue);
+
+                    break;
+                case 'subject':
+                    $docProps->setSubject($propertyValue);
+
+                    break;
+                case 'creator':
+                    $docProps->setCreator($propertyValue);
+                    $docProps->setLastModifiedBy($propertyValue);
+
+                    break;
+                case 'creation-date':
+                    $creationDate = strtotime($propertyValue);
+                    $docProps->setCreated($creationDate);
+                    $docProps->setModified($creationDate);
+
+                    break;
+                case 'keyword':
+                    $docProps->setKeywords($propertyValue);
+
+                    break;
+                case 'description':
+                    $docProps->setDescription($propertyValue);
+
+                    break;
+            }
+        }
+    }
+
+    private function setMetaProperties(
+        $namespacesMeta,
+        \SimpleXMLElement $propertyValue,
+        $propertyName,
+        DocumentProperties $docProps
+    ) {
+        $propertyValueAttributes = $propertyValue->attributes($namespacesMeta['meta']);
+        $propertyValue = (string) $propertyValue;
+        switch ($propertyName) {
+            case 'initial-creator':
+                $docProps->setCreator($propertyValue);
+
+                break;
+            case 'keyword':
+                $docProps->setKeywords($propertyValue);
+
+                break;
+            case 'creation-date':
+                $creationDate = strtotime($propertyValue);
+                $docProps->setCreated($creationDate);
+
+                break;
+            case 'user-defined':
+                $this->setUserDefinedProperty($propertyValueAttributes, $propertyValue, $docProps);
+
+                break;
+        }
+    }
+
+    private function setUserDefinedProperty($propertyValueAttributes, $propertyValue, DocumentProperties $docProps)
+    {
+        $propertyValueName = '';
+        $propertyValueType = DocumentProperties::PROPERTY_TYPE_STRING;
+        foreach ($propertyValueAttributes as $key => $value) {
+            if ($key == 'name') {
+                $propertyValueName = (string) $value;
+            } elseif ($key == 'value-type') {
+                switch ($value) {
+                    case 'date':
+                        $propertyValue = DocumentProperties::convertProperty($propertyValue, 'date');
+                        $propertyValueType = DocumentProperties::PROPERTY_TYPE_DATE;
+
+                        break;
+                    case 'boolean':
+                        $propertyValue = DocumentProperties::convertProperty($propertyValue, 'bool');
+                        $propertyValueType = DocumentProperties::PROPERTY_TYPE_BOOLEAN;
+
+                        break;
+                    case 'float':
+                        $propertyValue = DocumentProperties::convertProperty($propertyValue, 'r4');
+                        $propertyValueType = DocumentProperties::PROPERTY_TYPE_FLOAT;
+
+                        break;
+                    default:
+                        $propertyValueType = DocumentProperties::PROPERTY_TYPE_STRING;
+                }
+            }
+        }
+
+        $docProps->setCustomProperty($propertyValueName, $propertyValue, $propertyValueType);
+    }
+}

+ 60 - 31
htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Security/XmlScanner.php

@@ -3,16 +3,10 @@
 namespace PhpOffice\PhpSpreadsheet\Reader\Security;
 namespace PhpOffice\PhpSpreadsheet\Reader\Security;
 
 
 use PhpOffice\PhpSpreadsheet\Reader;
 use PhpOffice\PhpSpreadsheet\Reader;
+use PhpOffice\PhpSpreadsheet\Settings;
 
 
 class XmlScanner
 class XmlScanner
 {
 {
-    /**
-     * Identifies whether the thread-safe libxmlDisableEntityLoader() function is available.
-     *
-     * @var bool
-     */
-    private $libxmlDisableEntityLoader = false;
-
     /**
     /**
      * String used to identify risky xml elements.
      * String used to identify risky xml elements.
      *
      *
@@ -22,10 +16,16 @@ class XmlScanner
 
 
     private $callback;
     private $callback;
 
 
-    private function __construct($pattern = '<!DOCTYPE')
+    private static $libxmlDisableEntityLoaderValue;
+
+    public function __construct($pattern = '<!DOCTYPE')
     {
     {
         $this->pattern = $pattern;
         $this->pattern = $pattern;
-        $this->libxmlDisableEntityLoader = $this->identifyLibxmlDisableEntityLoaderAvailability();
+
+        $this->disableEntityLoaderCheck();
+
+        // A fatal error will bypass the destructor, so we register a shutdown here
+        register_shutdown_function([__CLASS__, 'shutdown']);
     }
     }
 
 
     public static function getInstance(Reader\IReader $reader)
     public static function getInstance(Reader\IReader $reader)
@@ -43,7 +43,7 @@ class XmlScanner
         }
         }
     }
     }
 
 
-    private function identifyLibxmlDisableEntityLoaderAvailability()
+    public static function threadSafeLibxmlDisableEntityLoaderAvailability()
     {
     {
         if (PHP_MAJOR_VERSION == 7) {
         if (PHP_MAJOR_VERSION == 7) {
             switch (PHP_MINOR_VERSION) {
             switch (PHP_MINOR_VERSION) {
@@ -61,11 +61,54 @@ class XmlScanner
         return false;
         return false;
     }
     }
 
 
+    private function disableEntityLoaderCheck()
+    {
+        if (Settings::getLibXmlDisableEntityLoader()) {
+            $libxmlDisableEntityLoaderValue = libxml_disable_entity_loader(true);
+
+            if (self::$libxmlDisableEntityLoaderValue === null) {
+                self::$libxmlDisableEntityLoaderValue = $libxmlDisableEntityLoaderValue;
+            }
+        }
+    }
+
+    public static function shutdown()
+    {
+        if (self::$libxmlDisableEntityLoaderValue !== null) {
+            libxml_disable_entity_loader(self::$libxmlDisableEntityLoaderValue);
+            self::$libxmlDisableEntityLoaderValue = null;
+        }
+    }
+
+    public function __destruct()
+    {
+        self::shutdown();
+    }
+
     public function setAdditionalCallback(callable $callback)
     public function setAdditionalCallback(callable $callback)
     {
     {
         $this->callback = $callback;
         $this->callback = $callback;
     }
     }
 
 
+    private function toUtf8($xml)
+    {
+        $pattern = '/encoding="(.*?)"/';
+        $result = preg_match($pattern, $xml, $matches);
+        $charset = strtoupper($result ? $matches[1] : 'UTF-8');
+
+        if ($charset !== 'UTF-8') {
+            $xml = mb_convert_encoding($xml, 'UTF-8', $charset);
+
+            $result = preg_match($pattern, $xml, $matches);
+            $charset = strtoupper($result ? $matches[1] : 'UTF-8');
+            if ($charset !== 'UTF-8') {
+                throw new Reader\Exception('Suspicious Double-encoded XML, spreadsheet file load() aborted to prevent XXE/XEE attacks');
+            }
+        }
+
+        return $xml;
+    }
+
     /**
     /**
      * Scan the XML for use of <!ENTITY to prevent XXE/XEE attacks.
      * Scan the XML for use of <!ENTITY to prevent XXE/XEE attacks.
      *
      *
@@ -77,33 +120,19 @@ class XmlScanner
      */
      */
     public function scan($xml)
     public function scan($xml)
     {
     {
-        if ($this->libxmlDisableEntityLoader) {
-            $previousLibxmlDisableEntityLoaderValue = libxml_disable_entity_loader(true);
-        }
+        $this->disableEntityLoaderCheck();
 
 
-        $pattern = '/encoding="(.*?)"/';
-        $result = preg_match($pattern, $xml, $matches);
-        $charset = $result ? $matches[1] : 'UTF-8';
-
-        if ($charset !== 'UTF-8') {
-            $xml = mb_convert_encoding($xml, 'UTF-8', $charset);
-        }
+        $xml = $this->toUtf8($xml);
 
 
         // Don't rely purely on libxml_disable_entity_loader()
         // Don't rely purely on libxml_disable_entity_loader()
         $pattern = '/\\0?' . implode('\\0?', str_split($this->pattern)) . '\\0?/';
         $pattern = '/\\0?' . implode('\\0?', str_split($this->pattern)) . '\\0?/';
 
 
-        try {
-            if (preg_match($pattern, $xml)) {
-                throw new Reader\Exception('Detected use of ENTITY in XML, spreadsheet file load() aborted to prevent XXE/XEE attacks');
-            }
+        if (preg_match($pattern, $xml)) {
+            throw new Reader\Exception('Detected use of ENTITY in XML, spreadsheet file load() aborted to prevent XXE/XEE attacks');
+        }
 
 
-            if ($this->callback !== null && is_callable($this->callback)) {
-                $xml = call_user_func($this->callback, $xml);
-            }
-        } finally {
-            if (isset($previousLibxmlDisableEntityLoaderValue)) {
-                libxml_disable_entity_loader($previousLibxmlDisableEntityLoaderValue);
-            }
+        if ($this->callback !== null && is_callable($this->callback)) {
+            $xml = call_user_func($this->callback, $xml);
         }
         }
 
 
         return $xml;
         return $xml;

+ 1 - 1
htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Slk.php

@@ -43,7 +43,7 @@ class Slk extends BaseReader
      */
      */
     public function __construct()
     public function __construct()
     {
     {
-        $this->readFilter = new DefaultReadFilter();
+        parent::__construct();
     }
     }
 
 
     /**
     /**

+ 1 - 1
htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xls.php

@@ -412,7 +412,7 @@ class Xls extends BaseReader
      */
      */
     public function __construct()
     public function __construct()
     {
     {
-        $this->readFilter = new DefaultReadFilter();
+        parent::__construct();
     }
     }
 
 
     /**
     /**

+ 113 - 688
htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xlsx.php

@@ -4,10 +4,19 @@ namespace PhpOffice\PhpSpreadsheet\Reader;
 
 
 use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
 use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
 use PhpOffice\PhpSpreadsheet\Cell\Hyperlink;
 use PhpOffice\PhpSpreadsheet\Cell\Hyperlink;
-use PhpOffice\PhpSpreadsheet\Document\Properties;
 use PhpOffice\PhpSpreadsheet\NamedRange;
 use PhpOffice\PhpSpreadsheet\NamedRange;
 use PhpOffice\PhpSpreadsheet\Reader\Security\XmlScanner;
 use PhpOffice\PhpSpreadsheet\Reader\Security\XmlScanner;
+use PhpOffice\PhpSpreadsheet\Reader\Xlsx\AutoFilter;
 use PhpOffice\PhpSpreadsheet\Reader\Xlsx\Chart;
 use PhpOffice\PhpSpreadsheet\Reader\Xlsx\Chart;
+use PhpOffice\PhpSpreadsheet\Reader\Xlsx\ColumnAndRowAttributes;
+use PhpOffice\PhpSpreadsheet\Reader\Xlsx\ConditionalStyles;
+use PhpOffice\PhpSpreadsheet\Reader\Xlsx\DataValidations;
+use PhpOffice\PhpSpreadsheet\Reader\Xlsx\Hyperlinks;
+use PhpOffice\PhpSpreadsheet\Reader\Xlsx\PageSetup;
+use PhpOffice\PhpSpreadsheet\Reader\Xlsx\Properties as PropertyReader;
+use PhpOffice\PhpSpreadsheet\Reader\Xlsx\SheetViewOptions;
+use PhpOffice\PhpSpreadsheet\Reader\Xlsx\SheetViews;
+use PhpOffice\PhpSpreadsheet\Reader\Xlsx\Styles;
 use PhpOffice\PhpSpreadsheet\ReferenceHelper;
 use PhpOffice\PhpSpreadsheet\ReferenceHelper;
 use PhpOffice\PhpSpreadsheet\RichText\RichText;
 use PhpOffice\PhpSpreadsheet\RichText\RichText;
 use PhpOffice\PhpSpreadsheet\Settings;
 use PhpOffice\PhpSpreadsheet\Settings;
@@ -20,11 +29,9 @@ use PhpOffice\PhpSpreadsheet\Spreadsheet;
 use PhpOffice\PhpSpreadsheet\Style\Border;
 use PhpOffice\PhpSpreadsheet\Style\Border;
 use PhpOffice\PhpSpreadsheet\Style\Borders;
 use PhpOffice\PhpSpreadsheet\Style\Borders;
 use PhpOffice\PhpSpreadsheet\Style\Color;
 use PhpOffice\PhpSpreadsheet\Style\Color;
-use PhpOffice\PhpSpreadsheet\Style\Conditional;
 use PhpOffice\PhpSpreadsheet\Style\NumberFormat;
 use PhpOffice\PhpSpreadsheet\Style\NumberFormat;
 use PhpOffice\PhpSpreadsheet\Style\Protection;
 use PhpOffice\PhpSpreadsheet\Style\Protection;
 use PhpOffice\PhpSpreadsheet\Style\Style;
 use PhpOffice\PhpSpreadsheet\Style\Style;
-use PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column;
 use PhpOffice\PhpSpreadsheet\Worksheet\HeaderFooterDrawing;
 use PhpOffice\PhpSpreadsheet\Worksheet\HeaderFooterDrawing;
 use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
 use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
 use SimpleXMLElement;
 use SimpleXMLElement;
@@ -52,7 +59,7 @@ class Xlsx extends BaseReader
      */
      */
     public function __construct()
     public function __construct()
     {
     {
-        $this->readFilter = new DefaultReadFilter();
+        parent::__construct();
         $this->referenceHelper = ReferenceHelper::getInstance();
         $this->referenceHelper = ReferenceHelper::getInstance();
         $this->securityScanner = XmlScanner::getInstance($this);
         $this->securityScanner = XmlScanner::getInstance($this);
     }
     }
@@ -323,60 +330,6 @@ class Xlsx extends BaseReader
         return $contents;
         return $contents;
     }
     }
 
 
-    /**
-     * Set Worksheet column attributes by attributes array passed.
-     *
-     * @param Worksheet $docSheet
-     * @param string $column A, B, ... DX, ...
-     * @param array $columnAttributes array of attributes (indexes are attribute name, values are value)
-     *                               'xfIndex', 'visible', 'collapsed', 'outlineLevel', 'width', ... ?
-     */
-    private function setColumnAttributes(Worksheet $docSheet, $column, array $columnAttributes)
-    {
-        if (isset($columnAttributes['xfIndex'])) {
-            $docSheet->getColumnDimension($column)->setXfIndex($columnAttributes['xfIndex']);
-        }
-        if (isset($columnAttributes['visible'])) {
-            $docSheet->getColumnDimension($column)->setVisible($columnAttributes['visible']);
-        }
-        if (isset($columnAttributes['collapsed'])) {
-            $docSheet->getColumnDimension($column)->setCollapsed($columnAttributes['collapsed']);
-        }
-        if (isset($columnAttributes['outlineLevel'])) {
-            $docSheet->getColumnDimension($column)->setOutlineLevel($columnAttributes['outlineLevel']);
-        }
-        if (isset($columnAttributes['width'])) {
-            $docSheet->getColumnDimension($column)->setWidth($columnAttributes['width']);
-        }
-    }
-
-    /**
-     * Set Worksheet row attributes by attributes array passed.
-     *
-     * @param Worksheet $docSheet
-     * @param int $row 1, 2, 3, ... 99, ...
-     * @param array $rowAttributes array of attributes (indexes are attribute name, values are value)
-     *                               'xfIndex', 'visible', 'collapsed', 'outlineLevel', 'rowHeight', ... ?
-     */
-    private function setRowAttributes(Worksheet $docSheet, $row, array $rowAttributes)
-    {
-        if (isset($rowAttributes['xfIndex'])) {
-            $docSheet->getRowDimension($row)->setXfIndex($rowAttributes['xfIndex']);
-        }
-        if (isset($rowAttributes['visible'])) {
-            $docSheet->getRowDimension($row)->setVisible($rowAttributes['visible']);
-        }
-        if (isset($rowAttributes['collapsed'])) {
-            $docSheet->getRowDimension($row)->setCollapsed($rowAttributes['collapsed']);
-        }
-        if (isset($rowAttributes['outlineLevel'])) {
-            $docSheet->getRowDimension($row)->setOutlineLevel($rowAttributes['outlineLevel']);
-        }
-        if (isset($rowAttributes['rowHeight'])) {
-            $docSheet->getRowDimension($row)->setRowHeight($rowAttributes['rowHeight']);
-        }
-    }
-
     /**
     /**
      * Loads Spreadsheet from file.
      * Loads Spreadsheet from file.
      *
      *
@@ -456,70 +409,20 @@ class Xlsx extends BaseReader
             'SimpleXMLElement',
             'SimpleXMLElement',
             Settings::getLibXmlLoaderOptions()
             Settings::getLibXmlLoaderOptions()
         );
         );
+
+        $propertyReader = new PropertyReader($this->securityScanner, $excel->getProperties());
         foreach ($rels->Relationship as $rel) {
         foreach ($rels->Relationship as $rel) {
             switch ($rel['Type']) {
             switch ($rel['Type']) {
                 case 'http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties':
                 case 'http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties':
-                    $xmlCore = simplexml_load_string(
-                        $this->securityScanner->scan($this->getFromZipArchive($zip, "{$rel['Target']}")),
-                        'SimpleXMLElement',
-                        Settings::getLibXmlLoaderOptions()
-                    );
-                    if (is_object($xmlCore)) {
-                        $xmlCore->registerXPathNamespace('dc', 'http://purl.org/dc/elements/1.1/');
-                        $xmlCore->registerXPathNamespace('dcterms', 'http://purl.org/dc/terms/');
-                        $xmlCore->registerXPathNamespace('cp', 'http://schemas.openxmlformats.org/package/2006/metadata/core-properties');
-                        $docProps = $excel->getProperties();
-                        $docProps->setCreator((string) self::getArrayItem($xmlCore->xpath('dc:creator')));
-                        $docProps->setLastModifiedBy((string) self::getArrayItem($xmlCore->xpath('cp:lastModifiedBy')));
-                        $docProps->setCreated(strtotime(self::getArrayItem($xmlCore->xpath('dcterms:created')))); //! respect xsi:type
-                        $docProps->setModified(strtotime(self::getArrayItem($xmlCore->xpath('dcterms:modified')))); //! respect xsi:type
-                        $docProps->setTitle((string) self::getArrayItem($xmlCore->xpath('dc:title')));
-                        $docProps->setDescription((string) self::getArrayItem($xmlCore->xpath('dc:description')));
-                        $docProps->setSubject((string) self::getArrayItem($xmlCore->xpath('dc:subject')));
-                        $docProps->setKeywords((string) self::getArrayItem($xmlCore->xpath('cp:keywords')));
-                        $docProps->setCategory((string) self::getArrayItem($xmlCore->xpath('cp:category')));
-                    }
+                    $propertyReader->readCoreProperties($this->getFromZipArchive($zip, "{$rel['Target']}"));
 
 
                     break;
                     break;
                 case 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties':
                 case 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties':
-                    $xmlCore = simplexml_load_string(
-                        $this->securityScanner->scan($this->getFromZipArchive($zip, "{$rel['Target']}")),
-                        'SimpleXMLElement',
-                        Settings::getLibXmlLoaderOptions()
-                    );
-                    if (is_object($xmlCore)) {
-                        $docProps = $excel->getProperties();
-                        if (isset($xmlCore->Company)) {
-                            $docProps->setCompany((string) $xmlCore->Company);
-                        }
-                        if (isset($xmlCore->Manager)) {
-                            $docProps->setManager((string) $xmlCore->Manager);
-                        }
-                    }
+                    $propertyReader->readExtendedProperties($this->getFromZipArchive($zip, "{$rel['Target']}"));
 
 
                     break;
                     break;
                 case 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/custom-properties':
                 case 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/custom-properties':
-                    $xmlCore = simplexml_load_string(
-                        $this->securityScanner->scan($this->getFromZipArchive($zip, "{$rel['Target']}")),
-                        'SimpleXMLElement',
-                        Settings::getLibXmlLoaderOptions()
-                    );
-                    if (is_object($xmlCore)) {
-                        $docProps = $excel->getProperties();
-                        /** @var SimpleXMLElement $xmlProperty */
-                        foreach ($xmlCore as $xmlProperty) {
-                            $cellDataOfficeAttributes = $xmlProperty->attributes();
-                            if (isset($cellDataOfficeAttributes['name'])) {
-                                $propertyName = (string) $cellDataOfficeAttributes['name'];
-                                $cellDataOfficeChildren = $xmlProperty->children('http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes');
-                                $attributeType = $cellDataOfficeChildren->getName();
-                                $attributeValue = (string) $cellDataOfficeChildren->{$attributeType};
-                                $attributeValue = Properties::convertProperty($attributeValue, $attributeType);
-                                $attributeType = Properties::convertPropertyType($attributeType);
-                                $docProps->setCustomProperty($propertyName, $attributeValue, $attributeType);
-                            }
-                        }
-                    }
+                    $propertyReader->readCustomProperties($this->getFromZipArchive($zip, "{$rel['Target']}"));
 
 
                     break;
                     break;
                 //Ribbon
                 //Ribbon
@@ -586,8 +489,7 @@ class Xlsx extends BaseReader
                             }
                             }
                         }
                         }
                     }
                     }
-                    $styles = [];
-                    $cellStyles = [];
+
                     $xpath = self::getArrayItem($relsWorkbook->xpath("rel:Relationship[@Type='http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles']"));
                     $xpath = self::getArrayItem($relsWorkbook->xpath("rel:Relationship[@Type='http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles']"));
                     //~ http://schemas.openxmlformats.org/spreadsheetml/2006/main"
                     //~ http://schemas.openxmlformats.org/spreadsheetml/2006/main"
                     $xmlStyles = simplexml_load_string(
                     $xmlStyles = simplexml_load_string(
@@ -595,6 +497,9 @@ class Xlsx extends BaseReader
                         'SimpleXMLElement',
                         'SimpleXMLElement',
                         Settings::getLibXmlLoaderOptions()
                         Settings::getLibXmlLoaderOptions()
                     );
                     );
+
+                    $styles = [];
+                    $cellStyles = [];
                     $numFmts = null;
                     $numFmts = null;
                     if ($xmlStyles && $xmlStyles->numFmts[0]) {
                     if ($xmlStyles && $xmlStyles->numFmts[0]) {
                         $numFmts = $xmlStyles->numFmts[0];
                         $numFmts = $xmlStyles->numFmts[0];
@@ -674,31 +579,10 @@ class Xlsx extends BaseReader
                         }
                         }
                     }
                     }
 
 
-                    $dxfs = [];
-                    if (!$this->readDataOnly && $xmlStyles) {
-                        //    Conditional Styles
-                        if ($xmlStyles->dxfs) {
-                            foreach ($xmlStyles->dxfs->dxf as $dxf) {
-                                $style = new Style(false, true);
-                                self::readStyle($style, $dxf);
-                                $dxfs[] = $style;
-                            }
-                        }
-                        //    Cell Styles
-                        if ($xmlStyles->cellStyles) {
-                            foreach ($xmlStyles->cellStyles->cellStyle as $cellStyle) {
-                                if ((int) ($cellStyle['builtinId']) == 0) {
-                                    if (isset($cellStyles[(int) ($cellStyle['xfId'])])) {
-                                        // Set default style
-                                        $style = new Style();
-                                        self::readStyle($style, $cellStyles[(int) ($cellStyle['xfId'])]);
-
-                                        // normal style, currently not using it for anything
-                                    }
-                                }
-                            }
-                        }
-                    }
+                    $styleReader = new Styles($xmlStyles);
+                    $styleReader->setStyleBaseData(self::$theme, $styles, $cellStyles);
+                    $dxfs = $styleReader->dxfs($this->readDataOnly);
+                    $styles = $styleReader->styles();
 
 
                     //~ http://schemas.openxmlformats.org/spreadsheetml/2006/main"
                     //~ http://schemas.openxmlformats.org/spreadsheetml/2006/main"
                     $xmlWorkbook = simplexml_load_string(
                     $xmlWorkbook = simplexml_load_string(
@@ -765,134 +649,19 @@ class Xlsx extends BaseReader
                                 $docSheet->setSheetState((string) $eleSheet['state']);
                                 $docSheet->setSheetState((string) $eleSheet['state']);
                             }
                             }
 
 
-                            if (isset($xmlSheet->sheetViews, $xmlSheet->sheetViews->sheetView)) {
-                                if (isset($xmlSheet->sheetViews->sheetView['zoomScale'])) {
-                                    $zoomScale = (int) ($xmlSheet->sheetViews->sheetView['zoomScale']);
-                                    if ($zoomScale <= 0) {
-                                        // setZoomScale will throw an Exception if the scale is less than or equals 0
-                                        // that is OK when manually creating documents, but we should be able to read all documents
-                                        $zoomScale = 100;
-                                    }
-
-                                    $docSheet->getSheetView()->setZoomScale($zoomScale);
-                                }
-                                if (isset($xmlSheet->sheetViews->sheetView['zoomScaleNormal'])) {
-                                    $zoomScaleNormal = (int) ($xmlSheet->sheetViews->sheetView['zoomScaleNormal']);
-                                    if ($zoomScaleNormal <= 0) {
-                                        // setZoomScaleNormal will throw an Exception if the scale is less than or equals 0
-                                        // that is OK when manually creating documents, but we should be able to read all documents
-                                        $zoomScaleNormal = 100;
-                                    }
-
-                                    $docSheet->getSheetView()->setZoomScaleNormal($zoomScaleNormal);
-                                }
-                                if (isset($xmlSheet->sheetViews->sheetView['view'])) {
-                                    $docSheet->getSheetView()->setView((string) $xmlSheet->sheetViews->sheetView['view']);
-                                }
-                                if (isset($xmlSheet->sheetViews->sheetView['showGridLines'])) {
-                                    $docSheet->setShowGridLines(self::boolean((string) $xmlSheet->sheetViews->sheetView['showGridLines']));
-                                }
-                                if (isset($xmlSheet->sheetViews->sheetView['showRowColHeaders'])) {
-                                    $docSheet->setShowRowColHeaders(self::boolean((string) $xmlSheet->sheetViews->sheetView['showRowColHeaders']));
-                                }
-                                if (isset($xmlSheet->sheetViews->sheetView['rightToLeft'])) {
-                                    $docSheet->setRightToLeft(self::boolean((string) $xmlSheet->sheetViews->sheetView['rightToLeft']));
-                                }
-                                if (isset($xmlSheet->sheetViews->sheetView->pane)) {
-                                    $xSplit = 0;
-                                    $ySplit = 0;
-                                    $topLeftCell = null;
-
-                                    if (isset($xmlSheet->sheetViews->sheetView->pane['xSplit'])) {
-                                        $xSplit = (int) ($xmlSheet->sheetViews->sheetView->pane['xSplit']);
-                                    }
-
-                                    if (isset($xmlSheet->sheetViews->sheetView->pane['ySplit'])) {
-                                        $ySplit = (int) ($xmlSheet->sheetViews->sheetView->pane['ySplit']);
-                                    }
-
-                                    if (isset($xmlSheet->sheetViews->sheetView->pane['topLeftCell'])) {
-                                        $topLeftCell = (string) $xmlSheet->sheetViews->sheetView->pane['topLeftCell'];
-                                    }
-
-                                    $docSheet->freezePane(Coordinate::stringFromColumnIndex($xSplit + 1) . ($ySplit + 1), $topLeftCell);
-                                }
-
-                                if (isset($xmlSheet->sheetViews->sheetView->selection)) {
-                                    if (isset($xmlSheet->sheetViews->sheetView->selection['sqref'])) {
-                                        $sqref = (string) $xmlSheet->sheetViews->sheetView->selection['sqref'];
-                                        $sqref = explode(' ', $sqref);
-                                        $sqref = $sqref[0];
-                                        $docSheet->setSelectedCells($sqref);
-                                    }
-                                }
-                            }
-
-                            if (isset($xmlSheet->sheetPr, $xmlSheet->sheetPr->tabColor)) {
-                                if (isset($xmlSheet->sheetPr->tabColor['rgb'])) {
-                                    $docSheet->getTabColor()->setARGB((string) $xmlSheet->sheetPr->tabColor['rgb']);
-                                }
-                            }
-                            if (isset($xmlSheet->sheetPr, $xmlSheet->sheetPr['codeName'])) {
-                                $docSheet->setCodeName((string) $xmlSheet->sheetPr['codeName'], false);
-                            }
-                            if (isset($xmlSheet->sheetPr, $xmlSheet->sheetPr->outlinePr)) {
-                                if (isset($xmlSheet->sheetPr->outlinePr['summaryRight']) &&
-                                    !self::boolean((string) $xmlSheet->sheetPr->outlinePr['summaryRight'])) {
-                                    $docSheet->setShowSummaryRight(false);
-                                } else {
-                                    $docSheet->setShowSummaryRight(true);
+                            if ($xmlSheet) {
+                                if (isset($xmlSheet->sheetViews, $xmlSheet->sheetViews->sheetView)) {
+                                    $sheetViews = new SheetViews($xmlSheet->sheetViews->sheetView, $docSheet);
+                                    $sheetViews->load();
                                 }
                                 }
 
 
-                                if (isset($xmlSheet->sheetPr->outlinePr['summaryBelow']) &&
-                                    !self::boolean((string) $xmlSheet->sheetPr->outlinePr['summaryBelow'])) {
-                                    $docSheet->setShowSummaryBelow(false);
-                                } else {
-                                    $docSheet->setShowSummaryBelow(true);
-                                }
-                            }
+                                $sheetViewOptions = new SheetViewOptions($docSheet, $xmlSheet);
+                                $sheetViewOptions->load($this->getReadDataOnly());
 
 
-                            if (isset($xmlSheet->sheetPr, $xmlSheet->sheetPr->pageSetUpPr)) {
-                                if (isset($xmlSheet->sheetPr->pageSetUpPr['fitToPage']) &&
-                                    !self::boolean((string) $xmlSheet->sheetPr->pageSetUpPr['fitToPage'])) {
-                                    $docSheet->getPageSetup()->setFitToPage(false);
-                                } else {
-                                    $docSheet->getPageSetup()->setFitToPage(true);
-                                }
+                                (new ColumnAndRowAttributes($docSheet, $xmlSheet))
+                                    ->load($this->getReadFilter(), $this->getReadDataOnly());
                             }
                             }
 
 
-                            if (isset($xmlSheet->sheetFormatPr)) {
-                                if (isset($xmlSheet->sheetFormatPr['customHeight']) &&
-                                    self::boolean((string) $xmlSheet->sheetFormatPr['customHeight']) &&
-                                    isset($xmlSheet->sheetFormatPr['defaultRowHeight'])) {
-                                    $docSheet->getDefaultRowDimension()->setRowHeight((float) $xmlSheet->sheetFormatPr['defaultRowHeight']);
-                                }
-                                if (isset($xmlSheet->sheetFormatPr['defaultColWidth'])) {
-                                    $docSheet->getDefaultColumnDimension()->setWidth((float) $xmlSheet->sheetFormatPr['defaultColWidth']);
-                                }
-                                if (isset($xmlSheet->sheetFormatPr['zeroHeight']) &&
-                                    ((string) $xmlSheet->sheetFormatPr['zeroHeight'] == '1')) {
-                                    $docSheet->getDefaultRowDimension()->setZeroHeight(true);
-                                }
-                            }
-
-                            if (isset($xmlSheet->printOptions) && !$this->readDataOnly) {
-                                if (self::boolean((string) $xmlSheet->printOptions['gridLinesSet'])) {
-                                    $docSheet->setShowGridlines(true);
-                                }
-                                if (self::boolean((string) $xmlSheet->printOptions['gridLines'])) {
-                                    $docSheet->setPrintGridlines(true);
-                                }
-                                if (self::boolean((string) $xmlSheet->printOptions['horizontalCentered'])) {
-                                    $docSheet->getPageSetup()->setHorizontalCentered(true);
-                                }
-                                if (self::boolean((string) $xmlSheet->printOptions['verticalCentered'])) {
-                                    $docSheet->getPageSetup()->setVerticalCentered(true);
-                                }
-                            }
-
-                            $this->readColumnsAndRowsAttributes($xmlSheet, $docSheet);
-
                             if ($xmlSheet && $xmlSheet->sheetData && $xmlSheet->sheetData->row) {
                             if ($xmlSheet && $xmlSheet->sheetData && $xmlSheet->sheetData->row) {
                                 $cIndex = 1; // Cell Start from 1
                                 $cIndex = 1; // Cell Start from 1
                                 foreach ($xmlSheet->sheetData->row as $row) {
                                 foreach ($xmlSheet->sheetData->row as $row) {
@@ -972,38 +741,39 @@ class Xlsx extends BaseReader
                                                 break;
                                                 break;
                                         }
                                         }
 
 
-                                        // Check for numeric values
-                                        if (is_numeric($value) && $cellDataType != 's') {
-                                            if ($value == (int) $value) {
-                                                $value = (int) $value;
-                                            } elseif ($value == (float) $value) {
-                                                $value = (float) $value;
-                                            } elseif ($value == (float) $value) {
-                                                $value = (float) $value;
+                                        // read empty cells or the cells are not empty
+                                        if ($this->readEmptyCells || ($value !== null && $value !== '')) {
+                                            // Check for numeric values
+                                            if (is_numeric($value) && $cellDataType != 's') {
+                                                if ($value == (int) $value) {
+                                                    $value = (int) $value;
+                                                } elseif ($value == (float) $value) {
+                                                    $value = (float) $value;
+                                                }
                                             }
                                             }
-                                        }
 
 
-                                        // Rich text?
-                                        if ($value instanceof RichText && $this->readDataOnly) {
-                                            $value = $value->getPlainText();
-                                        }
+                                            // Rich text?
+                                            if ($value instanceof RichText && $this->readDataOnly) {
+                                                $value = $value->getPlainText();
+                                            }
 
 
-                                        $cell = $docSheet->getCell($r);
-                                        // Assign value
-                                        if ($cellDataType != '') {
-                                            $cell->setValueExplicit($value, $cellDataType);
-                                        } else {
-                                            $cell->setValue($value);
-                                        }
-                                        if ($calculatedValue !== null) {
-                                            $cell->setCalculatedValue($calculatedValue);
-                                        }
+                                            $cell = $docSheet->getCell($r);
+                                            // Assign value
+                                            if ($cellDataType != '') {
+                                                $cell->setValueExplicit($value, $cellDataType);
+                                            } else {
+                                                $cell->setValue($value);
+                                            }
+                                            if ($calculatedValue !== null) {
+                                                $cell->setCalculatedValue($calculatedValue);
+                                            }
 
 
-                                        // Style information?
-                                        if ($c['s'] && !$this->readDataOnly) {
-                                            // no style index means 0, it seems
-                                            $cell->setXfIndex(isset($styles[(int) ($c['s'])]) ?
-                                                (int) ($c['s']) : 0);
+                                            // Style information?
+                                            if ($c['s'] && !$this->readDataOnly) {
+                                                // no style index means 0, it seems
+                                                $cell->setXfIndex(isset($styles[(int) ($c['s'])]) ?
+                                                    (int) ($c['s']) : 0);
+                                            }
                                         }
                                         }
                                         $rowIndex += 1;
                                         $rowIndex += 1;
                                     }
                                     }
@@ -1011,49 +781,8 @@ class Xlsx extends BaseReader
                                 }
                                 }
                             }
                             }
 
 
-                            $conditionals = [];
                             if (!$this->readDataOnly && $xmlSheet && $xmlSheet->conditionalFormatting) {
                             if (!$this->readDataOnly && $xmlSheet && $xmlSheet->conditionalFormatting) {
-                                foreach ($xmlSheet->conditionalFormatting as $conditional) {
-                                    foreach ($conditional->cfRule as $cfRule) {
-                                        if (((string) $cfRule['type'] == Conditional::CONDITION_NONE || (string) $cfRule['type'] == Conditional::CONDITION_CELLIS || (string) $cfRule['type'] == Conditional::CONDITION_CONTAINSTEXT || (string) $cfRule['type'] == Conditional::CONDITION_EXPRESSION) && isset($dxfs[(int) ($cfRule['dxfId'])])) {
-                                            $conditionals[(string) $conditional['sqref']][(int) ($cfRule['priority'])] = $cfRule;
-                                        }
-                                    }
-                                }
-
-                                foreach ($conditionals as $ref => $cfRules) {
-                                    ksort($cfRules);
-                                    $conditionalStyles = [];
-                                    foreach ($cfRules as $cfRule) {
-                                        $objConditional = new Conditional();
-                                        $objConditional->setConditionType((string) $cfRule['type']);
-                                        $objConditional->setOperatorType((string) $cfRule['operator']);
-
-                                        if ((string) $cfRule['text'] != '') {
-                                            $objConditional->setText((string) $cfRule['text']);
-                                        }
-
-                                        if (isset($cfRule['stopIfTrue']) && (int) $cfRule['stopIfTrue'] === 1) {
-                                            $objConditional->setStopIfTrue(true);
-                                        }
-
-                                        if (count($cfRule->formula) > 1) {
-                                            foreach ($cfRule->formula as $formula) {
-                                                $objConditional->addCondition((string) $formula);
-                                            }
-                                        } else {
-                                            $objConditional->addCondition((string) $cfRule->formula);
-                                        }
-                                        $objConditional->setStyle(clone $dxfs[(int) ($cfRule['dxfId'])]);
-                                        $conditionalStyles[] = $objConditional;
-                                    }
-
-                                    // Extract all cell references in $ref
-                                    $cellBlocks = explode(' ', str_replace('$', '', strtoupper($ref)));
-                                    foreach ($cellBlocks as $cellBlock) {
-                                        $docSheet->getStyle($cellBlock)->setConditionalStyles($conditionalStyles);
-                                    }
-                                }
+                                (new ConditionalStyles($docSheet, $xmlSheet, $dxfs))->load();
                             }
                             }
 
 
                             $aKeys = ['sheet', 'objects', 'scenarios', 'formatCells', 'formatColumns', 'formatRows', 'insertColumns', 'insertRows', 'insertHyperlinks', 'deleteColumns', 'deleteRows', 'selectLockedCells', 'sort', 'autoFilter', 'pivotTables', 'selectUnlockedCells'];
                             $aKeys = ['sheet', 'objects', 'scenarios', 'formatCells', 'formatColumns', 'formatRows', 'insertColumns', 'insertRows', 'insertHyperlinks', 'deleteColumns', 'deleteRows', 'selectLockedCells', 'sort', 'autoFilter', 'pivotTables', 'selectUnlockedCells'];
@@ -1074,103 +803,7 @@ class Xlsx extends BaseReader
                             }
                             }
 
 
                             if ($xmlSheet && $xmlSheet->autoFilter && !$this->readDataOnly) {
                             if ($xmlSheet && $xmlSheet->autoFilter && !$this->readDataOnly) {
-                                $autoFilterRange = (string) $xmlSheet->autoFilter['ref'];
-                                if (strpos($autoFilterRange, ':') !== false) {
-                                    $autoFilter = $docSheet->getAutoFilter();
-                                    $autoFilter->setRange($autoFilterRange);
-
-                                    foreach ($xmlSheet->autoFilter->filterColumn as $filterColumn) {
-                                        $column = $autoFilter->getColumnByOffset((int) $filterColumn['colId']);
-                                        //    Check for standard filters
-                                        if ($filterColumn->filters) {
-                                            $column->setFilterType(Column::AUTOFILTER_FILTERTYPE_FILTER);
-                                            $filters = $filterColumn->filters;
-                                            if ((isset($filters['blank'])) && ($filters['blank'] == 1)) {
-                                                //    Operator is undefined, but always treated as EQUAL
-                                                $column->createRule()->setRule(null, '')->setRuleType(Column\Rule::AUTOFILTER_RULETYPE_FILTER);
-                                            }
-                                            //    Standard filters are always an OR join, so no join rule needs to be set
-                                            //    Entries can be either filter elements
-                                            foreach ($filters->filter as $filterRule) {
-                                                //    Operator is undefined, but always treated as EQUAL
-                                                $column->createRule()->setRule(null, (string) $filterRule['val'])->setRuleType(Column\Rule::AUTOFILTER_RULETYPE_FILTER);
-                                            }
-                                            //    Or Date Group elements
-                                            foreach ($filters->dateGroupItem as $dateGroupItem) {
-                                                //    Operator is undefined, but always treated as EQUAL
-                                                $column->createRule()->setRule(
-                                                    null,
-                                                    [
-                                                        'year' => (string) $dateGroupItem['year'],
-                                                        'month' => (string) $dateGroupItem['month'],
-                                                        'day' => (string) $dateGroupItem['day'],
-                                                        'hour' => (string) $dateGroupItem['hour'],
-                                                        'minute' => (string) $dateGroupItem['minute'],
-                                                        'second' => (string) $dateGroupItem['second'],
-                                                    ],
-                                                    (string) $dateGroupItem['dateTimeGrouping']
-                                                )
-                                                    ->setRuleType(Column\Rule::AUTOFILTER_RULETYPE_DATEGROUP);
-                                            }
-                                        }
-                                        //    Check for custom filters
-                                        if ($filterColumn->customFilters) {
-                                            $column->setFilterType(Column::AUTOFILTER_FILTERTYPE_CUSTOMFILTER);
-                                            $customFilters = $filterColumn->customFilters;
-                                            //    Custom filters can an AND or an OR join;
-                                            //        and there should only ever be one or two entries
-                                            if ((isset($customFilters['and'])) && ($customFilters['and'] == 1)) {
-                                                $column->setJoin(Column::AUTOFILTER_COLUMN_JOIN_AND);
-                                            }
-                                            foreach ($customFilters->customFilter as $filterRule) {
-                                                $column->createRule()->setRule(
-                                                    (string) $filterRule['operator'],
-                                                    (string) $filterRule['val']
-                                                )
-                                                    ->setRuleType(Column\Rule::AUTOFILTER_RULETYPE_CUSTOMFILTER);
-                                            }
-                                        }
-                                        //    Check for dynamic filters
-                                        if ($filterColumn->dynamicFilter) {
-                                            $column->setFilterType(Column::AUTOFILTER_FILTERTYPE_DYNAMICFILTER);
-                                            //    We should only ever have one dynamic filter
-                                            foreach ($filterColumn->dynamicFilter as $filterRule) {
-                                                //    Operator is undefined, but always treated as EQUAL
-                                                $column->createRule()->setRule(
-                                                    null,
-                                                    (string) $filterRule['val'],
-                                                    (string) $filterRule['type']
-                                                )
-                                                    ->setRuleType(Column\Rule::AUTOFILTER_RULETYPE_DYNAMICFILTER);
-                                                if (isset($filterRule['val'])) {
-                                                    $column->setAttribute('val', (string) $filterRule['val']);
-                                                }
-                                                if (isset($filterRule['maxVal'])) {
-                                                    $column->setAttribute('maxVal', (string) $filterRule['maxVal']);
-                                                }
-                                            }
-                                        }
-                                        //    Check for dynamic filters
-                                        if ($filterColumn->top10) {
-                                            $column->setFilterType(Column::AUTOFILTER_FILTERTYPE_TOPTENFILTER);
-                                            //    We should only ever have one top10 filter
-                                            foreach ($filterColumn->top10 as $filterRule) {
-                                                $column->createRule()->setRule(
-                                                    (((isset($filterRule['percent'])) && ($filterRule['percent'] == 1))
-                                                        ? Column\Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_PERCENT
-                                                        : Column\Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_BY_VALUE
-                                                    ),
-                                                    (string) $filterRule['val'],
-                                                    (((isset($filterRule['top'])) && ($filterRule['top'] == 1))
-                                                        ? Column\Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_TOP
-                                                        : Column\Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_BOTTOM
-                                                    )
-                                                )
-                                                    ->setRuleType(Column\Rule::AUTOFILTER_RULETYPE_TOPTENFILTER);
-                                            }
-                                        }
-                                    }
-                                }
+                                (new AutoFilter($docSheet, $xmlSheet))->load();
                             }
                             }
 
 
                             if ($xmlSheet && $xmlSheet->mergeCells && $xmlSheet->mergeCells->mergeCell && !$this->readDataOnly) {
                             if ($xmlSheet && $xmlSheet->mergeCells && $xmlSheet->mergeCells->mergeCell && !$this->readDataOnly) {
@@ -1182,124 +815,12 @@ class Xlsx extends BaseReader
                                 }
                                 }
                             }
                             }
 
 
-                            if ($xmlSheet && $xmlSheet->pageMargins && !$this->readDataOnly) {
-                                $docPageMargins = $docSheet->getPageMargins();
-                                $docPageMargins->setLeft((float) ($xmlSheet->pageMargins['left']));
-                                $docPageMargins->setRight((float) ($xmlSheet->pageMargins['right']));
-                                $docPageMargins->setTop((float) ($xmlSheet->pageMargins['top']));
-                                $docPageMargins->setBottom((float) ($xmlSheet->pageMargins['bottom']));
-                                $docPageMargins->setHeader((float) ($xmlSheet->pageMargins['header']));
-                                $docPageMargins->setFooter((float) ($xmlSheet->pageMargins['footer']));
-                            }
-
-                            if ($xmlSheet && $xmlSheet->pageSetup && !$this->readDataOnly) {
-                                $docPageSetup = $docSheet->getPageSetup();
-
-                                if (isset($xmlSheet->pageSetup['orientation'])) {
-                                    $docPageSetup->setOrientation((string) $xmlSheet->pageSetup['orientation']);
-                                }
-                                if (isset($xmlSheet->pageSetup['paperSize'])) {
-                                    $docPageSetup->setPaperSize((int) ($xmlSheet->pageSetup['paperSize']));
-                                }
-                                if (isset($xmlSheet->pageSetup['scale'])) {
-                                    $docPageSetup->setScale((int) ($xmlSheet->pageSetup['scale']), false);
-                                }
-                                if (isset($xmlSheet->pageSetup['fitToHeight']) && (int) ($xmlSheet->pageSetup['fitToHeight']) >= 0) {
-                                    $docPageSetup->setFitToHeight((int) ($xmlSheet->pageSetup['fitToHeight']), false);
-                                }
-                                if (isset($xmlSheet->pageSetup['fitToWidth']) && (int) ($xmlSheet->pageSetup['fitToWidth']) >= 0) {
-                                    $docPageSetup->setFitToWidth((int) ($xmlSheet->pageSetup['fitToWidth']), false);
-                                }
-                                if (isset($xmlSheet->pageSetup['firstPageNumber'], $xmlSheet->pageSetup['useFirstPageNumber']) &&
-                                    self::boolean((string) $xmlSheet->pageSetup['useFirstPageNumber'])) {
-                                    $docPageSetup->setFirstPageNumber((int) ($xmlSheet->pageSetup['firstPageNumber']));
-                                }
-
-                                $relAttributes = $xmlSheet->pageSetup->attributes('http://schemas.openxmlformats.org/officeDocument/2006/relationships');
-                                if (isset($relAttributes['id'])) {
-                                    $unparsedLoadedData['sheets'][$docSheet->getCodeName()]['pageSetupRelId'] = (string) $relAttributes['id'];
-                                }
-                            }
-
-                            if ($xmlSheet && $xmlSheet->headerFooter && !$this->readDataOnly) {
-                                $docHeaderFooter = $docSheet->getHeaderFooter();
-
-                                if (isset($xmlSheet->headerFooter['differentOddEven']) &&
-                                    self::boolean((string) $xmlSheet->headerFooter['differentOddEven'])) {
-                                    $docHeaderFooter->setDifferentOddEven(true);
-                                } else {
-                                    $docHeaderFooter->setDifferentOddEven(false);
-                                }
-                                if (isset($xmlSheet->headerFooter['differentFirst']) &&
-                                    self::boolean((string) $xmlSheet->headerFooter['differentFirst'])) {
-                                    $docHeaderFooter->setDifferentFirst(true);
-                                } else {
-                                    $docHeaderFooter->setDifferentFirst(false);
-                                }
-                                if (isset($xmlSheet->headerFooter['scaleWithDoc']) &&
-                                    !self::boolean((string) $xmlSheet->headerFooter['scaleWithDoc'])) {
-                                    $docHeaderFooter->setScaleWithDocument(false);
-                                } else {
-                                    $docHeaderFooter->setScaleWithDocument(true);
-                                }
-                                if (isset($xmlSheet->headerFooter['alignWithMargins']) &&
-                                    !self::boolean((string) $xmlSheet->headerFooter['alignWithMargins'])) {
-                                    $docHeaderFooter->setAlignWithMargins(false);
-                                } else {
-                                    $docHeaderFooter->setAlignWithMargins(true);
-                                }
-
-                                $docHeaderFooter->setOddHeader((string) $xmlSheet->headerFooter->oddHeader);
-                                $docHeaderFooter->setOddFooter((string) $xmlSheet->headerFooter->oddFooter);
-                                $docHeaderFooter->setEvenHeader((string) $xmlSheet->headerFooter->evenHeader);
-                                $docHeaderFooter->setEvenFooter((string) $xmlSheet->headerFooter->evenFooter);
-                                $docHeaderFooter->setFirstHeader((string) $xmlSheet->headerFooter->firstHeader);
-                                $docHeaderFooter->setFirstFooter((string) $xmlSheet->headerFooter->firstFooter);
-                            }
-
-                            if ($xmlSheet && $xmlSheet->rowBreaks && $xmlSheet->rowBreaks->brk && !$this->readDataOnly) {
-                                foreach ($xmlSheet->rowBreaks->brk as $brk) {
-                                    if ($brk['man']) {
-                                        $docSheet->setBreak("A$brk[id]", Worksheet::BREAK_ROW);
-                                    }
-                                }
-                            }
-                            if ($xmlSheet && $xmlSheet->colBreaks && $xmlSheet->colBreaks->brk && !$this->readDataOnly) {
-                                foreach ($xmlSheet->colBreaks->brk as $brk) {
-                                    if ($brk['man']) {
-                                        $docSheet->setBreak(Coordinate::stringFromColumnIndex((string) $brk['id'] + 1) . '1', Worksheet::BREAK_COLUMN);
-                                    }
-                                }
+                            if ($xmlSheet && !$this->readDataOnly) {
+                                $unparsedLoadedData = (new PageSetup($docSheet, $xmlSheet))->load($unparsedLoadedData);
                             }
                             }
 
 
                             if ($xmlSheet && $xmlSheet->dataValidations && !$this->readDataOnly) {
                             if ($xmlSheet && $xmlSheet->dataValidations && !$this->readDataOnly) {
-                                foreach ($xmlSheet->dataValidations->dataValidation as $dataValidation) {
-                                    // Uppercase coordinate
-                                    $range = strtoupper($dataValidation['sqref']);
-                                    $rangeSet = explode(' ', $range);
-                                    foreach ($rangeSet as $range) {
-                                        $stRange = $docSheet->shrinkRangeToFit($range);
-
-                                        // Extract all cell references in $range
-                                        foreach (Coordinate::extractAllCellReferencesInRange($stRange) as $reference) {
-                                            // Create validation
-                                            $docValidation = $docSheet->getCell($reference)->getDataValidation();
-                                            $docValidation->setType((string) $dataValidation['type']);
-                                            $docValidation->setErrorStyle((string) $dataValidation['errorStyle']);
-                                            $docValidation->setOperator((string) $dataValidation['operator']);
-                                            $docValidation->setAllowBlank($dataValidation['allowBlank'] != 0);
-                                            $docValidation->setShowDropDown($dataValidation['showDropDown'] == 0);
-                                            $docValidation->setShowInputMessage($dataValidation['showInputMessage'] != 0);
-                                            $docValidation->setShowErrorMessage($dataValidation['showErrorMessage'] != 0);
-                                            $docValidation->setErrorTitle((string) $dataValidation['errorTitle']);
-                                            $docValidation->setError((string) $dataValidation['error']);
-                                            $docValidation->setPromptTitle((string) $dataValidation['promptTitle']);
-                                            $docValidation->setPrompt((string) $dataValidation['prompt']);
-                                            $docValidation->setFormula1((string) $dataValidation->formula1);
-                                            $docValidation->setFormula2((string) $dataValidation->formula2);
-                                        }
-                                    }
-                                }
+                                (new DataValidations($docSheet, $xmlSheet))->load();
                             }
                             }
 
 
                             // unparsed sheet AlternateContent
                             // unparsed sheet AlternateContent
@@ -1313,50 +834,25 @@ class Xlsx extends BaseReader
                             }
                             }
 
 
                             // Add hyperlinks
                             // Add hyperlinks
-                            $hyperlinks = [];
                             if (!$this->readDataOnly) {
                             if (!$this->readDataOnly) {
+                                $hyperlinkReader = new Hyperlinks($docSheet);
                                 // Locate hyperlink relations
                                 // Locate hyperlink relations
-                                if ($zip->locateName(dirname("$dir/$fileWorksheet") . '/_rels/' . basename($fileWorksheet) . '.rels')) {
+                                $relationsFileName = dirname("$dir/$fileWorksheet") . '/_rels/' . basename($fileWorksheet) . '.rels';
+                                if ($zip->locateName($relationsFileName)) {
                                     //~ http://schemas.openxmlformats.org/package/2006/relationships"
                                     //~ http://schemas.openxmlformats.org/package/2006/relationships"
                                     $relsWorksheet = simplexml_load_string(
                                     $relsWorksheet = simplexml_load_string(
                                         $this->securityScanner->scan(
                                         $this->securityScanner->scan(
-                                            $this->getFromZipArchive($zip, dirname("$dir/$fileWorksheet") . '/_rels/' . basename($fileWorksheet) . '.rels')
+                                            $this->getFromZipArchive($zip, $relationsFileName)
                                         ),
                                         ),
                                         'SimpleXMLElement',
                                         'SimpleXMLElement',
                                         Settings::getLibXmlLoaderOptions()
                                         Settings::getLibXmlLoaderOptions()
                                     );
                                     );
-                                    foreach ($relsWorksheet->Relationship as $ele) {
-                                        if ($ele['Type'] == 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink') {
-                                            $hyperlinks[(string) $ele['Id']] = (string) $ele['Target'];
-                                        }
-                                    }
+                                    $hyperlinkReader->readHyperlinks($relsWorksheet);
                                 }
                                 }
 
 
                                 // Loop through hyperlinks
                                 // Loop through hyperlinks
                                 if ($xmlSheet && $xmlSheet->hyperlinks) {
                                 if ($xmlSheet && $xmlSheet->hyperlinks) {
-                                    /** @var SimpleXMLElement $hyperlink */
-                                    foreach ($xmlSheet->hyperlinks->hyperlink as $hyperlink) {
-                                        // Link url
-                                        $linkRel = $hyperlink->attributes('http://schemas.openxmlformats.org/officeDocument/2006/relationships');
-
-                                        foreach (Coordinate::extractAllCellReferencesInRange($hyperlink['ref']) as $cellReference) {
-                                            $cell = $docSheet->getCell($cellReference);
-                                            if (isset($linkRel['id'])) {
-                                                $hyperlinkUrl = $hyperlinks[(string) $linkRel['id']];
-                                                if (isset($hyperlink['location'])) {
-                                                    $hyperlinkUrl .= '#' . (string) $hyperlink['location'];
-                                                }
-                                                $cell->getHyperlink()->setUrl($hyperlinkUrl);
-                                            } elseif (isset($hyperlink['location'])) {
-                                                $cell->getHyperlink()->setUrl('sheet://' . (string) $hyperlink['location']);
-                                            }
-
-                                            // Tooltip
-                                            if (isset($hyperlink['tooltip'])) {
-                                                $cell->getHyperlink()->setTooltip((string) $hyperlink['tooltip']);
-                                            }
-                                        }
-                                    }
+                                    $hyperlinkReader->setHyperlinks($xmlSheet->hyperlinks);
                                 }
                                 }
                             }
                             }
 
 
@@ -1418,12 +914,18 @@ class Xlsx extends BaseReader
                                 foreach ($vmlComments as $relName => $relPath) {
                                 foreach ($vmlComments as $relName => $relPath) {
                                     // Load VML comments file
                                     // Load VML comments file
                                     $relPath = File::realpath(dirname("$dir/$fileWorksheet") . '/' . $relPath);
                                     $relPath = File::realpath(dirname("$dir/$fileWorksheet") . '/' . $relPath);
-                                    $vmlCommentsFile = simplexml_load_string(
-                                        $this->securityScanner->scan($this->getFromZipArchive($zip, $relPath)),
-                                        'SimpleXMLElement',
-                                        Settings::getLibXmlLoaderOptions()
-                                    );
-                                    $vmlCommentsFile->registerXPathNamespace('v', 'urn:schemas-microsoft-com:vml');
+
+                                    try {
+                                        $vmlCommentsFile = simplexml_load_string(
+                                            $this->securityScanner->scan($this->getFromZipArchive($zip, $relPath)),
+                                            'SimpleXMLElement',
+                                            Settings::getLibXmlLoaderOptions()
+                                        );
+                                        $vmlCommentsFile->registerXPathNamespace('v', 'urn:schemas-microsoft-com:vml');
+                                    } catch (\Throwable $ex) {
+                                        //Ignore unparsable vmlDrawings. Later they will be moved from $unparsedVmlDrawings to $unparsedLoadedData
+                                        continue;
+                                    }
 
 
                                     $shapes = $vmlCommentsFile->xpath('//v:shape');
                                     $shapes = $vmlCommentsFile->xpath('//v:shape');
                                     foreach ($shapes as $shape) {
                                     foreach ($shapes as $shape) {
@@ -1597,8 +1099,10 @@ class Xlsx extends BaseReader
                                     }
                                     }
                                 }
                                 }
                                 if ($xmlSheet->drawing && !$this->readDataOnly) {
                                 if ($xmlSheet->drawing && !$this->readDataOnly) {
+                                    $unparsedDrawings = [];
                                     foreach ($xmlSheet->drawing as $drawing) {
                                     foreach ($xmlSheet->drawing as $drawing) {
-                                        $fileDrawing = $drawings[(string) self::getArrayItem($drawing->attributes('http://schemas.openxmlformats.org/officeDocument/2006/relationships'), 'id')];
+                                        $drawingRelId = (string) self::getArrayItem($drawing->attributes('http://schemas.openxmlformats.org/officeDocument/2006/relationships'), 'id');
+                                        $fileDrawing = $drawings[$drawingRelId];
                                         //~ http://schemas.openxmlformats.org/package/2006/relationships"
                                         //~ http://schemas.openxmlformats.org/package/2006/relationships"
                                         $relsDrawing = simplexml_load_string(
                                         $relsDrawing = simplexml_load_string(
                                             $this->securityScanner->scan(
                                             $this->securityScanner->scan(
@@ -1630,10 +1134,11 @@ class Xlsx extends BaseReader
                                             $this->securityScanner->scan($this->getFromZipArchive($zip, $fileDrawing)),
                                             $this->securityScanner->scan($this->getFromZipArchive($zip, $fileDrawing)),
                                             'SimpleXMLElement',
                                             'SimpleXMLElement',
                                             Settings::getLibXmlLoaderOptions()
                                             Settings::getLibXmlLoaderOptions()
-                                        )->children('http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing');
+                                        );
+                                        $xmlDrawingChildren = $xmlDrawing->children('http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing');
 
 
-                                        if ($xmlDrawing->oneCellAnchor) {
-                                            foreach ($xmlDrawing->oneCellAnchor as $oneCellAnchor) {
+                                        if ($xmlDrawingChildren->oneCellAnchor) {
+                                            foreach ($xmlDrawingChildren->oneCellAnchor as $oneCellAnchor) {
                                                 if ($oneCellAnchor->pic->blipFill) {
                                                 if ($oneCellAnchor->pic->blipFill) {
                                                     /** @var SimpleXMLElement $blip */
                                                     /** @var SimpleXMLElement $blip */
                                                     $blip = $oneCellAnchor->pic->blipFill->children('http://schemas.openxmlformats.org/drawingml/2006/main')->blip;
                                                     $blip = $oneCellAnchor->pic->blipFill->children('http://schemas.openxmlformats.org/drawingml/2006/main')->blip;
@@ -1667,12 +1172,13 @@ class Xlsx extends BaseReader
                                                     if ($outerShdw) {
                                                     if ($outerShdw) {
                                                         $shadow = $objDrawing->getShadow();
                                                         $shadow = $objDrawing->getShadow();
                                                         $shadow->setVisible(true);
                                                         $shadow->setVisible(true);
-                                                        $shadow->setBlurRadius(Drawing::EMUTopixels(self::getArrayItem($outerShdw->attributes(), 'blurRad')));
-                                                        $shadow->setDistance(Drawing::EMUTopixels(self::getArrayItem($outerShdw->attributes(), 'dist')));
+                                                        $shadow->setBlurRadius(Drawing::EMUToPixels(self::getArrayItem($outerShdw->attributes(), 'blurRad')));
+                                                        $shadow->setDistance(Drawing::EMUToPixels(self::getArrayItem($outerShdw->attributes(), 'dist')));
                                                         $shadow->setDirection(Drawing::angleToDegrees(self::getArrayItem($outerShdw->attributes(), 'dir')));
                                                         $shadow->setDirection(Drawing::angleToDegrees(self::getArrayItem($outerShdw->attributes(), 'dir')));
                                                         $shadow->setAlignment((string) self::getArrayItem($outerShdw->attributes(), 'algn'));
                                                         $shadow->setAlignment((string) self::getArrayItem($outerShdw->attributes(), 'algn'));
-                                                        $shadow->getColor()->setRGB(self::getArrayItem($outerShdw->srgbClr->attributes(), 'val'));
-                                                        $shadow->setAlpha(self::getArrayItem($outerShdw->srgbClr->alpha->attributes(), 'val') / 1000);
+                                                        $clr = isset($outerShdw->srgbClr) ? $outerShdw->srgbClr : $outerShdw->prstClr;
+                                                        $shadow->getColor()->setRGB(self::getArrayItem($clr->attributes(), 'val'));
+                                                        $shadow->setAlpha(self::getArrayItem($clr->alpha->attributes(), 'val') / 1000);
                                                     }
                                                     }
 
 
                                                     $this->readHyperLinkDrawing($objDrawing, $oneCellAnchor, $hyperlinks);
                                                     $this->readHyperLinkDrawing($objDrawing, $oneCellAnchor, $hyperlinks);
@@ -1688,8 +1194,8 @@ class Xlsx extends BaseReader
                                                 }
                                                 }
                                             }
                                             }
                                         }
                                         }
-                                        if ($xmlDrawing->twoCellAnchor) {
-                                            foreach ($xmlDrawing->twoCellAnchor as $twoCellAnchor) {
+                                        if ($xmlDrawingChildren->twoCellAnchor) {
+                                            foreach ($xmlDrawingChildren->twoCellAnchor as $twoCellAnchor) {
                                                 if ($twoCellAnchor->pic->blipFill) {
                                                 if ($twoCellAnchor->pic->blipFill) {
                                                     $blip = $twoCellAnchor->pic->blipFill->children('http://schemas.openxmlformats.org/drawingml/2006/main')->blip;
                                                     $blip = $twoCellAnchor->pic->blipFill->children('http://schemas.openxmlformats.org/drawingml/2006/main')->blip;
                                                     $xfrm = $twoCellAnchor->pic->spPr->children('http://schemas.openxmlformats.org/drawingml/2006/main')->xfrm;
                                                     $xfrm = $twoCellAnchor->pic->spPr->children('http://schemas.openxmlformats.org/drawingml/2006/main')->xfrm;
@@ -1719,12 +1225,13 @@ class Xlsx extends BaseReader
                                                     if ($outerShdw) {
                                                     if ($outerShdw) {
                                                         $shadow = $objDrawing->getShadow();
                                                         $shadow = $objDrawing->getShadow();
                                                         $shadow->setVisible(true);
                                                         $shadow->setVisible(true);
-                                                        $shadow->setBlurRadius(Drawing::EMUTopixels(self::getArrayItem($outerShdw->attributes(), 'blurRad')));
-                                                        $shadow->setDistance(Drawing::EMUTopixels(self::getArrayItem($outerShdw->attributes(), 'dist')));
+                                                        $shadow->setBlurRadius(Drawing::EMUToPixels(self::getArrayItem($outerShdw->attributes(), 'blurRad')));
+                                                        $shadow->setDistance(Drawing::EMUToPixels(self::getArrayItem($outerShdw->attributes(), 'dist')));
                                                         $shadow->setDirection(Drawing::angleToDegrees(self::getArrayItem($outerShdw->attributes(), 'dir')));
                                                         $shadow->setDirection(Drawing::angleToDegrees(self::getArrayItem($outerShdw->attributes(), 'dir')));
                                                         $shadow->setAlignment((string) self::getArrayItem($outerShdw->attributes(), 'algn'));
                                                         $shadow->setAlignment((string) self::getArrayItem($outerShdw->attributes(), 'algn'));
-                                                        $shadow->getColor()->setRGB(self::getArrayItem($outerShdw->srgbClr->attributes(), 'val'));
-                                                        $shadow->setAlpha(self::getArrayItem($outerShdw->srgbClr->alpha->attributes(), 'val') / 1000);
+                                                        $clr = isset($outerShdw->srgbClr) ? $outerShdw->srgbClr : $outerShdw->prstClr;
+                                                        $shadow->getColor()->setRGB(self::getArrayItem($clr->attributes(), 'val'));
+                                                        $shadow->setAlpha(self::getArrayItem($clr->alpha->attributes(), 'val') / 1000);
                                                     }
                                                     }
 
 
                                                     $this->readHyperLinkDrawing($objDrawing, $twoCellAnchor, $hyperlinks);
                                                     $this->readHyperLinkDrawing($objDrawing, $twoCellAnchor, $hyperlinks);
@@ -1754,13 +1261,21 @@ class Xlsx extends BaseReader
                                                 }
                                                 }
                                             }
                                             }
                                         }
                                         }
+                                        if ($relsDrawing === false && $xmlDrawing->count() == 0) {
+                                            // Save Drawing without rels and children as unparsed
+                                            $unparsedDrawings[$drawingRelId] = $xmlDrawing->asXML();
+                                        }
                                     }
                                     }
 
 
                                     // store original rId of drawing files
                                     // store original rId of drawing files
                                     $unparsedLoadedData['sheets'][$docSheet->getCodeName()]['drawingOriginalIds'] = [];
                                     $unparsedLoadedData['sheets'][$docSheet->getCodeName()]['drawingOriginalIds'] = [];
                                     foreach ($relsWorksheet->Relationship as $ele) {
                                     foreach ($relsWorksheet->Relationship as $ele) {
                                         if ($ele['Type'] == 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing') {
                                         if ($ele['Type'] == 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing') {
-                                            $unparsedLoadedData['sheets'][$docSheet->getCodeName()]['drawingOriginalIds'][(string) $ele['Target']] = (string) $ele['Id'];
+                                            $drawingRelId = (string) $ele['Id'];
+                                            $unparsedLoadedData['sheets'][$docSheet->getCodeName()]['drawingOriginalIds'][(string) $ele['Target']] = $drawingRelId;
+                                            if (isset($unparsedDrawings[$drawingRelId])) {
+                                                $unparsedLoadedData['sheets'][$docSheet->getCodeName()]['Drawings'][$drawingRelId] = $unparsedDrawings[$drawingRelId];
+                                            }
                                         }
                                         }
                                     }
                                     }
 
 
@@ -1905,7 +1420,7 @@ class Xlsx extends BaseReader
                                     if (strpos((string) $definedName, '!') !== false) {
                                     if (strpos((string) $definedName, '!') !== false) {
                                         // Extract sheet name
                                         // Extract sheet name
                                         $extractedSheetName = Worksheet::extractSheetTitle((string) $definedName, true);
                                         $extractedSheetName = Worksheet::extractSheetTitle((string) $definedName, true);
-                                        $extractedSheetName = $extractedSheetName[0];
+                                        $extractedSheetName = trim($extractedSheetName[0], "'");
 
 
                                         // Locate sheet
                                         // Locate sheet
                                         $locatedSheet = $excel->getSheetByName($extractedSheetName);
                                         $locatedSheet = $excel->getSheetByName($extractedSheetName);
@@ -2511,94 +2026,4 @@ class Xlsx extends BaseReader
 
 
         return (bool) $xsdBoolean;
         return (bool) $xsdBoolean;
     }
     }
-
-    /**
-     * Read columns and rows attributes from XML and set them on the worksheet.
-     *
-     * @param SimpleXMLElement $xmlSheet
-     * @param Worksheet $docSheet
-     */
-    private function readColumnsAndRowsAttributes(SimpleXMLElement $xmlSheet, Worksheet $docSheet)
-    {
-        $columnsAttributes = [];
-        $rowsAttributes = [];
-        if (isset($xmlSheet->cols) && !$this->readDataOnly) {
-            foreach ($xmlSheet->cols->col as $col) {
-                for ($i = (int) ($col['min']); $i <= (int) ($col['max']); ++$i) {
-                    if ($col['style'] && !$this->readDataOnly) {
-                        $columnsAttributes[Coordinate::stringFromColumnIndex($i)]['xfIndex'] = (int) $col['style'];
-                    }
-                    if (self::boolean($col['hidden'])) {
-                        $columnsAttributes[Coordinate::stringFromColumnIndex($i)]['visible'] = false;
-                    }
-                    if (self::boolean($col['collapsed'])) {
-                        $columnsAttributes[Coordinate::stringFromColumnIndex($i)]['collapsed'] = true;
-                    }
-                    if ($col['outlineLevel'] > 0) {
-                        $columnsAttributes[Coordinate::stringFromColumnIndex($i)]['outlineLevel'] = (int) $col['outlineLevel'];
-                    }
-                    $columnsAttributes[Coordinate::stringFromColumnIndex($i)]['width'] = (float) $col['width'];
-
-                    if ((int) ($col['max']) == 16384) {
-                        break;
-                    }
-                }
-            }
-        }
-
-        if ($xmlSheet && $xmlSheet->sheetData && $xmlSheet->sheetData->row) {
-            foreach ($xmlSheet->sheetData->row as $row) {
-                if ($row['ht'] && !$this->readDataOnly) {
-                    $rowsAttributes[(int) $row['r']]['rowHeight'] = (float) $row['ht'];
-                }
-                if (self::boolean($row['hidden']) && !$this->readDataOnly) {
-                    $rowsAttributes[(int) $row['r']]['visible'] = false;
-                }
-                if (self::boolean($row['collapsed'])) {
-                    $rowsAttributes[(int) $row['r']]['collapsed'] = true;
-                }
-                if ($row['outlineLevel'] > 0) {
-                    $rowsAttributes[(int) $row['r']]['outlineLevel'] = (int) $row['outlineLevel'];
-                }
-                if ($row['s'] && !$this->readDataOnly) {
-                    $rowsAttributes[(int) $row['r']]['xfIndex'] = (int) $row['s'];
-                }
-            }
-        }
-
-        $readFilter = (\get_class($this->getReadFilter()) !== DefaultReadFilter::class ? $this->getReadFilter() : null);
-
-        // set columns/rows attributes
-        $columnsAttributesSet = [];
-        $rowsAttributesSet = [];
-        foreach ($columnsAttributes as $coordColumn => $columnAttributes) {
-            if ($readFilter !== null) {
-                foreach ($rowsAttributes as $coordRow => $rowAttributes) {
-                    if (!$readFilter->readCell($coordColumn, $coordRow, $docSheet->getTitle())) {
-                        continue 2;
-                    }
-                }
-            }
-
-            if (!isset($columnsAttributesSet[$coordColumn])) {
-                $this->setColumnAttributes($docSheet, $coordColumn, $columnAttributes);
-                $columnsAttributesSet[$coordColumn] = true;
-            }
-        }
-
-        foreach ($rowsAttributes as $coordRow => $rowAttributes) {
-            if ($readFilter !== null) {
-                foreach ($columnsAttributes as $coordColumn => $columnAttributes) {
-                    if (!$readFilter->readCell($coordColumn, $coordRow, $docSheet->getTitle())) {
-                        continue 2;
-                    }
-                }
-            }
-
-            if (!isset($rowsAttributesSet[$coordRow])) {
-                $this->setRowAttributes($docSheet, $coordRow, $rowAttributes);
-                $rowsAttributesSet[$coordRow] = true;
-            }
-        }
-    }
 }
 }

+ 144 - 0
htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xlsx/AutoFilter.php

@@ -0,0 +1,144 @@
+<?php
+
+namespace PhpOffice\PhpSpreadsheet\Reader\Xlsx;
+
+use PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column;
+use PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column\Rule;
+use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
+
+class AutoFilter
+{
+    private $worksheet;
+
+    private $worksheetXml;
+
+    public function __construct(Worksheet $workSheet, \SimpleXMLElement $worksheetXml)
+    {
+        $this->worksheet = $workSheet;
+        $this->worksheetXml = $worksheetXml;
+    }
+
+    public function load()
+    {
+        $autoFilterRange = (string) $this->worksheetXml->autoFilter['ref'];
+        if (strpos($autoFilterRange, ':') !== false) {
+            $this->readAutoFilter($autoFilterRange, $this->worksheetXml);
+        }
+    }
+
+    private function readAutoFilter($autoFilterRange, $xmlSheet)
+    {
+        $autoFilter = $this->worksheet->getAutoFilter();
+        $autoFilter->setRange($autoFilterRange);
+
+        foreach ($xmlSheet->autoFilter->filterColumn as $filterColumn) {
+            $column = $autoFilter->getColumnByOffset((int) $filterColumn['colId']);
+            //    Check for standard filters
+            if ($filterColumn->filters) {
+                $column->setFilterType(Column::AUTOFILTER_FILTERTYPE_FILTER);
+                $filters = $filterColumn->filters;
+                if ((isset($filters['blank'])) && ($filters['blank'] == 1)) {
+                    //    Operator is undefined, but always treated as EQUAL
+                    $column->createRule()->setRule(null, '')->setRuleType(Rule::AUTOFILTER_RULETYPE_FILTER);
+                }
+                //    Standard filters are always an OR join, so no join rule needs to be set
+                //    Entries can be either filter elements
+                foreach ($filters->filter as $filterRule) {
+                    //    Operator is undefined, but always treated as EQUAL
+                    $column->createRule()->setRule(null, (string) $filterRule['val'])->setRuleType(Rule::AUTOFILTER_RULETYPE_FILTER);
+                }
+
+                //    Or Date Group elements
+                $this->readDateRangeAutoFilter($filters, $column);
+            }
+
+            //    Check for custom filters
+            $this->readCustomAutoFilter($filterColumn, $column);
+            //    Check for dynamic filters
+            $this->readDynamicAutoFilter($filterColumn, $column);
+            //    Check for dynamic filters
+            $this->readTopTenAutoFilter($filterColumn, $column);
+        }
+    }
+
+    private function readDateRangeAutoFilter(\SimpleXMLElement $filters, Column $column)
+    {
+        foreach ($filters->dateGroupItem as $dateGroupItem) {
+            //    Operator is undefined, but always treated as EQUAL
+            $column->createRule()->setRule(
+                null,
+                [
+                    'year' => (string) $dateGroupItem['year'],
+                    'month' => (string) $dateGroupItem['month'],
+                    'day' => (string) $dateGroupItem['day'],
+                    'hour' => (string) $dateGroupItem['hour'],
+                    'minute' => (string) $dateGroupItem['minute'],
+                    'second' => (string) $dateGroupItem['second'],
+                ],
+                (string) $dateGroupItem['dateTimeGrouping']
+            )->setRuleType(Rule::AUTOFILTER_RULETYPE_DATEGROUP);
+        }
+    }
+
+    private function readCustomAutoFilter(\SimpleXMLElement $filterColumn, Column $column)
+    {
+        if ($filterColumn->customFilters) {
+            $column->setFilterType(Column::AUTOFILTER_FILTERTYPE_CUSTOMFILTER);
+            $customFilters = $filterColumn->customFilters;
+            //    Custom filters can an AND or an OR join;
+            //        and there should only ever be one or two entries
+            if ((isset($customFilters['and'])) && ($customFilters['and'] == 1)) {
+                $column->setJoin(Column::AUTOFILTER_COLUMN_JOIN_AND);
+            }
+            foreach ($customFilters->customFilter as $filterRule) {
+                $column->createRule()->setRule(
+                    (string) $filterRule['operator'],
+                    (string) $filterRule['val']
+                )->setRuleType(Rule::AUTOFILTER_RULETYPE_CUSTOMFILTER);
+            }
+        }
+    }
+
+    private function readDynamicAutoFilter(\SimpleXMLElement $filterColumn, Column $column)
+    {
+        if ($filterColumn->dynamicFilter) {
+            $column->setFilterType(Column::AUTOFILTER_FILTERTYPE_DYNAMICFILTER);
+            //    We should only ever have one dynamic filter
+            foreach ($filterColumn->dynamicFilter as $filterRule) {
+                //    Operator is undefined, but always treated as EQUAL
+                $column->createRule()->setRule(
+                    null,
+                    (string) $filterRule['val'],
+                    (string) $filterRule['type']
+                )->setRuleType(Rule::AUTOFILTER_RULETYPE_DYNAMICFILTER);
+                if (isset($filterRule['val'])) {
+                    $column->setAttribute('val', (string) $filterRule['val']);
+                }
+                if (isset($filterRule['maxVal'])) {
+                    $column->setAttribute('maxVal', (string) $filterRule['maxVal']);
+                }
+            }
+        }
+    }
+
+    private function readTopTenAutoFilter(\SimpleXMLElement $filterColumn, Column $column)
+    {
+        if ($filterColumn->top10) {
+            $column->setFilterType(Column::AUTOFILTER_FILTERTYPE_TOPTENFILTER);
+            //    We should only ever have one top10 filter
+            foreach ($filterColumn->top10 as $filterRule) {
+                $column->createRule()->setRule(
+                    (((isset($filterRule['percent'])) && ($filterRule['percent'] == 1))
+                        ? Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_PERCENT
+                        : Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_BY_VALUE
+                    ),
+                    (string) $filterRule['val'],
+                    (((isset($filterRule['top'])) && ($filterRule['top'] == 1))
+                        ? Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_TOP
+                        : Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_BOTTOM
+                    )
+                )->setRuleType(Rule::AUTOFILTER_RULETYPE_TOPTENFILTER);
+            }
+        }
+    }
+}

+ 19 - 0
htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xlsx/BaseParserClass.php

@@ -0,0 +1,19 @@
+<?php
+
+namespace PhpOffice\PhpSpreadsheet\Reader\Xlsx;
+
+class BaseParserClass
+{
+    protected static function boolean($value)
+    {
+        if (is_object($value)) {
+            $value = (string) $value;
+        }
+
+        if (is_numeric($value)) {
+            return (bool) $value;
+        }
+
+        return $value === strtolower('true');
+    }
+}

+ 204 - 0
htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xlsx/ColumnAndRowAttributes.php

@@ -0,0 +1,204 @@
+<?php
+
+namespace PhpOffice\PhpSpreadsheet\Reader\Xlsx;
+
+use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
+use PhpOffice\PhpSpreadsheet\Reader\IReadFilter;
+use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
+
+class ColumnAndRowAttributes extends BaseParserClass
+{
+    private $worksheet;
+
+    private $worksheetXml;
+
+    public function __construct(Worksheet $workSheet, \SimpleXMLElement $worksheetXml = null)
+    {
+        $this->worksheet = $workSheet;
+        $this->worksheetXml = $worksheetXml;
+    }
+
+    /**
+     * Set Worksheet column attributes by attributes array passed.
+     *
+     * @param string $columnAddress A, B, ... DX, ...
+     * @param array $columnAttributes array of attributes (indexes are attribute name, values are value)
+     *                               'xfIndex', 'visible', 'collapsed', 'outlineLevel', 'width', ... ?
+     */
+    private function setColumnAttributes($columnAddress, array $columnAttributes)
+    {
+        if (isset($columnAttributes['xfIndex'])) {
+            $this->worksheet->getColumnDimension($columnAddress)->setXfIndex($columnAttributes['xfIndex']);
+        }
+        if (isset($columnAttributes['visible'])) {
+            $this->worksheet->getColumnDimension($columnAddress)->setVisible($columnAttributes['visible']);
+        }
+        if (isset($columnAttributes['collapsed'])) {
+            $this->worksheet->getColumnDimension($columnAddress)->setCollapsed($columnAttributes['collapsed']);
+        }
+        if (isset($columnAttributes['outlineLevel'])) {
+            $this->worksheet->getColumnDimension($columnAddress)->setOutlineLevel($columnAttributes['outlineLevel']);
+        }
+        if (isset($columnAttributes['width'])) {
+            $this->worksheet->getColumnDimension($columnAddress)->setWidth($columnAttributes['width']);
+        }
+    }
+
+    /**
+     * Set Worksheet row attributes by attributes array passed.
+     *
+     * @param int $rowNumber 1, 2, 3, ... 99, ...
+     * @param array $rowAttributes array of attributes (indexes are attribute name, values are value)
+     *                               'xfIndex', 'visible', 'collapsed', 'outlineLevel', 'rowHeight', ... ?
+     */
+    private function setRowAttributes($rowNumber, array $rowAttributes)
+    {
+        if (isset($rowAttributes['xfIndex'])) {
+            $this->worksheet->getRowDimension($rowNumber)->setXfIndex($rowAttributes['xfIndex']);
+        }
+        if (isset($rowAttributes['visible'])) {
+            $this->worksheet->getRowDimension($rowNumber)->setVisible($rowAttributes['visible']);
+        }
+        if (isset($rowAttributes['collapsed'])) {
+            $this->worksheet->getRowDimension($rowNumber)->setCollapsed($rowAttributes['collapsed']);
+        }
+        if (isset($rowAttributes['outlineLevel'])) {
+            $this->worksheet->getRowDimension($rowNumber)->setOutlineLevel($rowAttributes['outlineLevel']);
+        }
+        if (isset($rowAttributes['rowHeight'])) {
+            $this->worksheet->getRowDimension($rowNumber)->setRowHeight($rowAttributes['rowHeight']);
+        }
+    }
+
+    /**
+     * @param IReadFilter $readFilter
+     * @param bool $readDataOnly
+     */
+    public function load(IReadFilter $readFilter = null, $readDataOnly = false)
+    {
+        if ($this->worksheetXml === null) {
+            return;
+        }
+
+        $columnsAttributes = [];
+        $rowsAttributes = [];
+        if (isset($this->worksheetXml->cols)) {
+            $columnsAttributes = $this->readColumnAttributes($this->worksheetXml->cols, $readDataOnly);
+        }
+
+        if ($this->worksheetXml->sheetData && $this->worksheetXml->sheetData->row) {
+            $rowsAttributes = $this->readRowAttributes($this->worksheetXml->sheetData->row, $readDataOnly);
+        }
+
+        // set columns/rows attributes
+        $columnsAttributesAreSet = [];
+        foreach ($columnsAttributes as $columnCoordinate => $columnAttributes) {
+            if ($readFilter === null ||
+                !$this->isFilteredColumn($readFilter, $columnCoordinate, $rowsAttributes)) {
+                if (!isset($columnsAttributesAreSet[$columnCoordinate])) {
+                    $this->setColumnAttributes($columnCoordinate, $columnAttributes);
+                    $columnsAttributesAreSet[$columnCoordinate] = true;
+                }
+            }
+        }
+
+        $rowsAttributesAreSet = [];
+        foreach ($rowsAttributes as $rowCoordinate => $rowAttributes) {
+            if ($readFilter === null ||
+                !$this->isFilteredRow($readFilter, $rowCoordinate, $columnsAttributes)) {
+                if (!isset($rowsAttributesAreSet[$rowCoordinate])) {
+                    $this->setRowAttributes($rowCoordinate, $rowAttributes);
+                    $rowsAttributesAreSet[$rowCoordinate] = true;
+                }
+            }
+        }
+    }
+
+    private function isFilteredColumn(IReadFilter $readFilter, $columnCoordinate, array $rowsAttributes)
+    {
+        foreach ($rowsAttributes as $rowCoordinate => $rowAttributes) {
+            if (!$readFilter->readCell($columnCoordinate, $rowCoordinate, $this->worksheet->getTitle())) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    private function readColumnAttributes(\SimpleXMLElement $worksheetCols, $readDataOnly)
+    {
+        $columnAttributes = [];
+
+        foreach ($worksheetCols->col as $column) {
+            $startColumn = Coordinate::stringFromColumnIndex((int) $column['min']);
+            $endColumn = Coordinate::stringFromColumnIndex((int) $column['max']);
+            ++$endColumn;
+            for ($columnAddress = $startColumn; $columnAddress !== $endColumn; ++$columnAddress) {
+                $columnAttributes[$columnAddress] = $this->readColumnRangeAttributes($column, $readDataOnly);
+
+                if ((int) ($column['max']) == 16384) {
+                    break;
+                }
+            }
+        }
+
+        return $columnAttributes;
+    }
+
+    private function readColumnRangeAttributes(\SimpleXMLElement $column, $readDataOnly)
+    {
+        $columnAttributes = [];
+
+        if ($column['style'] && !$readDataOnly) {
+            $columnAttributes['xfIndex'] = (int) $column['style'];
+        }
+        if (self::boolean($column['hidden'])) {
+            $columnAttributes['visible'] = false;
+        }
+        if (self::boolean($column['collapsed'])) {
+            $columnAttributes['collapsed'] = true;
+        }
+        if (((int) $column['outlineLevel']) > 0) {
+            $columnAttributes['outlineLevel'] = (int) $column['outlineLevel'];
+        }
+        $columnAttributes['width'] = (float) $column['width'];
+
+        return $columnAttributes;
+    }
+
+    private function isFilteredRow(IReadFilter $readFilter, $rowCoordinate, array $columnsAttributes)
+    {
+        foreach ($columnsAttributes as $columnCoordinate => $columnAttributes) {
+            if (!$readFilter->readCell($columnCoordinate, $rowCoordinate, $this->worksheet->getTitle())) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    private function readRowAttributes(\SimpleXMLElement $worksheetRow, $readDataOnly)
+    {
+        $rowAttributes = [];
+
+        foreach ($worksheetRow as $row) {
+            if ($row['ht'] && !$readDataOnly) {
+                $rowAttributes[(int) $row['r']]['rowHeight'] = (float) $row['ht'];
+            }
+            if (self::boolean($row['hidden'])) {
+                $rowAttributes[(int) $row['r']]['visible'] = false;
+            }
+            if (self::boolean($row['collapsed'])) {
+                $rowAttributes[(int) $row['r']]['collapsed'] = true;
+            }
+            if ((int) $row['outlineLevel'] > 0) {
+                $rowAttributes[(int) $row['r']]['outlineLevel'] = (int) $row['outlineLevel'];
+            }
+            if ($row['s'] && !$readDataOnly) {
+                $rowAttributes[(int) $row['r']]['xfIndex'] = (int) $row['s'];
+            }
+        }
+
+        return $rowAttributes;
+    }
+}

+ 92 - 0
htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xlsx/ConditionalStyles.php

@@ -0,0 +1,92 @@
+<?php
+
+namespace PhpOffice\PhpSpreadsheet\Reader\Xlsx;
+
+use PhpOffice\PhpSpreadsheet\Style\Conditional;
+use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
+
+class ConditionalStyles
+{
+    private $worksheet;
+
+    private $worksheetXml;
+
+    private $dxfs;
+
+    public function __construct(Worksheet $workSheet, \SimpleXMLElement $worksheetXml, array $dxfs = [])
+    {
+        $this->worksheet = $workSheet;
+        $this->worksheetXml = $worksheetXml;
+        $this->dxfs = $dxfs;
+    }
+
+    public function load()
+    {
+        $this->setConditionalStyles(
+            $this->worksheet,
+            $this->readConditionalStyles($this->worksheetXml)
+        );
+    }
+
+    private function readConditionalStyles($xmlSheet)
+    {
+        $conditionals = [];
+        foreach ($xmlSheet->conditionalFormatting as $conditional) {
+            foreach ($conditional->cfRule as $cfRule) {
+                if (((string) $cfRule['type'] == Conditional::CONDITION_NONE
+                    || (string) $cfRule['type'] == Conditional::CONDITION_CELLIS
+                    || (string) $cfRule['type'] == Conditional::CONDITION_CONTAINSTEXT
+                    || (string) $cfRule['type'] == Conditional::CONDITION_EXPRESSION)
+                    && isset($this->dxfs[(int) ($cfRule['dxfId'])])) {
+                    $conditionals[(string) $conditional['sqref']][(int) ($cfRule['priority'])] = $cfRule;
+                }
+            }
+        }
+
+        return $conditionals;
+    }
+
+    private function setConditionalStyles(Worksheet $worksheet, array $conditionals)
+    {
+        foreach ($conditionals as $ref => $cfRules) {
+            ksort($cfRules);
+            $conditionalStyles = $this->readStyleRules($cfRules);
+
+            // Extract all cell references in $ref
+            $cellBlocks = explode(' ', str_replace('$', '', strtoupper($ref)));
+            foreach ($cellBlocks as $cellBlock) {
+                $worksheet->getStyle($cellBlock)->setConditionalStyles($conditionalStyles);
+            }
+        }
+    }
+
+    private function readStyleRules($cfRules)
+    {
+        $conditionalStyles = [];
+        foreach ($cfRules as $cfRule) {
+            $objConditional = new Conditional();
+            $objConditional->setConditionType((string) $cfRule['type']);
+            $objConditional->setOperatorType((string) $cfRule['operator']);
+
+            if ((string) $cfRule['text'] != '') {
+                $objConditional->setText((string) $cfRule['text']);
+            }
+
+            if (isset($cfRule['stopIfTrue']) && (int) $cfRule['stopIfTrue'] === 1) {
+                $objConditional->setStopIfTrue(true);
+            }
+
+            if (count($cfRule->formula) > 1) {
+                foreach ($cfRule->formula as $formula) {
+                    $objConditional->addCondition((string) $formula);
+                }
+            } else {
+                $objConditional->addCondition((string) $cfRule->formula);
+            }
+            $objConditional->setStyle(clone $this->dxfs[(int) ($cfRule['dxfId'])]);
+            $conditionalStyles[] = $objConditional;
+        }
+
+        return $conditionalStyles;
+    }
+}

+ 50 - 0
htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xlsx/DataValidations.php

@@ -0,0 +1,50 @@
+<?php
+
+namespace PhpOffice\PhpSpreadsheet\Reader\Xlsx;
+
+use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
+use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
+
+class DataValidations
+{
+    private $worksheet;
+
+    private $worksheetXml;
+
+    public function __construct(Worksheet $workSheet, \SimpleXMLElement $worksheetXml)
+    {
+        $this->worksheet = $workSheet;
+        $this->worksheetXml = $worksheetXml;
+    }
+
+    public function load()
+    {
+        foreach ($this->worksheetXml->dataValidations->dataValidation as $dataValidation) {
+            // Uppercase coordinate
+            $range = strtoupper($dataValidation['sqref']);
+            $rangeSet = explode(' ', $range);
+            foreach ($rangeSet as $range) {
+                $stRange = $this->worksheet->shrinkRangeToFit($range);
+
+                // Extract all cell references in $range
+                foreach (Coordinate::extractAllCellReferencesInRange($stRange) as $reference) {
+                    // Create validation
+                    $docValidation = $this->worksheet->getCell($reference)->getDataValidation();
+                    $docValidation->setType((string) $dataValidation['type']);
+                    $docValidation->setErrorStyle((string) $dataValidation['errorStyle']);
+                    $docValidation->setOperator((string) $dataValidation['operator']);
+                    $docValidation->setAllowBlank($dataValidation['allowBlank'] != 0);
+                    $docValidation->setShowDropDown($dataValidation['showDropDown'] == 0);
+                    $docValidation->setShowInputMessage($dataValidation['showInputMessage'] != 0);
+                    $docValidation->setShowErrorMessage($dataValidation['showErrorMessage'] != 0);
+                    $docValidation->setErrorTitle((string) $dataValidation['errorTitle']);
+                    $docValidation->setError((string) $dataValidation['error']);
+                    $docValidation->setPromptTitle((string) $dataValidation['promptTitle']);
+                    $docValidation->setPrompt((string) $dataValidation['prompt']);
+                    $docValidation->setFormula1((string) $dataValidation->formula1);
+                    $docValidation->setFormula2((string) $dataValidation->formula2);
+                }
+            }
+        }
+    }
+}

+ 58 - 0
htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xlsx/Hyperlinks.php

@@ -0,0 +1,58 @@
+<?php
+
+namespace PhpOffice\PhpSpreadsheet\Reader\Xlsx;
+
+use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
+use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
+
+class Hyperlinks
+{
+    private $worksheet;
+
+    private $hyperlinks = [];
+
+    public function __construct(Worksheet $workSheet)
+    {
+        $this->worksheet = $workSheet;
+    }
+
+    public function readHyperlinks(\SimpleXMLElement $relsWorksheet)
+    {
+        foreach ($relsWorksheet->Relationship as $element) {
+            if ($element['Type'] == 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink') {
+                $this->hyperlinks[(string) $element['Id']] = (string) $element['Target'];
+            }
+        }
+    }
+
+    public function setHyperlinks(\SimpleXMLElement $worksheetXml)
+    {
+        foreach ($worksheetXml->hyperlink as $hyperlink) {
+            $this->setHyperlink($hyperlink, $this->worksheet);
+        }
+    }
+
+    private function setHyperlink(\SimpleXMLElement $hyperlink, Worksheet $worksheet)
+    {
+        // Link url
+        $linkRel = $hyperlink->attributes('http://schemas.openxmlformats.org/officeDocument/2006/relationships');
+
+        foreach (Coordinate::extractAllCellReferencesInRange($hyperlink['ref']) as $cellReference) {
+            $cell = $worksheet->getCell($cellReference);
+            if (isset($linkRel['id'])) {
+                $hyperlinkUrl = $this->hyperlinks[(string) $linkRel['id']];
+                if (isset($hyperlink['location'])) {
+                    $hyperlinkUrl .= '#' . (string) $hyperlink['location'];
+                }
+                $cell->getHyperlink()->setUrl($hyperlinkUrl);
+            } elseif (isset($hyperlink['location'])) {
+                $cell->getHyperlink()->setUrl('sheet://' . (string) $hyperlink['location']);
+            }
+
+            // Tooltip
+            if (isset($hyperlink['tooltip'])) {
+                $cell->getHyperlink()->setTooltip((string) $hyperlink['tooltip']);
+            }
+        }
+    }
+}

+ 150 - 0
htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xlsx/PageSetup.php

@@ -0,0 +1,150 @@
+<?php
+
+namespace PhpOffice\PhpSpreadsheet\Reader\Xlsx;
+
+use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
+use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
+
+class PageSetup extends BaseParserClass
+{
+    private $worksheet;
+
+    private $worksheetXml;
+
+    public function __construct(Worksheet $workSheet, \SimpleXMLElement $worksheetXml = null)
+    {
+        $this->worksheet = $workSheet;
+        $this->worksheetXml = $worksheetXml;
+    }
+
+    public function load(array $unparsedLoadedData)
+    {
+        if (!$this->worksheetXml) {
+            return $unparsedLoadedData;
+        }
+
+        $this->margins($this->worksheetXml, $this->worksheet);
+        $unparsedLoadedData = $this->pageSetup($this->worksheetXml, $this->worksheet, $unparsedLoadedData);
+        $this->headerFooter($this->worksheetXml, $this->worksheet);
+        $this->pageBreaks($this->worksheetXml, $this->worksheet);
+
+        return $unparsedLoadedData;
+    }
+
+    private function margins(\SimpleXMLElement $xmlSheet, Worksheet $worksheet)
+    {
+        if ($xmlSheet->pageMargins) {
+            $docPageMargins = $worksheet->getPageMargins();
+            $docPageMargins->setLeft((float) ($xmlSheet->pageMargins['left']));
+            $docPageMargins->setRight((float) ($xmlSheet->pageMargins['right']));
+            $docPageMargins->setTop((float) ($xmlSheet->pageMargins['top']));
+            $docPageMargins->setBottom((float) ($xmlSheet->pageMargins['bottom']));
+            $docPageMargins->setHeader((float) ($xmlSheet->pageMargins['header']));
+            $docPageMargins->setFooter((float) ($xmlSheet->pageMargins['footer']));
+        }
+    }
+
+    private function pageSetup(\SimpleXMLElement $xmlSheet, Worksheet $worksheet, array $unparsedLoadedData)
+    {
+        if ($xmlSheet->pageSetup) {
+            $docPageSetup = $worksheet->getPageSetup();
+
+            if (isset($xmlSheet->pageSetup['orientation'])) {
+                $docPageSetup->setOrientation((string) $xmlSheet->pageSetup['orientation']);
+            }
+            if (isset($xmlSheet->pageSetup['paperSize'])) {
+                $docPageSetup->setPaperSize((int) ($xmlSheet->pageSetup['paperSize']));
+            }
+            if (isset($xmlSheet->pageSetup['scale'])) {
+                $docPageSetup->setScale((int) ($xmlSheet->pageSetup['scale']), false);
+            }
+            if (isset($xmlSheet->pageSetup['fitToHeight']) && (int) ($xmlSheet->pageSetup['fitToHeight']) >= 0) {
+                $docPageSetup->setFitToHeight((int) ($xmlSheet->pageSetup['fitToHeight']), false);
+            }
+            if (isset($xmlSheet->pageSetup['fitToWidth']) && (int) ($xmlSheet->pageSetup['fitToWidth']) >= 0) {
+                $docPageSetup->setFitToWidth((int) ($xmlSheet->pageSetup['fitToWidth']), false);
+            }
+            if (isset($xmlSheet->pageSetup['firstPageNumber'], $xmlSheet->pageSetup['useFirstPageNumber']) &&
+                self::boolean((string) $xmlSheet->pageSetup['useFirstPageNumber'])) {
+                $docPageSetup->setFirstPageNumber((int) ($xmlSheet->pageSetup['firstPageNumber']));
+            }
+
+            $relAttributes = $xmlSheet->pageSetup->attributes('http://schemas.openxmlformats.org/officeDocument/2006/relationships');
+            if (isset($relAttributes['id'])) {
+                $unparsedLoadedData['sheets'][$worksheet->getCodeName()]['pageSetupRelId'] = (string) $relAttributes['id'];
+            }
+        }
+
+        return $unparsedLoadedData;
+    }
+
+    private function headerFooter(\SimpleXMLElement $xmlSheet, Worksheet $worksheet)
+    {
+        if ($xmlSheet->headerFooter) {
+            $docHeaderFooter = $worksheet->getHeaderFooter();
+
+            if (isset($xmlSheet->headerFooter['differentOddEven']) &&
+                self::boolean((string) $xmlSheet->headerFooter['differentOddEven'])) {
+                $docHeaderFooter->setDifferentOddEven(true);
+            } else {
+                $docHeaderFooter->setDifferentOddEven(false);
+            }
+            if (isset($xmlSheet->headerFooter['differentFirst']) &&
+                self::boolean((string) $xmlSheet->headerFooter['differentFirst'])) {
+                $docHeaderFooter->setDifferentFirst(true);
+            } else {
+                $docHeaderFooter->setDifferentFirst(false);
+            }
+            if (isset($xmlSheet->headerFooter['scaleWithDoc']) &&
+                !self::boolean((string) $xmlSheet->headerFooter['scaleWithDoc'])) {
+                $docHeaderFooter->setScaleWithDocument(false);
+            } else {
+                $docHeaderFooter->setScaleWithDocument(true);
+            }
+            if (isset($xmlSheet->headerFooter['alignWithMargins']) &&
+                !self::boolean((string) $xmlSheet->headerFooter['alignWithMargins'])) {
+                $docHeaderFooter->setAlignWithMargins(false);
+            } else {
+                $docHeaderFooter->setAlignWithMargins(true);
+            }
+
+            $docHeaderFooter->setOddHeader((string) $xmlSheet->headerFooter->oddHeader);
+            $docHeaderFooter->setOddFooter((string) $xmlSheet->headerFooter->oddFooter);
+            $docHeaderFooter->setEvenHeader((string) $xmlSheet->headerFooter->evenHeader);
+            $docHeaderFooter->setEvenFooter((string) $xmlSheet->headerFooter->evenFooter);
+            $docHeaderFooter->setFirstHeader((string) $xmlSheet->headerFooter->firstHeader);
+            $docHeaderFooter->setFirstFooter((string) $xmlSheet->headerFooter->firstFooter);
+        }
+    }
+
+    private function pageBreaks(\SimpleXMLElement $xmlSheet, Worksheet $worksheet)
+    {
+        if ($xmlSheet->rowBreaks && $xmlSheet->rowBreaks->brk) {
+            $this->rowBreaks($xmlSheet, $worksheet);
+        }
+        if ($xmlSheet->colBreaks && $xmlSheet->colBreaks->brk) {
+            $this->columnBreaks($xmlSheet, $worksheet);
+        }
+    }
+
+    private function rowBreaks(\SimpleXMLElement $xmlSheet, Worksheet $worksheet)
+    {
+        foreach ($xmlSheet->rowBreaks->brk as $brk) {
+            if ($brk['man']) {
+                $worksheet->setBreak("A{$brk['id']}", Worksheet::BREAK_ROW);
+            }
+        }
+    }
+
+    private function columnBreaks(\SimpleXMLElement $xmlSheet, Worksheet $worksheet)
+    {
+        foreach ($xmlSheet->colBreaks->brk as $brk) {
+            if ($brk['man']) {
+                $worksheet->setBreak(
+                    Coordinate::stringFromColumnIndex(((int) $brk['id']) + 1) . '1',
+                    Worksheet::BREAK_COLUMN
+                );
+            }
+        }
+    }
+}

+ 91 - 0
htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xlsx/Properties.php

@@ -0,0 +1,91 @@
+<?php
+
+namespace PhpOffice\PhpSpreadsheet\Reader\Xlsx;
+
+use PhpOffice\PhpSpreadsheet\Document\Properties as DocumentProperties;
+use PhpOffice\PhpSpreadsheet\Reader\Security\XmlScanner;
+use PhpOffice\PhpSpreadsheet\Settings;
+
+class Properties
+{
+    private $securityScanner;
+
+    private $docProps;
+
+    public function __construct(XmlScanner $securityScanner, DocumentProperties $docProps)
+    {
+        $this->securityScanner = $securityScanner;
+        $this->docProps = $docProps;
+    }
+
+    private function extractPropertyData($propertyData)
+    {
+        return simplexml_load_string(
+            $this->securityScanner->scan($propertyData),
+            'SimpleXMLElement',
+            Settings::getLibXmlLoaderOptions()
+        );
+    }
+
+    public function readCoreProperties($propertyData)
+    {
+        $xmlCore = $this->extractPropertyData($propertyData);
+
+        if (is_object($xmlCore)) {
+            $xmlCore->registerXPathNamespace('dc', 'http://purl.org/dc/elements/1.1/');
+            $xmlCore->registerXPathNamespace('dcterms', 'http://purl.org/dc/terms/');
+            $xmlCore->registerXPathNamespace('cp', 'http://schemas.openxmlformats.org/package/2006/metadata/core-properties');
+
+            $this->docProps->setCreator((string) self::getArrayItem($xmlCore->xpath('dc:creator')));
+            $this->docProps->setLastModifiedBy((string) self::getArrayItem($xmlCore->xpath('cp:lastModifiedBy')));
+            $this->docProps->setCreated(strtotime(self::getArrayItem($xmlCore->xpath('dcterms:created')))); //! respect xsi:type
+            $this->docProps->setModified(strtotime(self::getArrayItem($xmlCore->xpath('dcterms:modified')))); //! respect xsi:type
+            $this->docProps->setTitle((string) self::getArrayItem($xmlCore->xpath('dc:title')));
+            $this->docProps->setDescription((string) self::getArrayItem($xmlCore->xpath('dc:description')));
+            $this->docProps->setSubject((string) self::getArrayItem($xmlCore->xpath('dc:subject')));
+            $this->docProps->setKeywords((string) self::getArrayItem($xmlCore->xpath('cp:keywords')));
+            $this->docProps->setCategory((string) self::getArrayItem($xmlCore->xpath('cp:category')));
+        }
+    }
+
+    public function readExtendedProperties($propertyData)
+    {
+        $xmlCore = $this->extractPropertyData($propertyData);
+
+        if (is_object($xmlCore)) {
+            if (isset($xmlCore->Company)) {
+                $this->docProps->setCompany((string) $xmlCore->Company);
+            }
+            if (isset($xmlCore->Manager)) {
+                $this->docProps->setManager((string) $xmlCore->Manager);
+            }
+        }
+    }
+
+    public function readCustomProperties($propertyData)
+    {
+        $xmlCore = $this->extractPropertyData($propertyData);
+
+        if (is_object($xmlCore)) {
+            foreach ($xmlCore as $xmlProperty) {
+                /** @var \SimpleXMLElement $xmlProperty */
+                $cellDataOfficeAttributes = $xmlProperty->attributes();
+                if (isset($cellDataOfficeAttributes['name'])) {
+                    $propertyName = (string) $cellDataOfficeAttributes['name'];
+                    $cellDataOfficeChildren = $xmlProperty->children('http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes');
+
+                    $attributeType = $cellDataOfficeChildren->getName();
+                    $attributeValue = (string) $cellDataOfficeChildren->{$attributeType};
+                    $attributeValue = DocumentProperties::convertProperty($attributeValue, $attributeType);
+                    $attributeType = DocumentProperties::convertPropertyType($attributeType);
+                    $this->docProps->setCustomProperty($propertyName, $attributeValue, $attributeType);
+                }
+            }
+        }
+    }
+
+    private static function getArrayItem(array $array, $key = 0)
+    {
+        return isset($array[$key]) ? $array[$key] : null;
+    }
+}

+ 124 - 0
htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xlsx/SheetViewOptions.php

@@ -0,0 +1,124 @@
+<?php
+
+namespace PhpOffice\PhpSpreadsheet\Reader\Xlsx;
+
+use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
+
+class SheetViewOptions extends BaseParserClass
+{
+    private $worksheet;
+
+    private $worksheetXml;
+
+    public function __construct(Worksheet $workSheet, \SimpleXMLElement $worksheetXml = null)
+    {
+        $this->worksheet = $workSheet;
+        $this->worksheetXml = $worksheetXml;
+    }
+
+    /**
+     * @param bool $readDataOnly
+     */
+    public function load($readDataOnly = false)
+    {
+        if ($this->worksheetXml === null) {
+            return;
+        }
+
+        if (isset($this->worksheetXml->sheetPr)) {
+            $this->tabColor($this->worksheetXml->sheetPr);
+            $this->codeName($this->worksheetXml->sheetPr);
+            $this->outlines($this->worksheetXml->sheetPr);
+            $this->pageSetup($this->worksheetXml->sheetPr);
+        }
+
+        if (isset($this->worksheetXml->sheetFormatPr)) {
+            $this->sheetFormat($this->worksheetXml->sheetFormatPr);
+        }
+
+        if (!$readDataOnly && isset($this->worksheetXml->printOptions)) {
+            $this->printOptions($this->worksheetXml->printOptions);
+        }
+    }
+
+    private function tabColor(\SimpleXMLElement $sheetPr)
+    {
+        if (isset($sheetPr->tabColor, $sheetPr->tabColor['rgb'])) {
+            $this->worksheet->getTabColor()->setARGB((string) $sheetPr->tabColor['rgb']);
+        }
+    }
+
+    private function codeName(\SimpleXMLElement $sheetPr)
+    {
+        if (isset($sheetPr['codeName'])) {
+            $this->worksheet->setCodeName((string) $sheetPr['codeName'], false);
+        }
+    }
+
+    private function outlines(\SimpleXMLElement $sheetPr)
+    {
+        if (isset($sheetPr->outlinePr)) {
+            if (isset($sheetPr->outlinePr['summaryRight']) &&
+                !self::boolean((string) $sheetPr->outlinePr['summaryRight'])) {
+                $this->worksheet->setShowSummaryRight(false);
+            } else {
+                $this->worksheet->setShowSummaryRight(true);
+            }
+
+            if (isset($sheetPr->outlinePr['summaryBelow']) &&
+                !self::boolean((string) $sheetPr->outlinePr['summaryBelow'])) {
+                $this->worksheet->setShowSummaryBelow(false);
+            } else {
+                $this->worksheet->setShowSummaryBelow(true);
+            }
+        }
+    }
+
+    private function pageSetup(\SimpleXMLElement $sheetPr)
+    {
+        if (isset($sheetPr->pageSetUpPr)) {
+            if (isset($sheetPr->pageSetUpPr['fitToPage']) &&
+                !self::boolean((string) $sheetPr->pageSetUpPr['fitToPage'])) {
+                $this->worksheet->getPageSetup()->setFitToPage(false);
+            } else {
+                $this->worksheet->getPageSetup()->setFitToPage(true);
+            }
+        }
+    }
+
+    private function sheetFormat(\SimpleXMLElement $sheetFormatPr)
+    {
+        if (isset($sheetFormatPr['customHeight']) &&
+            self::boolean((string) $sheetFormatPr['customHeight']) &&
+            isset($sheetFormatPr['defaultRowHeight'])) {
+            $this->worksheet->getDefaultRowDimension()
+                ->setRowHeight((float) $sheetFormatPr['defaultRowHeight']);
+        }
+
+        if (isset($sheetFormatPr['defaultColWidth'])) {
+            $this->worksheet->getDefaultColumnDimension()
+                ->setWidth((float) $sheetFormatPr['defaultColWidth']);
+        }
+
+        if (isset($sheetFormatPr['zeroHeight']) &&
+            ((string) $sheetFormatPr['zeroHeight'] === '1')) {
+            $this->worksheet->getDefaultRowDimension()->setZeroHeight(true);
+        }
+    }
+
+    private function printOptions(\SimpleXMLElement $printOptions)
+    {
+        if (self::boolean((string) $printOptions['gridLinesSet'])) {
+            $this->worksheet->setShowGridlines(true);
+        }
+        if (self::boolean((string) $printOptions['gridLines'])) {
+            $this->worksheet->setPrintGridlines(true);
+        }
+        if (self::boolean((string) $printOptions['horizontalCentered'])) {
+            $this->worksheet->getPageSetup()->setHorizontalCentered(true);
+        }
+        if (self::boolean((string) $printOptions['verticalCentered'])) {
+            $this->worksheet->getPageSetup()->setVerticalCentered(true);
+        }
+    }
+}

+ 127 - 0
htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xlsx/SheetViews.php

@@ -0,0 +1,127 @@
+<?php
+
+namespace PhpOffice\PhpSpreadsheet\Reader\Xlsx;
+
+use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
+use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
+
+class SheetViews extends BaseParserClass
+{
+    private $sheetViewXml;
+
+    private $worksheet;
+
+    public function __construct(\SimpleXMLElement $sheetViewXml, Worksheet $workSheet)
+    {
+        $this->sheetViewXml = $sheetViewXml;
+        $this->worksheet = $workSheet;
+    }
+
+    public function load()
+    {
+        $this->zoomScale();
+        $this->view();
+        $this->gridLines();
+        $this->headers();
+        $this->direction();
+
+        if (isset($this->sheetViewXml->pane)) {
+            $this->pane();
+        }
+        if (isset($this->sheetViewXml->selection, $this->sheetViewXml->selection['sqref'])) {
+            $this->selection();
+        }
+    }
+
+    private function zoomScale()
+    {
+        if (isset($this->sheetViewXml['zoomScale'])) {
+            $zoomScale = (int) ($this->sheetViewXml['zoomScale']);
+            if ($zoomScale <= 0) {
+                // setZoomScale will throw an Exception if the scale is less than or equals 0
+                // that is OK when manually creating documents, but we should be able to read all documents
+                $zoomScale = 100;
+            }
+
+            $this->worksheet->getSheetView()->setZoomScale($zoomScale);
+        }
+
+        if (isset($this->sheetViewXml['zoomScaleNormal'])) {
+            $zoomScaleNormal = (int) ($this->sheetViewXml['zoomScaleNormal']);
+            if ($zoomScaleNormal <= 0) {
+                // setZoomScaleNormal will throw an Exception if the scale is less than or equals 0
+                // that is OK when manually creating documents, but we should be able to read all documents
+                $zoomScaleNormal = 100;
+            }
+
+            $this->worksheet->getSheetView()->setZoomScaleNormal($zoomScaleNormal);
+        }
+    }
+
+    private function view()
+    {
+        if (isset($this->sheetViewXml['view'])) {
+            $this->worksheet->getSheetView()->setView((string) $this->sheetViewXml['view']);
+        }
+    }
+
+    private function gridLines()
+    {
+        if (isset($this->sheetViewXml['showGridLines'])) {
+            $this->worksheet->setShowGridLines(
+                self::boolean((string) $this->sheetViewXml['showGridLines'])
+            );
+        }
+    }
+
+    private function headers()
+    {
+        if (isset($this->sheetViewXml['showRowColHeaders'])) {
+            $this->worksheet->setShowRowColHeaders(
+                self::boolean((string) $this->sheetViewXml['showRowColHeaders'])
+            );
+        }
+    }
+
+    private function direction()
+    {
+        if (isset($this->sheetViewXml['rightToLeft'])) {
+            $this->worksheet->setRightToLeft(
+                self::boolean((string) $this->sheetViewXml['rightToLeft'])
+            );
+        }
+    }
+
+    private function pane()
+    {
+        $xSplit = 0;
+        $ySplit = 0;
+        $topLeftCell = null;
+
+        if (isset($this->sheetViewXml->pane['xSplit'])) {
+            $xSplit = (int) ($this->sheetViewXml->pane['xSplit']);
+        }
+
+        if (isset($this->sheetViewXml->pane['ySplit'])) {
+            $ySplit = (int) ($this->sheetViewXml->pane['ySplit']);
+        }
+
+        if (isset($this->sheetViewXml->pane['topLeftCell'])) {
+            $topLeftCell = (string) $this->sheetViewXml->pane['topLeftCell'];
+        }
+
+        $this->worksheet->freezePane(
+            Coordinate::stringFromColumnIndex($xSplit + 1) . ($ySplit + 1),
+            $topLeftCell
+        );
+    }
+
+    private function selection()
+    {
+        $sqref = (string) $this->sheetViewXml->selection['sqref'];
+        $sqref = explode(' ', $sqref);
+        $sqref = $sqref[0];
+
+        $this->worksheet->setSelectedCells($sqref);
+    }
+}

+ 265 - 0
htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xlsx/Styles.php

@@ -0,0 +1,265 @@
+<?php
+
+namespace PhpOffice\PhpSpreadsheet\Reader\Xlsx;
+
+use PhpOffice\PhpSpreadsheet\Style\Alignment;
+use PhpOffice\PhpSpreadsheet\Style\Border;
+use PhpOffice\PhpSpreadsheet\Style\Borders;
+use PhpOffice\PhpSpreadsheet\Style\Color;
+use PhpOffice\PhpSpreadsheet\Style\Fill;
+use PhpOffice\PhpSpreadsheet\Style\Font;
+use PhpOffice\PhpSpreadsheet\Style\Protection;
+use PhpOffice\PhpSpreadsheet\Style\Style;
+
+class Styles extends BaseParserClass
+{
+    /**
+     * Theme instance.
+     *
+     * @var Theme
+     */
+    private static $theme = null;
+
+    private $styles = [];
+
+    private $cellStyles = [];
+
+    private $styleXml;
+
+    public function __construct(\SimpleXMLElement $styleXml)
+    {
+        $this->styleXml = $styleXml;
+    }
+
+    public function setStyleBaseData(Theme $theme = null, $styles = [], $cellStyles = [])
+    {
+        self::$theme = $theme;
+        $this->styles = $styles;
+        $this->cellStyles = $cellStyles;
+    }
+
+    private static function readFontStyle(Font $fontStyle, \SimpleXMLElement $fontStyleXml)
+    {
+        $fontStyle->setName((string) $fontStyleXml->name['val']);
+        $fontStyle->setSize((float) $fontStyleXml->sz['val']);
+
+        if (isset($fontStyleXml->b)) {
+            $fontStyle->setBold(!isset($fontStyleXml->b['val']) || self::boolean((string) $fontStyleXml->b['val']));
+        }
+        if (isset($fontStyleXml->i)) {
+            $fontStyle->setItalic(!isset($fontStyleXml->i['val']) || self::boolean((string) $fontStyleXml->i['val']));
+        }
+        if (isset($fontStyleXml->strike)) {
+            $fontStyle->setStrikethrough(!isset($fontStyleXml->strike['val']) || self::boolean((string) $fontStyleXml->strike['val']));
+        }
+        $fontStyle->getColor()->setARGB(self::readColor($fontStyleXml->color));
+
+        if (isset($fontStyleXml->u) && !isset($fontStyleXml->u['val'])) {
+            $fontStyle->setUnderline(Font::UNDERLINE_SINGLE);
+        } elseif (isset($fontStyleXml->u, $fontStyleXml->u['val'])) {
+            $fontStyle->setUnderline((string) $fontStyleXml->u['val']);
+        }
+
+        if (isset($fontStyleXml->vertAlign, $fontStyleXml->vertAlign['val'])) {
+            $verticalAlign = strtolower((string) $fontStyleXml->vertAlign['val']);
+            if ($verticalAlign === 'superscript') {
+                $fontStyle->setSuperscript(true);
+            }
+            if ($verticalAlign === 'subscript') {
+                $fontStyle->setSubscript(true);
+            }
+        }
+    }
+
+    private static function readFillStyle(Fill $fillStyle, \SimpleXMLElement $fillStyleXml)
+    {
+        if ($fillStyleXml->gradientFill) {
+            /** @var \SimpleXMLElement $gradientFill */
+            $gradientFill = $fillStyleXml->gradientFill[0];
+            if (!empty($gradientFill['type'])) {
+                $fillStyle->setFillType((string) $gradientFill['type']);
+            }
+            $fillStyle->setRotation((float) ($gradientFill['degree']));
+            $gradientFill->registerXPathNamespace('sml', 'http://schemas.openxmlformats.org/spreadsheetml/2006/main');
+            $fillStyle->getStartColor()->setARGB(self::readColor(self::getArrayItem($gradientFill->xpath('sml:stop[@position=0]'))->color));
+            $fillStyle->getEndColor()->setARGB(self::readColor(self::getArrayItem($gradientFill->xpath('sml:stop[@position=1]'))->color));
+        } elseif ($fillStyleXml->patternFill) {
+            $patternType = (string) $fillStyleXml->patternFill['patternType'] != '' ? (string) $fillStyleXml->patternFill['patternType'] : 'solid';
+            $fillStyle->setFillType($patternType);
+            if ($fillStyleXml->patternFill->fgColor) {
+                $fillStyle->getStartColor()->setARGB(self::readColor($fillStyleXml->patternFill->fgColor, true));
+            } else {
+                $fillStyle->getStartColor()->setARGB('FF000000');
+            }
+            if ($fillStyleXml->patternFill->bgColor) {
+                $fillStyle->getEndColor()->setARGB(self::readColor($fillStyleXml->patternFill->bgColor, true));
+            }
+        }
+    }
+
+    private static function readBorderStyle(Borders $borderStyle, \SimpleXMLElement $borderStyleXml)
+    {
+        $diagonalUp = self::boolean((string) $borderStyleXml['diagonalUp']);
+        $diagonalDown = self::boolean((string) $borderStyleXml['diagonalDown']);
+        if (!$diagonalUp && !$diagonalDown) {
+            $borderStyle->setDiagonalDirection(Borders::DIAGONAL_NONE);
+        } elseif ($diagonalUp && !$diagonalDown) {
+            $borderStyle->setDiagonalDirection(Borders::DIAGONAL_UP);
+        } elseif (!$diagonalUp && $diagonalDown) {
+            $borderStyle->setDiagonalDirection(Borders::DIAGONAL_DOWN);
+        } else {
+            $borderStyle->setDiagonalDirection(Borders::DIAGONAL_BOTH);
+        }
+
+        self::readBorder($borderStyle->getLeft(), $borderStyleXml->left);
+        self::readBorder($borderStyle->getRight(), $borderStyleXml->right);
+        self::readBorder($borderStyle->getTop(), $borderStyleXml->top);
+        self::readBorder($borderStyle->getBottom(), $borderStyleXml->bottom);
+        self::readBorder($borderStyle->getDiagonal(), $borderStyleXml->diagonal);
+    }
+
+    private static function readBorder(Border $border, \SimpleXMLElement $borderXml)
+    {
+        if (isset($borderXml['style'])) {
+            $border->setBorderStyle((string) $borderXml['style']);
+        }
+        if (isset($borderXml->color)) {
+            $border->getColor()->setARGB(self::readColor($borderXml->color));
+        }
+    }
+
+    private static function readAlignmentStyle(Alignment $alignment, \SimpleXMLElement $alignmentXml)
+    {
+        $alignment->setHorizontal((string) $alignmentXml->alignment['horizontal']);
+        $alignment->setVertical((string) $alignmentXml->alignment['vertical']);
+
+        $textRotation = 0;
+        if ((int) $alignmentXml->alignment['textRotation'] <= 90) {
+            $textRotation = (int) $alignmentXml->alignment['textRotation'];
+        } elseif ((int) $alignmentXml->alignment['textRotation'] > 90) {
+            $textRotation = 90 - (int) $alignmentXml->alignment['textRotation'];
+        }
+
+        $alignment->setTextRotation((int) $textRotation);
+        $alignment->setWrapText(self::boolean((string) $alignmentXml->alignment['wrapText']));
+        $alignment->setShrinkToFit(self::boolean((string) $alignmentXml->alignment['shrinkToFit']));
+        $alignment->setIndent((int) ((string) $alignmentXml->alignment['indent']) > 0 ? (int) ((string) $alignmentXml->alignment['indent']) : 0);
+        $alignment->setReadOrder((int) ((string) $alignmentXml->alignment['readingOrder']) > 0 ? (int) ((string) $alignmentXml->alignment['readingOrder']) : 0);
+    }
+
+    private function readStyle(Style $docStyle, $style)
+    {
+        $docStyle->getNumberFormat()->setFormatCode($style->numFmt);
+
+        if (isset($style->font)) {
+            self::readFontStyle($docStyle->getFont(), $style->font);
+        }
+
+        if (isset($style->fill)) {
+            self::readFillStyle($docStyle->getFill(), $style->fill);
+        }
+
+        if (isset($style->border)) {
+            self::readBorderStyle($docStyle->getBorders(), $style->border);
+        }
+
+        if (isset($style->alignment)) {
+            self::readAlignmentStyle($docStyle->getAlignment(), $style->alignment);
+        }
+
+        // protection
+        if (isset($style->protection)) {
+            $this->readProtectionLocked($docStyle, $style);
+            $this->readProtectionHidden($docStyle, $style);
+        }
+
+        // top-level style settings
+        if (isset($style->quotePrefix)) {
+            $docStyle->setQuotePrefix(true);
+        }
+    }
+
+    private function readProtectionLocked(Style $docStyle, $style)
+    {
+        if (isset($style->protection['locked'])) {
+            if (self::boolean((string) $style->protection['locked'])) {
+                $docStyle->getProtection()->setLocked(Protection::PROTECTION_PROTECTED);
+            } else {
+                $docStyle->getProtection()->setLocked(Protection::PROTECTION_UNPROTECTED);
+            }
+        }
+    }
+
+    private function readProtectionHidden(Style $docStyle, $style)
+    {
+        if (isset($style->protection['hidden'])) {
+            if (self::boolean((string) $style->protection['hidden'])) {
+                $docStyle->getProtection()->setHidden(Protection::PROTECTION_PROTECTED);
+            } else {
+                $docStyle->getProtection()->setHidden(Protection::PROTECTION_UNPROTECTED);
+            }
+        }
+    }
+
+    private static function readColor($color, $background = false)
+    {
+        if (isset($color['rgb'])) {
+            return (string) $color['rgb'];
+        } elseif (isset($color['indexed'])) {
+            return Color::indexedColor($color['indexed'] - 7, $background)->getARGB();
+        } elseif (isset($color['theme'])) {
+            if (self::$theme !== null) {
+                $returnColour = self::$theme->getColourByIndex((int) $color['theme']);
+                if (isset($color['tint'])) {
+                    $tintAdjust = (float) $color['tint'];
+                    $returnColour = Color::changeBrightness($returnColour, $tintAdjust);
+                }
+
+                return 'FF' . $returnColour;
+            }
+        }
+
+        return ($background) ? 'FFFFFFFF' : 'FF000000';
+    }
+
+    public function dxfs($readDataOnly = false)
+    {
+        $dxfs = [];
+        if (!$readDataOnly && $this->styleXml) {
+            //    Conditional Styles
+            if ($this->styleXml->dxfs) {
+                foreach ($this->styleXml->dxfs->dxf as $dxf) {
+                    $style = new Style(false, true);
+                    $this->readStyle($style, $dxf);
+                    $dxfs[] = $style;
+                }
+            }
+            //    Cell Styles
+            if ($this->styleXml->cellStyles) {
+                foreach ($this->styleXml->cellStyles->cellStyle as $cellStyle) {
+                    if ((int) ($cellStyle['builtinId']) == 0) {
+                        if (isset($this->cellStyles[(int) ($cellStyle['xfId'])])) {
+                            // Set default style
+                            $style = new Style();
+                            $this->readStyle($style, $this->cellStyles[(int) ($cellStyle['xfId'])]);
+
+                            // normal style, currently not using it for anything
+                        }
+                    }
+                }
+            }
+        }
+
+        return $dxfs;
+    }
+
+    public function styles()
+    {
+        return $this->styles;
+    }
+
+    private static function getArrayItem($array, $key = 0)
+    {
+        return isset($array[$key]) ? $array[$key] : null;
+    }
+}

+ 1 - 1
htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xml.php

@@ -41,7 +41,7 @@ class Xml extends BaseReader
      */
      */
     public function __construct()
     public function __construct()
     {
     {
-        $this->readFilter = new DefaultReadFilter();
+        parent::__construct();
         $this->securityScanner = XmlScanner::getInstance($this);
         $this->securityScanner = XmlScanner::getInstance($this);
     }
     }
 
 

+ 13 - 13
htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/ReferenceHelper.php

@@ -82,13 +82,13 @@ class ReferenceHelper
      */
      */
     public static function cellSort($a, $b)
     public static function cellSort($a, $b)
     {
     {
-        $ac = $bc = '';
-        $ar = $br = 0;
+        // TODO Scrutinizer doesn't like sscanf($a, '%[A-Z]%d', $ac, $ar), and we can't use short list() syntax
+        //      [$ac, $ar] = sscanf($a, '%[A-Z]%d') while retaining PHP 5.6 support.
+        //      Switch when we drop support for 5.6
+        list($ac, $ar) = sscanf($a, '%[A-Z]%d');
+        list($bc, $br) = sscanf($b, '%[A-Z]%d');
 
 
-        sscanf($a, '%[A-Z]%d', $ac, $ar);
-        sscanf($b, '%[A-Z]%d', $bc, $br);
-
-        if ($ar == $br) {
+        if ($ar === $br) {
             return strcasecmp(strlen($ac) . $ac, strlen($bc) . $bc);
             return strcasecmp(strlen($ac) . $ac, strlen($bc) . $bc);
         }
         }
 
 
@@ -106,13 +106,13 @@ class ReferenceHelper
      */
      */
     public static function cellReverseSort($a, $b)
     public static function cellReverseSort($a, $b)
     {
     {
-        $ac = $bc = '';
-        $ar = $br = 0;
-
-        sscanf($a, '%[A-Z]%d', $ac, $ar);
-        sscanf($b, '%[A-Z]%d', $bc, $br);
+        // TODO Scrutinizer doesn't like sscanf($a, '%[A-Z]%d', $ac, $ar), and we can't use short list() syntax
+        //      [$ac, $ar] = sscanf($a, '%[A-Z]%d') while retaining PHP 5.6 support.
+        //      Switch when we drop support for 5.6
+        list($ac, $ar) = sscanf($a, '%[A-Z]%d');
+        list($bc, $br) = sscanf($b, '%[A-Z]%d');
 
 
-        if ($ar == $br) {
+        if ($ar === $br) {
             return 1 - strcasecmp(strlen($ac) . $ac, strlen($bc) . $bc);
             return 1 - strcasecmp(strlen($ac) . $ac, strlen($bc) . $bc);
         }
         }
 
 
@@ -625,7 +625,7 @@ class ReferenceHelper
      * Update references within formulas.
      * Update references within formulas.
      *
      *
      * @param string $pFormula Formula to update
      * @param string $pFormula Formula to update
-     * @param int $pBefore Insert before this one
+     * @param string $pBefore Insert before this one
      * @param int $pNumCols Number of columns to insert
      * @param int $pNumCols Number of columns to insert
      * @param int $pNumRows Number of rows to insert
      * @param int $pNumRows Number of rows to insert
      * @param string $sheetName Worksheet name/title
      * @param string $sheetName Worksheet name/title

+ 42 - 0
htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Settings.php

@@ -24,6 +24,20 @@ class Settings
      */
      */
     private static $libXmlLoaderOptions = null;
     private static $libXmlLoaderOptions = null;
 
 
+    /**
+     * Allow/disallow libxml_disable_entity_loader() call when not thread safe.
+     * Default behaviour is to do the check, but if you're running PHP versions
+     *      7.2 < 7.2.1
+     *      7.1 < 7.1.13
+     *      7.0 < 7.0.27
+     *      5.6 ANY
+     * then you may need to disable this check to prevent unwanted behaviour in other threads
+     * SECURITY WARNING: Changing this flag is not recommended.
+     *
+     * @var bool
+     */
+    private static $libXmlDisableEntityLoader = true;
+
     /**
     /**
      * The cache implementation to be used for cell collection.
      * The cache implementation to be used for cell collection.
      *
      *
@@ -101,6 +115,34 @@ class Settings
         return self::$libXmlLoaderOptions;
         return self::$libXmlLoaderOptions;
     }
     }
 
 
+    /**
+     * Enable/Disable the entity loader for libxml loader.
+     * Allow/disallow libxml_disable_entity_loader() call when not thread safe.
+     * Default behaviour is to do the check, but if you're running PHP versions
+     *      7.2 < 7.2.1
+     *      7.1 < 7.1.13
+     *      7.0 < 7.0.27
+     *      5.6 ANY
+     * then you may need to disable this check to prevent unwanted behaviour in other threads
+     * SECURITY WARNING: Changing this flag to false is not recommended.
+     *
+     * @param bool $state
+     */
+    public static function setLibXmlDisableEntityLoader($state)
+    {
+        self::$libXmlDisableEntityLoader = (bool) $state;
+    }
+
+    /**
+     * Return the state of the entity loader (disabled/enabled) for libxml loader.
+     *
+     * @return bool $state
+     */
+    public static function getLibXmlDisableEntityLoader()
+    {
+        return self::$libXmlDisableEntityLoader;
+    }
+
     /**
     /**
      * Sets the implementation of cache that should be used for cell collection.
      * Sets the implementation of cache that should be used for cell collection.
      *
      *

+ 13 - 12
htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Shared/Date.php

@@ -192,7 +192,7 @@ class Date
         $interval = $days . ' days';
         $interval = $days . ' days';
 
 
         return $baseDate->modify($interval)
         return $baseDate->modify($interval)
-            ->setTime($hours, $minutes, $seconds);
+            ->setTime((int) $hours, (int) $minutes, (int) $seconds);
     }
     }
 
 
     /**
     /**
@@ -244,12 +244,12 @@ class Date
     public static function dateTimeToExcel(DateTimeInterface $dateValue)
     public static function dateTimeToExcel(DateTimeInterface $dateValue)
     {
     {
         return self::formattedPHPToExcel(
         return self::formattedPHPToExcel(
-            $dateValue->format('Y'),
-            $dateValue->format('m'),
-            $dateValue->format('d'),
-            $dateValue->format('H'),
-            $dateValue->format('i'),
-            $dateValue->format('s')
+            (int) $dateValue->format('Y'),
+            (int) $dateValue->format('m'),
+            (int) $dateValue->format('d'),
+            (int) $dateValue->format('H'),
+            (int) $dateValue->format('i'),
+            (int) $dateValue->format('s')
         );
         );
     }
     }
 
 
@@ -325,11 +325,12 @@ class Date
      */
      */
     public static function isDateTime(Cell $pCell)
     public static function isDateTime(Cell $pCell)
     {
     {
-        return self::isDateTimeFormat(
-            $pCell->getWorksheet()->getStyle(
-                $pCell->getCoordinate()
-            )->getNumberFormat()
-        );
+        return is_numeric($pCell->getValue()) &&
+            self::isDateTimeFormat(
+                $pCell->getWorksheet()->getStyle(
+                    $pCell->getCoordinate()
+                )->getNumberFormat()
+            );
     }
     }
 
 
     /**
     /**

+ 21 - 15
htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Shared/OLE.php

@@ -537,31 +537,37 @@ class OLE
     /**
     /**
      * Returns a timestamp from an OLE container's date.
      * Returns a timestamp from an OLE container's date.
      *
      *
-     * @param int $string A binary string with the encoded date
+     * @param string $oleTimestamp A binary string with the encoded date
      *
      *
-     * @return string The timestamp corresponding to the string
+     * @throws ReaderException
+     *
+     * @return int The Unix timestamp corresponding to the string
      */
      */
-    public static function OLE2LocalDate($string)
+    public static function OLE2LocalDate($oleTimestamp)
     {
     {
-        if (strlen($string) != 8) {
+        if (strlen($oleTimestamp) != 8) {
             throw new ReaderException('Expecting 8 byte string');
             throw new ReaderException('Expecting 8 byte string');
         }
         }
 
 
-        // factor used for separating numbers into 4 bytes parts
-        $factor = pow(2, 32);
-        list(, $high_part) = unpack('V', substr($string, 4, 4));
-        list(, $low_part) = unpack('V', substr($string, 0, 4));
+        // convert to units of 100 ns since 1601:
+        $unpackedTimestamp = unpack('v4', $oleTimestamp);
+        $timestampHigh = (float) $unpackedTimestamp[4] * 65536 + (float) $unpackedTimestamp[3];
+        $timestampLow = (float) $unpackedTimestamp[2] * 65536 + (float) $unpackedTimestamp[1];
 
 
-        $big_date = ($high_part * $factor) + $low_part;
-        // translate to seconds
-        $big_date /= 10000000;
+        // translate to seconds since 1601:
+        $timestampHigh /= 10000000;
+        $timestampLow /= 10000000;
 
 
-        // days from 1-1-1601 until the beggining of UNIX era
+        // days from 1601 to 1970:
         $days = 134774;
         $days = 134774;
 
 
-        // translate to seconds from beggining of UNIX era
-        $big_date -= $days * 24 * 3600;
+        // translate to seconds since 1970:
+        $unixTimestamp = floor(65536.0 * 65536.0 * $timestampHigh + $timestampLow - $days * 24 * 3600 + 0.5);
+
+        if ((int) $unixTimestamp == $unixTimestamp) {
+            return (int) $unixTimestamp;
+        }
 
 
-        return floor($big_date);
+        return $unixTimestamp >= 0.0 ? PHP_INT_MAX : PHP_INT_MIN;
     }
     }
 }
 }

+ 3 - 1
htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Shared/Trend/ExponentialBestFit.php

@@ -113,7 +113,9 @@ class ExponentialBestFit extends BestFit
      */
      */
     public function __construct($yValues, $xValues = [], $const = true)
     public function __construct($yValues, $xValues = [], $const = true)
     {
     {
-        if (parent::__construct($yValues, $xValues) !== false) {
+        parent::__construct($yValues, $xValues);
+
+        if (!$this->error) {
             $this->exponentialRegression($yValues, $xValues, $const);
             $this->exponentialRegression($yValues, $xValues, $const);
         }
         }
     }
     }

+ 3 - 1
htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Shared/Trend/LinearBestFit.php

@@ -72,7 +72,9 @@ class LinearBestFit extends BestFit
      */
      */
     public function __construct($yValues, $xValues = [], $const = true)
     public function __construct($yValues, $xValues = [], $const = true)
     {
     {
-        if (parent::__construct($yValues, $xValues) !== false) {
+        parent::__construct($yValues, $xValues);
+
+        if (!$this->error) {
             $this->linearRegression($yValues, $xValues, $const);
             $this->linearRegression($yValues, $xValues, $const);
         }
         }
     }
     }

+ 3 - 1
htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Shared/Trend/LogarithmicBestFit.php

@@ -81,7 +81,9 @@ class LogarithmicBestFit extends BestFit
      */
      */
     public function __construct($yValues, $xValues = [], $const = true)
     public function __construct($yValues, $xValues = [], $const = true)
     {
     {
-        if (parent::__construct($yValues, $xValues) !== false) {
+        parent::__construct($yValues, $xValues);
+
+        if (!$this->error) {
             $this->logarithmicRegression($yValues, $xValues, $const);
             $this->logarithmicRegression($yValues, $xValues, $const);
         }
         }
     }
     }

+ 3 - 1
htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Shared/Trend/PolynomialBestFit.php

@@ -182,7 +182,9 @@ class PolynomialBestFit extends BestFit
      */
      */
     public function __construct($order, $yValues, $xValues = [], $const = true)
     public function __construct($order, $yValues, $xValues = [], $const = true)
     {
     {
-        if (parent::__construct($yValues, $xValues) !== false) {
+        parent::__construct($yValues, $xValues);
+
+        if (!$this->error) {
             if ($order < $this->valueCount) {
             if ($order < $this->valueCount) {
                 $this->bestFitType .= '_' . $order;
                 $this->bestFitType .= '_' . $order;
                 $this->order = $order;
                 $this->order = $order;

+ 3 - 1
htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Shared/Trend/PowerBestFit.php

@@ -105,7 +105,9 @@ class PowerBestFit extends BestFit
      */
      */
     public function __construct($yValues, $xValues = [], $const = true)
     public function __construct($yValues, $xValues = [], $const = true)
     {
     {
-        if (parent::__construct($yValues, $xValues) !== false) {
+        parent::__construct($yValues, $xValues);
+
+        if (!$this->error) {
             $this->powerRegression($yValues, $xValues, $const);
             $this->powerRegression($yValues, $xValues, $const);
         }
         }
     }
     }

+ 1 - 1
htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Spreadsheet.php

@@ -715,7 +715,7 @@ class Spreadsheet
      *
      *
      * @param string $pName Sheet name
      * @param string $pName Sheet name
      *
      *
-     * @return Worksheet
+     * @return null|Worksheet
      */
      */
     public function getSheetByName($pName)
     public function getSheetByName($pName)
     {
     {

+ 19 - 1
htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/NumberFormat.php

@@ -49,6 +49,8 @@ class NumberFormat extends Supervisor
     const FORMAT_CURRENCY_USD = '$#,##0_-';
     const FORMAT_CURRENCY_USD = '$#,##0_-';
     const FORMAT_CURRENCY_EUR_SIMPLE = '#,##0.00_-"€"';
     const FORMAT_CURRENCY_EUR_SIMPLE = '#,##0.00_-"€"';
     const FORMAT_CURRENCY_EUR = '#,##0_-"€"';
     const FORMAT_CURRENCY_EUR = '#,##0_-"€"';
+    const FORMAT_ACCOUNTING_USD = '_("$"* #,##0.00_);_("$"* \(#,##0.00\);_("$"* "-"??_);_(@_)';
+    const FORMAT_ACCOUNTING_EUR = '_("€"* #,##0.00_);_("€"* \(#,##0.00\);_("€"* "-"??_);_(@_)';
 
 
     /**
     /**
      * Excel built-in number formats.
      * Excel built-in number formats.
@@ -308,6 +310,22 @@ class NumberFormat extends Supervisor
             self::$builtInFormats[69] = 't# ?/?';
             self::$builtInFormats[69] = 't# ?/?';
             self::$builtInFormats[70] = 't# ??/??';
             self::$builtInFormats[70] = 't# ??/??';
 
 
+            // JPN
+            self::$builtInFormats[28] = '[$-411]ggge"年"m"月"d"日"';
+            self::$builtInFormats[29] = '[$-411]ggge"年"m"月"d"日"';
+            self::$builtInFormats[31] = 'yyyy"年"m"月"d"日"';
+            self::$builtInFormats[32] = 'h"時"mm"分"';
+            self::$builtInFormats[33] = 'h"時"mm"分"ss"秒"';
+            self::$builtInFormats[34] = 'yyyy"年"m"月"';
+            self::$builtInFormats[35] = 'm"月"d"日"';
+            self::$builtInFormats[51] = '[$-411]ggge"年"m"月"d"日"';
+            self::$builtInFormats[52] = 'yyyy"年"m"月"';
+            self::$builtInFormats[53] = 'm"月"d"日"';
+            self::$builtInFormats[54] = '[$-411]ggge"年"m"月"d"日"';
+            self::$builtInFormats[55] = 'yyyy"年"m"月"';
+            self::$builtInFormats[56] = 'm"月"d"日"';
+            self::$builtInFormats[58] = '[$-411]ggge"年"m"月"d"日"';
+
             // Flip array (for faster lookups)
             // Flip array (for faster lookups)
             self::$flippedBuiltInFormats = array_flip(self::$builtInFormats);
             self::$flippedBuiltInFormats = array_flip(self::$builtInFormats);
         }
         }
@@ -596,7 +614,7 @@ class NumberFormat extends Supervisor
         }
         }
 
 
         // Convert any other escaped characters to quoted strings, e.g. (\T to "T")
         // Convert any other escaped characters to quoted strings, e.g. (\T to "T")
-        $format = preg_replace('/(\\\([^ ]))(?=(?:[^"]|"[^"]*")*$)/u', '"${2}"', $format);
+        $format = preg_replace('/(\\\(((.)(?!((AM\/PM)|(A\/P))))|([^ ])))(?=(?:[^"]|"[^"]*")*$)/u', '"${2}"', $format);
 
 
         // Get the sections, there can be up to four sections, separated with a semi-colon (but only if not a quoted literal)
         // Get the sections, there can be up to four sections, separated with a semi-colon (but only if not a quoted literal)
         $sections = preg_split('/(;)(?=(?:[^"]|"[^"]*")*$)/u', $format);
         $sections = preg_split('/(;)(?=(?:[^"]|"[^"]*")*$)/u', $format);

+ 2 - 2
htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Worksheet/Dimension.php

@@ -64,7 +64,7 @@ abstract class Dimension
      */
      */
     public function setVisible($pValue)
     public function setVisible($pValue)
     {
     {
-        $this->visible = $pValue;
+        $this->visible = (bool) $pValue;
 
 
         return $this;
         return $this;
     }
     }
@@ -119,7 +119,7 @@ abstract class Dimension
      */
      */
     public function setCollapsed($pValue)
     public function setCollapsed($pValue)
     {
     {
-        $this->collapsed = $pValue;
+        $this->collapsed = (bool) $pValue;
 
 
         return $this;
         return $this;
     }
     }

+ 10 - 0
htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Worksheet/RowCellIterator.php

@@ -170,6 +170,16 @@ class RowCellIterator extends CellIterator
         return $this->currentColumnIndex <= $this->endColumnIndex && $this->currentColumnIndex >= $this->startColumnIndex;
         return $this->currentColumnIndex <= $this->endColumnIndex && $this->currentColumnIndex >= $this->startColumnIndex;
     }
     }
 
 
+    /**
+     * Return the current iterator position.
+     *
+     * @return int
+     */
+    public function getCurrentColumnIndex()
+    {
+        return $this->currentColumnIndex;
+    }
+
     /**
     /**
      * Validate start/end values for "IterateOnlyExistingCells" mode, and adjust if necessary.
      * Validate start/end values for "IterateOnlyExistingCells" mode, and adjust if necessary.
      *
      *

+ 2 - 2
htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Worksheet/Worksheet.php

@@ -1096,7 +1096,7 @@ class Worksheet implements IComparable
      * @param string $column Return the highest data row for the specified column,
      * @param string $column Return the highest data row for the specified column,
      *                                     or the highest data row of any column if no column letter is passed
      *                                     or the highest data row of any column if no column letter is passed
      *
      *
-     * @return string Highest row number that contains data
+     * @return int Highest row number that contains data
      */
      */
     public function getHighestDataRow($column = null)
     public function getHighestDataRow($column = null)
     {
     {
@@ -2064,7 +2064,7 @@ class Worksheet implements IComparable
     /**
     /**
      * Insert a new column, updating all possible related data.
      * Insert a new column, updating all possible related data.
      *
      *
-     * @param int $pBefore Insert before this one, eg: 'A'
+     * @param string $pBefore Insert before this one, eg: 'A'
      * @param int $pNumCols Number of columns to insert
      * @param int $pNumCols Number of columns to insert
      *
      *
      * @throws Exception
      * @throws Exception

+ 0 - 55
htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/BaseWriter.php

@@ -35,27 +35,11 @@ abstract class BaseWriter implements IWriter
      */
      */
     private $diskCachingDirectory = './';
     private $diskCachingDirectory = './';
 
 
-    /**
-     * Write charts in workbook?
-     *        If this is true, then the Writer will write definitions for any charts that exist in the PhpSpreadsheet object.
-     *        If false (the default) it will ignore any charts defined in the PhpSpreadsheet object.
-     *
-     * @return bool
-     */
     public function getIncludeCharts()
     public function getIncludeCharts()
     {
     {
         return $this->includeCharts;
         return $this->includeCharts;
     }
     }
 
 
-    /**
-     * Set write charts in workbook
-     *        Set to true, to advise the Writer to include any charts that exist in the PhpSpreadsheet object.
-     *        Set to false (the default) to ignore charts.
-     *
-     * @param bool $pValue
-     *
-     * @return IWriter
-     */
     public function setIncludeCharts($pValue)
     public function setIncludeCharts($pValue)
     {
     {
         $this->includeCharts = (bool) $pValue;
         $this->includeCharts = (bool) $pValue;
@@ -63,30 +47,11 @@ abstract class BaseWriter implements IWriter
         return $this;
         return $this;
     }
     }
 
 
-    /**
-     * Get Pre-Calculate Formulas flag
-     *     If this is true (the default), then the writer will recalculate all formulae in a workbook when saving,
-     *        so that the pre-calculated values are immediately available to MS Excel or other office spreadsheet
-     *        viewer when opening the file
-     *     If false, then formulae are not calculated on save. This is faster for saving in PhpSpreadsheet, but slower
-     *        when opening the resulting file in MS Excel, because Excel has to recalculate the formulae itself.
-     *
-     * @return bool
-     */
     public function getPreCalculateFormulas()
     public function getPreCalculateFormulas()
     {
     {
         return $this->preCalculateFormulas;
         return $this->preCalculateFormulas;
     }
     }
 
 
-    /**
-     * Set Pre-Calculate Formulas
-     *        Set to true (the default) to advise the Writer to calculate all formulae on save
-     *        Set to false to prevent precalculation of formulae on save.
-     *
-     * @param bool $pValue Pre-Calculate Formulas?
-     *
-     * @return IWriter
-     */
     public function setPreCalculateFormulas($pValue)
     public function setPreCalculateFormulas($pValue)
     {
     {
         $this->preCalculateFormulas = (bool) $pValue;
         $this->preCalculateFormulas = (bool) $pValue;
@@ -94,26 +59,11 @@ abstract class BaseWriter implements IWriter
         return $this;
         return $this;
     }
     }
 
 
-    /**
-     * Get use disk caching where possible?
-     *
-     * @return bool
-     */
     public function getUseDiskCaching()
     public function getUseDiskCaching()
     {
     {
         return $this->useDiskCaching;
         return $this->useDiskCaching;
     }
     }
 
 
-    /**
-     * Set use disk caching where possible?
-     *
-     * @param bool $pValue
-     * @param string $pDirectory Disk caching directory
-     *
-     * @throws Exception when directory does not exist
-     *
-     * @return IWriter
-     */
     public function setUseDiskCaching($pValue, $pDirectory = null)
     public function setUseDiskCaching($pValue, $pDirectory = null)
     {
     {
         $this->useDiskCaching = $pValue;
         $this->useDiskCaching = $pValue;
@@ -129,11 +79,6 @@ abstract class BaseWriter implements IWriter
         return $this;
         return $this;
     }
     }
 
 
-    /**
-     * Get disk caching directory.
-     *
-     * @return string
-     */
     public function getDiskCachingDirectory()
     public function getDiskCachingDirectory()
     {
     {
         return $this->diskCachingDirectory;
         return $this->diskCachingDirectory;

+ 69 - 0
htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/IWriter.php

@@ -13,6 +13,49 @@ interface IWriter
      */
      */
     public function __construct(Spreadsheet $spreadsheet);
     public function __construct(Spreadsheet $spreadsheet);
 
 
+    /**
+     * Write charts in workbook?
+     *        If this is true, then the Writer will write definitions for any charts that exist in the PhpSpreadsheet object.
+     *        If false (the default) it will ignore any charts defined in the PhpSpreadsheet object.
+     *
+     * @return bool
+     */
+    public function getIncludeCharts();
+
+    /**
+     * Set write charts in workbook
+     *        Set to true, to advise the Writer to include any charts that exist in the PhpSpreadsheet object.
+     *        Set to false (the default) to ignore charts.
+     *
+     * @param bool $pValue
+     *
+     * @return IWriter
+     */
+    public function setIncludeCharts($pValue);
+
+    /**
+     * Get Pre-Calculate Formulas flag
+     *     If this is true (the default), then the writer will recalculate all formulae in a workbook when saving,
+     *        so that the pre-calculated values are immediately available to MS Excel or other office spreadsheet
+     *        viewer when opening the file
+     *     If false, then formulae are not calculated on save. This is faster for saving in PhpSpreadsheet, but slower
+     *        when opening the resulting file in MS Excel, because Excel has to recalculate the formulae itself.
+     *
+     * @return bool
+     */
+    public function getPreCalculateFormulas();
+
+    /**
+     * Set Pre-Calculate Formulas
+     *        Set to true (the default) to advise the Writer to calculate all formulae on save
+     *        Set to false to prevent precalculation of formulae on save.
+     *
+     * @param bool $pValue Pre-Calculate Formulas?
+     *
+     * @return IWriter
+     */
+    public function setPreCalculateFormulas($pValue);
+
     /**
     /**
      * Save PhpSpreadsheet to file.
      * Save PhpSpreadsheet to file.
      *
      *
@@ -21,4 +64,30 @@ interface IWriter
      * @throws \PhpOffice\PhpSpreadsheet\Writer\Exception
      * @throws \PhpOffice\PhpSpreadsheet\Writer\Exception
      */
      */
     public function save($pFilename);
     public function save($pFilename);
+
+    /**
+     * Get use disk caching where possible?
+     *
+     * @return bool
+     */
+    public function getUseDiskCaching();
+
+    /**
+     * Set use disk caching where possible?
+     *
+     * @param bool $pValue
+     * @param string $pDirectory Disk caching directory
+     *
+     * @throws Exception when directory does not exist
+     *
+     * @return IWriter
+     */
+    public function setUseDiskCaching($pValue, $pDirectory = null);
+
+    /**
+     * Get disk caching directory.
+     *
+     * @return string
+     */
+    public function getDiskCachingDirectory();
 }
 }

+ 16 - 17
htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Xls/Parser.php

@@ -1009,7 +1009,7 @@ class Parser
 
 
                 break;
                 break;
             case '>':
             case '>':
-                if ($this->lookAhead == '=') { // it's a GE token
+                if ($this->lookAhead === '=') { // it's a GE token
                     break;
                     break;
                 }
                 }
 
 
@@ -1018,7 +1018,7 @@ class Parser
                 break;
                 break;
             case '<':
             case '<':
                 // it's a LE or a NE token
                 // it's a LE or a NE token
-                if (($this->lookAhead == '=') or ($this->lookAhead == '>')) {
+                if (($this->lookAhead === '=') or ($this->lookAhead === '>')) {
                     break;
                     break;
                 }
                 }
 
 
@@ -1027,12 +1027,12 @@ class Parser
                 break;
                 break;
             default:
             default:
                 // if it's a reference A1 or $A$1 or $A1 or A$1
                 // if it's a reference A1 or $A$1 or $A1 or A$1
-                if (preg_match('/^\$?[A-Ia-i]?[A-Za-z]\$?\d+$/', $token) and !preg_match('/\d/', $this->lookAhead) and ($this->lookAhead != ':') and ($this->lookAhead != '.') and ($this->lookAhead != '!')) {
+                if (preg_match('/^\$?[A-Ia-i]?[A-Za-z]\$?\d+$/', $token) and !preg_match('/\d/', $this->lookAhead) and ($this->lookAhead !== ':') and ($this->lookAhead !== '.') and ($this->lookAhead !== '!')) {
                     return $token;
                     return $token;
-                } elseif (preg_match('/^' . self::REGEX_SHEET_TITLE_UNQUOTED . '(\\:' . self::REGEX_SHEET_TITLE_UNQUOTED . ')?\\!\$?[A-Ia-i]?[A-Za-z]\$?\\d+$/u', $token) and !preg_match('/\d/', $this->lookAhead) and ($this->lookAhead != ':') and ($this->lookAhead != '.')) {
+                } elseif (preg_match('/^' . self::REGEX_SHEET_TITLE_UNQUOTED . '(\\:' . self::REGEX_SHEET_TITLE_UNQUOTED . ')?\\!\$?[A-Ia-i]?[A-Za-z]\$?\\d+$/u', $token) and !preg_match('/\d/', $this->lookAhead) and ($this->lookAhead !== ':') and ($this->lookAhead !== '.')) {
                     // If it's an external reference (Sheet1!A1 or Sheet1:Sheet2!A1 or Sheet1!$A$1 or Sheet1:Sheet2!$A$1)
                     // If it's an external reference (Sheet1!A1 or Sheet1:Sheet2!A1 or Sheet1!$A$1 or Sheet1:Sheet2!$A$1)
                     return $token;
                     return $token;
-                } elseif (preg_match("/^'" . self::REGEX_SHEET_TITLE_QUOTED . '(\\:' . self::REGEX_SHEET_TITLE_QUOTED . ")?'\\!\\$?[A-Ia-i]?[A-Za-z]\\$?\\d+$/u", $token) and !preg_match('/\d/', $this->lookAhead) and ($this->lookAhead != ':') and ($this->lookAhead != '.')) {
+                } elseif (preg_match("/^'" . self::REGEX_SHEET_TITLE_QUOTED . '(\\:' . self::REGEX_SHEET_TITLE_QUOTED . ")?'\\!\\$?[A-Ia-i]?[A-Za-z]\\$?\\d+$/u", $token) and !preg_match('/\d/', $this->lookAhead) and ($this->lookAhead !== ':') and ($this->lookAhead !== '.')) {
                     // If it's an external reference ('Sheet1'!A1 or 'Sheet1:Sheet2'!A1 or 'Sheet1'!$A$1 or 'Sheet1:Sheet2'!$A$1)
                     // If it's an external reference ('Sheet1'!A1 or 'Sheet1:Sheet2'!A1 or 'Sheet1'!$A$1 or 'Sheet1:Sheet2'!$A$1)
                     return $token;
                     return $token;
                 } elseif (preg_match('/^(\$)?[A-Ia-i]?[A-Za-z](\$)?\d+:(\$)?[A-Ia-i]?[A-Za-z](\$)?\d+$/', $token) && !preg_match('/\d/', $this->lookAhead)) {
                 } elseif (preg_match('/^(\$)?[A-Ia-i]?[A-Za-z](\$)?\d+:(\$)?[A-Ia-i]?[A-Za-z](\$)?\d+$/', $token) && !preg_match('/\d/', $this->lookAhead)) {
@@ -1044,19 +1044,19 @@ class Parser
                 } elseif (preg_match("/^'" . self::REGEX_SHEET_TITLE_QUOTED . '(\\:' . self::REGEX_SHEET_TITLE_QUOTED . ")?'\\!\\$?([A-Ia-i]?[A-Za-z])?\\$?\\d+:\\$?([A-Ia-i]?[A-Za-z])?\\$?\\d+$/u", $token) and !preg_match('/\d/', $this->lookAhead)) {
                 } elseif (preg_match("/^'" . self::REGEX_SHEET_TITLE_QUOTED . '(\\:' . self::REGEX_SHEET_TITLE_QUOTED . ")?'\\!\\$?([A-Ia-i]?[A-Za-z])?\\$?\\d+:\\$?([A-Ia-i]?[A-Za-z])?\\$?\\d+$/u", $token) and !preg_match('/\d/', $this->lookAhead)) {
                     // If it's an external range like 'Sheet1'!A1:B2 or 'Sheet1:Sheet2'!A1:B2 or 'Sheet1'!$A$1:$B$2 or 'Sheet1:Sheet2'!$A$1:$B$2
                     // If it's an external range like 'Sheet1'!A1:B2 or 'Sheet1:Sheet2'!A1:B2 or 'Sheet1'!$A$1:$B$2 or 'Sheet1:Sheet2'!$A$1:$B$2
                     return $token;
                     return $token;
-                } elseif (is_numeric($token) and (!is_numeric($token . $this->lookAhead) or ($this->lookAhead == '')) and ($this->lookAhead != '!') and ($this->lookAhead != ':')) {
+                } elseif (is_numeric($token) and (!is_numeric($token . $this->lookAhead) or ($this->lookAhead == '')) and ($this->lookAhead !== '!') and ($this->lookAhead !== ':')) {
                     // If it's a number (check that it's not a sheet name or range)
                     // If it's a number (check that it's not a sheet name or range)
                     return $token;
                     return $token;
-                } elseif (preg_match('/"([^"]|""){0,255}"/', $token) and $this->lookAhead != '"' and (substr_count($token, '"') % 2 == 0)) {
+                } elseif (preg_match('/"([^"]|""){0,255}"/', $token) and $this->lookAhead !== '"' and (substr_count($token, '"') % 2 == 0)) {
                     // If it's a string (of maximum 255 characters)
                     // If it's a string (of maximum 255 characters)
                     return $token;
                     return $token;
-                } elseif (preg_match('/^#[A-Z0\\/]{3,5}[!?]{1}$/', $token) or $token == '#N/A') {
+                } elseif (preg_match('/^#[A-Z0\\/]{3,5}[!?]{1}$/', $token) or $token === '#N/A') {
                     // If it's an error code
                     // If it's an error code
                     return $token;
                     return $token;
-                } elseif (preg_match("/^[A-Z0-9\xc0-\xdc\\.]+$/i", $token) and ($this->lookAhead == '(')) {
+                } elseif (preg_match("/^[A-Z0-9\xc0-\xdc\\.]+$/i", $token) and ($this->lookAhead === '(')) {
                     // if it's a function call
                     // if it's a function call
                     return $token;
                     return $token;
-                } elseif (substr($token, -1) == ')') {
+                } elseif (substr($token, -1) === ')') {
                     //    It's an argument of some description (e.g. a named range),
                     //    It's an argument of some description (e.g. a named range),
                     //        precise nature yet to be determined
                     //        precise nature yet to be determined
                     return $token;
                     return $token;
@@ -1078,8 +1078,7 @@ class Parser
     {
     {
         $this->currentCharacter = 0;
         $this->currentCharacter = 0;
         $this->formula = $formula;
         $this->formula = $formula;
-        $this->lookAhead = isset($formula[1]) ? $formula[1]
-        : '';
+        $this->lookAhead = isset($formula[1]) ? $formula[1] : '';
         $this->advance();
         $this->advance();
         $this->parseTree = $this->condition();
         $this->parseTree = $this->condition();
 
 
@@ -1248,10 +1247,10 @@ class Parser
      */
      */
     private function fact()
     private function fact()
     {
     {
-        if ($this->currentToken == '(') {
+        if ($this->currentToken === '(') {
             $this->advance(); // eat the "("
             $this->advance(); // eat the "("
             $result = $this->parenthesizedExpression();
             $result = $this->parenthesizedExpression();
-            if ($this->currentToken != ')') {
+            if ($this->currentToken !== ')') {
                 throw new WriterException("')' token expected.");
                 throw new WriterException("')' token expected.");
             }
             }
             $this->advance(); // eat the ")"
             $this->advance(); // eat the ")"
@@ -1299,7 +1298,7 @@ class Parser
             return $result;
             return $result;
         } elseif (is_numeric($this->currentToken)) {
         } elseif (is_numeric($this->currentToken)) {
             // If it's a number or a percent
             // If it's a number or a percent
-            if ($this->lookAhead == '%') {
+            if ($this->lookAhead === '%') {
                 $result = $this->createTree('ptgPercent', $this->currentToken, '');
                 $result = $this->createTree('ptgPercent', $this->currentToken, '');
                 $this->advance(); // Skip the percentage operator once we've pre-built that tree
                 $this->advance(); // Skip the percentage operator once we've pre-built that tree
             } else {
             } else {
@@ -1331,9 +1330,9 @@ class Parser
         $result = ''; // initialize result
         $result = ''; // initialize result
         $this->advance();
         $this->advance();
         $this->advance(); // eat the "("
         $this->advance(); // eat the "("
-        while ($this->currentToken != ')') {
+        while ($this->currentToken !== ')') {
             if ($num_args > 0) {
             if ($num_args > 0) {
-                if ($this->currentToken == ',' || $this->currentToken == ';') {
+                if ($this->currentToken === ',' || $this->currentToken === ';') {
                     $this->advance(); // eat the "," or ";"
                     $this->advance(); // eat the "," or ";"
                 } else {
                 } else {
                     throw new WriterException("Syntax error: comma expected in function $function, arg #{$num_args}");
                     throw new WriterException("Syntax error: comma expected in function $function, arg #{$num_args}");

+ 4 - 6
htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Xls/Workbook.php

@@ -267,9 +267,7 @@ class Workbook extends BIFFwriter
 
 
         $this->xfWriters[] = $xfWriter;
         $this->xfWriters[] = $xfWriter;
 
 
-        $xfIndex = count($this->xfWriters) - 1;
-
-        return $xfIndex;
+        return count($this->xfWriters) - 1;
     }
     }
 
 
     /**
     /**
@@ -319,7 +317,7 @@ class Workbook extends BIFFwriter
             if ($colorIndex) {
             if ($colorIndex) {
                 $this->colors[$rgb] = $colorIndex;
                 $this->colors[$rgb] = $colorIndex;
             } else {
             } else {
-                if (count($this->colors) == 0) {
+                if (count($this->colors) === 0) {
                     $lastColor = 7;
                     $lastColor = 7;
                 } else {
                 } else {
                     $lastColor = end($this->colors);
                     $lastColor = end($this->colors);
@@ -437,7 +435,7 @@ class Workbook extends BIFFwriter
 
 
         // Prepare part 3 of the workbook global stream, what goes after the SHEET records
         // Prepare part 3 of the workbook global stream, what goes after the SHEET records
         $part3 = '';
         $part3 = '';
-        if ($this->countryCode != -1) {
+        if ($this->countryCode !== -1) {
             $part3 .= $this->writeCountry();
             $part3 .= $this->writeCountry();
         }
         }
         $part3 .= $this->writeRecalcId();
         $part3 .= $this->writeRecalcId();
@@ -918,7 +916,7 @@ class Workbook extends BIFFwriter
         $record = 0x0022; // Record identifier
         $record = 0x0022; // Record identifier
         $length = 0x0002; // Bytes to follow
         $length = 0x0002; // Bytes to follow
 
 
-        $f1904 = (Date::getExcelCalendar() == Date::CALENDAR_MAC_1904)
+        $f1904 = (Date::getExcelCalendar() === Date::CALENDAR_MAC_1904)
             ? 1
             ? 1
             : 0; // Flag for 1904 date system
             : 0; // Flag for 1904 date system
 
 

+ 13 - 2
htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Xlsx.php

@@ -328,6 +328,17 @@ class Xlsx extends BaseWriter
                     $zip->addFromString('xl/drawings/drawing' . ($i + 1) . '.xml', $this->getWriterPart('Drawing')->writeDrawings($this->spreadSheet->getSheet($i), $this->includeCharts));
                     $zip->addFromString('xl/drawings/drawing' . ($i + 1) . '.xml', $this->getWriterPart('Drawing')->writeDrawings($this->spreadSheet->getSheet($i), $this->includeCharts));
                 }
                 }
 
 
+                // Add unparsed drawings
+                if (isset($unparsedLoadedData['sheets'][$sheetCodeName]['Drawings'])) {
+                    foreach ($unparsedLoadedData['sheets'][$sheetCodeName]['Drawings'] as $relId => $drawingXml) {
+                        $drawingFile = array_search($relId, $unparsedLoadedData['sheets'][$sheetCodeName]['drawingOriginalIds']);
+                        if ($drawingFile !== false) {
+                            $drawingFile = ltrim($drawingFile, '.');
+                            $zip->addFromString('xl' . $drawingFile, $drawingXml);
+                        }
+                    }
+                }
+
                 // Add comment relationship parts
                 // Add comment relationship parts
                 if (count($this->spreadSheet->getSheet($i)->getComments()) > 0) {
                 if (count($this->spreadSheet->getSheet($i)->getComments()) > 0) {
                     // VML Comments
                     // VML Comments
@@ -338,8 +349,8 @@ class Xlsx extends BaseWriter
                 }
                 }
 
 
                 // Add unparsed relationship parts
                 // Add unparsed relationship parts
-                if (isset($unparsedLoadedData['sheets'][$this->spreadSheet->getSheet($i)->getCodeName()]['vmlDrawings'])) {
-                    foreach ($unparsedLoadedData['sheets'][$this->spreadSheet->getSheet($i)->getCodeName()]['vmlDrawings'] as $vmlDrawing) {
+                if (isset($unparsedLoadedData['sheets'][$sheetCodeName]['vmlDrawings'])) {
+                    foreach ($unparsedLoadedData['sheets'][$sheetCodeName]['vmlDrawings'] as $vmlDrawing) {
                         $zip->addFromString($vmlDrawing['filePath'], $vmlDrawing['content']);
                         $zip->addFromString($vmlDrawing['filePath'], $vmlDrawing['content']);
                     }
                     }
                 }
                 }

+ 2 - 2
htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Xlsx/Workbook.php

@@ -93,7 +93,7 @@ class Workbook extends WriterPart
     {
     {
         $objWriter->startElement('workbookPr');
         $objWriter->startElement('workbookPr');
 
 
-        if (Date::getExcelCalendar() == Date::CALENDAR_MAC_1904) {
+        if (Date::getExcelCalendar() === Date::CALENDAR_MAC_1904) {
             $objWriter->writeAttribute('date1904', '1');
             $objWriter->writeAttribute('date1904', '1');
         }
         }
 
 
@@ -225,7 +225,7 @@ class Workbook extends WriterPart
             $objWriter->startElement('sheet');
             $objWriter->startElement('sheet');
             $objWriter->writeAttribute('name', $pSheetname);
             $objWriter->writeAttribute('name', $pSheetname);
             $objWriter->writeAttribute('sheetId', $pSheetId);
             $objWriter->writeAttribute('sheetId', $pSheetId);
-            if ($sheetState != 'visible' && $sheetState != '') {
+            if ($sheetState !== 'visible' && $sheetState != '') {
                 $objWriter->writeAttribute('state', $sheetState);
                 $objWriter->writeAttribute('state', $sheetState);
             }
             }
             $objWriter->writeAttribute('r:id', 'rId' . $pRelId);
             $objWriter->writeAttribute('r:id', 'rId' . $pRelId);

+ 15 - 11
htdocs/includes/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php

@@ -141,7 +141,7 @@ class Worksheet extends WriterPart
         $objWriter->startElement('sheetPr');
         $objWriter->startElement('sheetPr');
         if ($pSheet->getParent()->hasMacros()) {
         if ($pSheet->getParent()->hasMacros()) {
             //if the workbook have macros, we need to have codeName for the sheet
             //if the workbook have macros, we need to have codeName for the sheet
-            if ($pSheet->hasCodeName() == false) {
+            if (!$pSheet->hasCodeName()) {
                 $pSheet->setCodeName($pSheet->getTitle());
                 $pSheet->setCodeName($pSheet->getTitle());
             }
             }
             $objWriter->writeAttribute('codeName', $pSheet->getCodeName());
             $objWriter->writeAttribute('codeName', $pSheet->getCodeName());
@@ -322,7 +322,7 @@ class Worksheet extends WriterPart
         }
         }
 
 
         // Set Zero Height row
         // Set Zero Height row
-        if ((string) $pSheet->getDefaultRowDimension()->getZeroHeight() == '1' ||
+        if ((string) $pSheet->getDefaultRowDimension()->getZeroHeight() === '1' ||
             strtolower((string) $pSheet->getDefaultRowDimension()->getZeroHeight()) == 'true') {
             strtolower((string) $pSheet->getDefaultRowDimension()->getZeroHeight()) == 'true') {
             $objWriter->writeAttribute('zeroHeight', '1');
             $objWriter->writeAttribute('zeroHeight', '1');
         }
         }
@@ -383,7 +383,7 @@ class Worksheet extends WriterPart
                 }
                 }
 
 
                 // Column visibility
                 // Column visibility
-                if ($colDimension->getVisible() == false) {
+                if ($colDimension->getVisible() === false) {
                     $objWriter->writeAttribute('hidden', 'true');
                     $objWriter->writeAttribute('hidden', 'true');
                 }
                 }
 
 
@@ -398,7 +398,7 @@ class Worksheet extends WriterPart
                 }
                 }
 
 
                 // Collapsed
                 // Collapsed
-                if ($colDimension->getCollapsed() == true) {
+                if ($colDimension->getCollapsed() === true) {
                     $objWriter->writeAttribute('collapsed', 'true');
                     $objWriter->writeAttribute('collapsed', 'true');
                 }
                 }
 
 
@@ -428,7 +428,7 @@ class Worksheet extends WriterPart
         // sheetProtection
         // sheetProtection
         $objWriter->startElement('sheetProtection');
         $objWriter->startElement('sheetProtection');
 
 
-        if ($pSheet->getProtection()->getPassword() != '') {
+        if ($pSheet->getProtection()->getPassword() !== '') {
             $objWriter->writeAttribute('password', $pSheet->getProtection()->getPassword());
             $objWriter->writeAttribute('password', $pSheet->getProtection()->getPassword());
         }
         }
 
 
@@ -519,6 +519,9 @@ class Worksheet extends WriterPart
                             // Formula
                             // Formula
                             $objWriter->writeElement('formula', $formula);
                             $objWriter->writeElement('formula', $formula);
                         }
                         }
+                    } elseif ($conditional->getConditionType() == Conditional::CONDITION_CONTAINSBLANKS) {
+                        // formula copied from ms xlsx xml source file
+                        $objWriter->writeElement('formula', 'LEN(TRIM(' . $cellCoordinate . '))=0');
                     }
                     }
 
 
                     $objWriter->endElement();
                     $objWriter->endElement();
@@ -624,8 +627,9 @@ class Worksheet extends WriterPart
                     $objWriter->writeAttribute('location', str_replace('sheet://', '', $hyperlink->getUrl()));
                     $objWriter->writeAttribute('location', str_replace('sheet://', '', $hyperlink->getUrl()));
                 }
                 }
 
 
-                if ($hyperlink->getTooltip() != '') {
+                if ($hyperlink->getTooltip() !== '') {
                     $objWriter->writeAttribute('tooltip', $hyperlink->getTooltip());
                     $objWriter->writeAttribute('tooltip', $hyperlink->getTooltip());
+                    $objWriter->writeAttribute('display', $hyperlink->getTooltip());
                 }
                 }
 
 
                 $objWriter->endElement();
                 $objWriter->endElement();
@@ -991,12 +995,12 @@ class Worksheet extends WriterPart
                 }
                 }
 
 
                 // Row visibility
                 // Row visibility
-                if ($rowDimension->getVisible() == false) {
+                if (!$rowDimension->getVisible() === true) {
                     $objWriter->writeAttribute('hidden', 'true');
                     $objWriter->writeAttribute('hidden', 'true');
                 }
                 }
 
 
                 // Collapsed
                 // Collapsed
-                if ($rowDimension->getCollapsed() == true) {
+                if ($rowDimension->getCollapsed() === true) {
                     $objWriter->writeAttribute('collapsed', 'true');
                     $objWriter->writeAttribute('collapsed', 'true');
                 }
                 }
 
 
@@ -1101,7 +1105,7 @@ class Worksheet extends WriterPart
                     break;
                     break;
                 case 'f':            // Formula
                 case 'f':            // Formula
                     $attributes = $pCell->getFormulaAttributes();
                     $attributes = $pCell->getFormulaAttributes();
-                    if ($attributes['t'] == 'array') {
+                    if ($attributes['t'] === 'array') {
                         $objWriter->startElement('f');
                         $objWriter->startElement('f');
                         $objWriter->writeAttribute('t', 'array');
                         $objWriter->writeAttribute('t', 'array');
                         $objWriter->writeAttribute('ref', $pCellAddress);
                         $objWriter->writeAttribute('ref', $pCellAddress);
@@ -1114,7 +1118,7 @@ class Worksheet extends WriterPart
                     }
                     }
                     if ($this->getParentWriter()->getOffice2003Compatibility() === false) {
                     if ($this->getParentWriter()->getOffice2003Compatibility() === false) {
                         if ($this->getParentWriter()->getPreCalculateFormulas()) {
                         if ($this->getParentWriter()->getPreCalculateFormulas()) {
-                            if (!is_array($calculatedValue) && substr($calculatedValue, 0, 1) != '#') {
+                            if (!is_array($calculatedValue) && substr($calculatedValue, 0, 1) !== '#') {
                                 $objWriter->writeElement('v', StringHelper::formatNumber($calculatedValue));
                                 $objWriter->writeElement('v', StringHelper::formatNumber($calculatedValue));
                             } else {
                             } else {
                                 $objWriter->writeElement('v', '0');
                                 $objWriter->writeElement('v', '0');
@@ -1135,7 +1139,7 @@ class Worksheet extends WriterPart
 
 
                     break;
                     break;
                 case 'e':            // Error
                 case 'e':            // Error
-                    if (substr($cellValue, 0, 1) == '=') {
+                    if (substr($cellValue, 0, 1) === '=') {
                         $objWriter->writeElement('f', substr($cellValue, 1));
                         $objWriter->writeElement('f', substr($cellValue, 1));
                         $objWriter->writeElement('v', substr($cellValue, 1));
                         $objWriter->writeElement('v', substr($cellValue, 1));
                     } else {
                     } else {