/home/mip/mip/public/vendor/laravel-filemanager/files/folder-1/821668/phpoffice.zip
PK �8]!��Y7 7 phpspreadsheet/LICENSEnu �[��� MIT License
Copyright (c) 2019 PhpSpreadsheet Authors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
PK �8]Z#3� � 0 phpspreadsheet/src/PhpSpreadsheet/NamedRange.phpnu �[��� <?php
namespace PhpOffice\PhpSpreadsheet;
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
class NamedRange extends DefinedName
{
/**
* Create a new Named Range.
*/
public function __construct(
string $name,
?Worksheet $worksheet = null,
string $range = 'A1',
bool $localOnly = false,
?Worksheet $scope = null
) {
if ($worksheet === null && $scope === null) {
throw new Exception('You must specify a worksheet or a scope for a Named Range');
}
parent::__construct($name, $worksheet, $range, $localOnly, $scope);
}
/**
* Get the range value.
*/
public function getRange(): string
{
return $this->value;
}
/**
* Set the range value.
*/
public function setRange(string $range): self
{
if (!empty($range)) {
$this->value = $range;
}
return $this;
}
public function getCellsInRange(): array
{
$range = $this->value;
if (substr($range, 0, 1) === '=') {
$range = substr($range, 1);
}
return Coordinate::extractAllCellReferencesInRange($range);
}
}
PK �8]زv+ 4 phpspreadsheet/src/PhpSpreadsheet/Helper/Handler.phpnu �[��� <?php
namespace PhpOffice\PhpSpreadsheet\Helper;
class Handler
{
/** @var string */
private static $invalidHex = 'Y';
// A bunch of methods to show that we continue
// to capture messages even using PhpUnit 10.
public static function suppressed(): bool
{
return @trigger_error('hello');
}
public static function deprecated(): string
{
return (string) hexdec(self::$invalidHex);
}
public static function notice(string $value): void
{
date_default_timezone_set($value);
}
public static function warning(): bool
{
return file_get_contents(__FILE__ . 'noexist') !== false;
}
public static function userDeprecated(): bool
{
return trigger_error('hello', E_USER_DEPRECATED);
}
public static function userNotice(): bool
{
return trigger_error('userNotice', E_USER_NOTICE);
}
public static function userWarning(): bool
{
return trigger_error('userWarning', E_USER_WARNING);
}
}
PK �8]3���e �e 1 phpspreadsheet/src/PhpSpreadsheet/Helper/Html.phpnu �[��� <?php
namespace PhpOffice\PhpSpreadsheet\Helper;
use DOMDocument;
use DOMElement;
use DOMNode;
use DOMText;
use PhpOffice\PhpSpreadsheet\RichText\RichText;
use PhpOffice\PhpSpreadsheet\Style\Color;
use PhpOffice\PhpSpreadsheet\Style\Font;
class Html
{
private const COLOUR_MAP = [
'aliceblue' => 'f0f8ff',
'antiquewhite' => 'faebd7',
'antiquewhite1' => 'ffefdb',
'antiquewhite2' => 'eedfcc',
'antiquewhite3' => 'cdc0b0',
'antiquewhite4' => '8b8378',
'aqua' => '00ffff',
'aquamarine1' => '7fffd4',
'aquamarine2' => '76eec6',
'aquamarine4' => '458b74',
'azure1' => 'f0ffff',
'azure2' => 'e0eeee',
'azure3' => 'c1cdcd',
'azure4' => '838b8b',
'beige' => 'f5f5dc',
'bisque1' => 'ffe4c4',
'bisque2' => 'eed5b7',
'bisque3' => 'cdb79e',
'bisque4' => '8b7d6b',
'black' => '000000',
'blanchedalmond' => 'ffebcd',
'blue' => '0000ff',
'blue1' => '0000ff',
'blue2' => '0000ee',
'blue4' => '00008b',
'blueviolet' => '8a2be2',
'brown' => 'a52a2a',
'brown1' => 'ff4040',
'brown2' => 'ee3b3b',
'brown3' => 'cd3333',
'brown4' => '8b2323',
'burlywood' => 'deb887',
'burlywood1' => 'ffd39b',
'burlywood2' => 'eec591',
'burlywood3' => 'cdaa7d',
'burlywood4' => '8b7355',
'cadetblue' => '5f9ea0',
'cadetblue1' => '98f5ff',
'cadetblue2' => '8ee5ee',
'cadetblue3' => '7ac5cd',
'cadetblue4' => '53868b',
'chartreuse1' => '7fff00',
'chartreuse2' => '76ee00',
'chartreuse3' => '66cd00',
'chartreuse4' => '458b00',
'chocolate' => 'd2691e',
'chocolate1' => 'ff7f24',
'chocolate2' => 'ee7621',
'chocolate3' => 'cd661d',
'coral' => 'ff7f50',
'coral1' => 'ff7256',
'coral2' => 'ee6a50',
'coral3' => 'cd5b45',
'coral4' => '8b3e2f',
'cornflowerblue' => '6495ed',
'cornsilk1' => 'fff8dc',
'cornsilk2' => 'eee8cd',
'cornsilk3' => 'cdc8b1',
'cornsilk4' => '8b8878',
'cyan1' => '00ffff',
'cyan2' => '00eeee',
'cyan3' => '00cdcd',
'cyan4' => '008b8b',
'darkgoldenrod' => 'b8860b',
'darkgoldenrod1' => 'ffb90f',
'darkgoldenrod2' => 'eead0e',
'darkgoldenrod3' => 'cd950c',
'darkgoldenrod4' => '8b6508',
'darkgreen' => '006400',
'darkkhaki' => 'bdb76b',
'darkolivegreen' => '556b2f',
'darkolivegreen1' => 'caff70',
'darkolivegreen2' => 'bcee68',
'darkolivegreen3' => 'a2cd5a',
'darkolivegreen4' => '6e8b3d',
'darkorange' => 'ff8c00',
'darkorange1' => 'ff7f00',
'darkorange2' => 'ee7600',
'darkorange3' => 'cd6600',
'darkorange4' => '8b4500',
'darkorchid' => '9932cc',
'darkorchid1' => 'bf3eff',
'darkorchid2' => 'b23aee',
'darkorchid3' => '9a32cd',
'darkorchid4' => '68228b',
'darksalmon' => 'e9967a',
'darkseagreen' => '8fbc8f',
'darkseagreen1' => 'c1ffc1',
'darkseagreen2' => 'b4eeb4',
'darkseagreen3' => '9bcd9b',
'darkseagreen4' => '698b69',
'darkslateblue' => '483d8b',
'darkslategray' => '2f4f4f',
'darkslategray1' => '97ffff',
'darkslategray2' => '8deeee',
'darkslategray3' => '79cdcd',
'darkslategray4' => '528b8b',
'darkturquoise' => '00ced1',
'darkviolet' => '9400d3',
'deeppink1' => 'ff1493',
'deeppink2' => 'ee1289',
'deeppink3' => 'cd1076',
'deeppink4' => '8b0a50',
'deepskyblue1' => '00bfff',
'deepskyblue2' => '00b2ee',
'deepskyblue3' => '009acd',
'deepskyblue4' => '00688b',
'dimgray' => '696969',
'dodgerblue1' => '1e90ff',
'dodgerblue2' => '1c86ee',
'dodgerblue3' => '1874cd',
'dodgerblue4' => '104e8b',
'firebrick' => 'b22222',
'firebrick1' => 'ff3030',
'firebrick2' => 'ee2c2c',
'firebrick3' => 'cd2626',
'firebrick4' => '8b1a1a',
'floralwhite' => 'fffaf0',
'forestgreen' => '228b22',
'fuchsia' => 'ff00ff',
'gainsboro' => 'dcdcdc',
'ghostwhite' => 'f8f8ff',
'gold1' => 'ffd700',
'gold2' => 'eec900',
'gold3' => 'cdad00',
'gold4' => '8b7500',
'goldenrod' => 'daa520',
'goldenrod1' => 'ffc125',
'goldenrod2' => 'eeb422',
'goldenrod3' => 'cd9b1d',
'goldenrod4' => '8b6914',
'gray' => 'bebebe',
'gray1' => '030303',
'gray10' => '1a1a1a',
'gray11' => '1c1c1c',
'gray12' => '1f1f1f',
'gray13' => '212121',
'gray14' => '242424',
'gray15' => '262626',
'gray16' => '292929',
'gray17' => '2b2b2b',
'gray18' => '2e2e2e',
'gray19' => '303030',
'gray2' => '050505',
'gray20' => '333333',
'gray21' => '363636',
'gray22' => '383838',
'gray23' => '3b3b3b',
'gray24' => '3d3d3d',
'gray25' => '404040',
'gray26' => '424242',
'gray27' => '454545',
'gray28' => '474747',
'gray29' => '4a4a4a',
'gray3' => '080808',
'gray30' => '4d4d4d',
'gray31' => '4f4f4f',
'gray32' => '525252',
'gray33' => '545454',
'gray34' => '575757',
'gray35' => '595959',
'gray36' => '5c5c5c',
'gray37' => '5e5e5e',
'gray38' => '616161',
'gray39' => '636363',
'gray4' => '0a0a0a',
'gray40' => '666666',
'gray41' => '696969',
'gray42' => '6b6b6b',
'gray43' => '6e6e6e',
'gray44' => '707070',
'gray45' => '737373',
'gray46' => '757575',
'gray47' => '787878',
'gray48' => '7a7a7a',
'gray49' => '7d7d7d',
'gray5' => '0d0d0d',
'gray50' => '7f7f7f',
'gray51' => '828282',
'gray52' => '858585',
'gray53' => '878787',
'gray54' => '8a8a8a',
'gray55' => '8c8c8c',
'gray56' => '8f8f8f',
'gray57' => '919191',
'gray58' => '949494',
'gray59' => '969696',
'gray6' => '0f0f0f',
'gray60' => '999999',
'gray61' => '9c9c9c',
'gray62' => '9e9e9e',
'gray63' => 'a1a1a1',
'gray64' => 'a3a3a3',
'gray65' => 'a6a6a6',
'gray66' => 'a8a8a8',
'gray67' => 'ababab',
'gray68' => 'adadad',
'gray69' => 'b0b0b0',
'gray7' => '121212',
'gray70' => 'b3b3b3',
'gray71' => 'b5b5b5',
'gray72' => 'b8b8b8',
'gray73' => 'bababa',
'gray74' => 'bdbdbd',
'gray75' => 'bfbfbf',
'gray76' => 'c2c2c2',
'gray77' => 'c4c4c4',
'gray78' => 'c7c7c7',
'gray79' => 'c9c9c9',
'gray8' => '141414',
'gray80' => 'cccccc',
'gray81' => 'cfcfcf',
'gray82' => 'd1d1d1',
'gray83' => 'd4d4d4',
'gray84' => 'd6d6d6',
'gray85' => 'd9d9d9',
'gray86' => 'dbdbdb',
'gray87' => 'dedede',
'gray88' => 'e0e0e0',
'gray89' => 'e3e3e3',
'gray9' => '171717',
'gray90' => 'e5e5e5',
'gray91' => 'e8e8e8',
'gray92' => 'ebebeb',
'gray93' => 'ededed',
'gray94' => 'f0f0f0',
'gray95' => 'f2f2f2',
'gray97' => 'f7f7f7',
'gray98' => 'fafafa',
'gray99' => 'fcfcfc',
'green' => '00ff00',
'green1' => '00ff00',
'green2' => '00ee00',
'green3' => '00cd00',
'green4' => '008b00',
'greenyellow' => 'adff2f',
'honeydew1' => 'f0fff0',
'honeydew2' => 'e0eee0',
'honeydew3' => 'c1cdc1',
'honeydew4' => '838b83',
'hotpink' => 'ff69b4',
'hotpink1' => 'ff6eb4',
'hotpink2' => 'ee6aa7',
'hotpink3' => 'cd6090',
'hotpink4' => '8b3a62',
'indianred' => 'cd5c5c',
'indianred1' => 'ff6a6a',
'indianred2' => 'ee6363',
'indianred3' => 'cd5555',
'indianred4' => '8b3a3a',
'ivory1' => 'fffff0',
'ivory2' => 'eeeee0',
'ivory3' => 'cdcdc1',
'ivory4' => '8b8b83',
'khaki' => 'f0e68c',
'khaki1' => 'fff68f',
'khaki2' => 'eee685',
'khaki3' => 'cdc673',
'khaki4' => '8b864e',
'lavender' => 'e6e6fa',
'lavenderblush1' => 'fff0f5',
'lavenderblush2' => 'eee0e5',
'lavenderblush3' => 'cdc1c5',
'lavenderblush4' => '8b8386',
'lawngreen' => '7cfc00',
'lemonchiffon1' => 'fffacd',
'lemonchiffon2' => 'eee9bf',
'lemonchiffon3' => 'cdc9a5',
'lemonchiffon4' => '8b8970',
'light' => 'eedd82',
'lightblue' => 'add8e6',
'lightblue1' => 'bfefff',
'lightblue2' => 'b2dfee',
'lightblue3' => '9ac0cd',
'lightblue4' => '68838b',
'lightcoral' => 'f08080',
'lightcyan1' => 'e0ffff',
'lightcyan2' => 'd1eeee',
'lightcyan3' => 'b4cdcd',
'lightcyan4' => '7a8b8b',
'lightgoldenrod1' => 'ffec8b',
'lightgoldenrod2' => 'eedc82',
'lightgoldenrod3' => 'cdbe70',
'lightgoldenrod4' => '8b814c',
'lightgoldenrodyellow' => 'fafad2',
'lightgray' => 'd3d3d3',
'lightpink' => 'ffb6c1',
'lightpink1' => 'ffaeb9',
'lightpink2' => 'eea2ad',
'lightpink3' => 'cd8c95',
'lightpink4' => '8b5f65',
'lightsalmon1' => 'ffa07a',
'lightsalmon2' => 'ee9572',
'lightsalmon3' => 'cd8162',
'lightsalmon4' => '8b5742',
'lightseagreen' => '20b2aa',
'lightskyblue' => '87cefa',
'lightskyblue1' => 'b0e2ff',
'lightskyblue2' => 'a4d3ee',
'lightskyblue3' => '8db6cd',
'lightskyblue4' => '607b8b',
'lightslateblue' => '8470ff',
'lightslategray' => '778899',
'lightsteelblue' => 'b0c4de',
'lightsteelblue1' => 'cae1ff',
'lightsteelblue2' => 'bcd2ee',
'lightsteelblue3' => 'a2b5cd',
'lightsteelblue4' => '6e7b8b',
'lightyellow1' => 'ffffe0',
'lightyellow2' => 'eeeed1',
'lightyellow3' => 'cdcdb4',
'lightyellow4' => '8b8b7a',
'lime' => '00ff00',
'limegreen' => '32cd32',
'linen' => 'faf0e6',
'magenta' => 'ff00ff',
'magenta2' => 'ee00ee',
'magenta3' => 'cd00cd',
'magenta4' => '8b008b',
'maroon' => 'b03060',
'maroon1' => 'ff34b3',
'maroon2' => 'ee30a7',
'maroon3' => 'cd2990',
'maroon4' => '8b1c62',
'medium' => '66cdaa',
'mediumaquamarine' => '66cdaa',
'mediumblue' => '0000cd',
'mediumorchid' => 'ba55d3',
'mediumorchid1' => 'e066ff',
'mediumorchid2' => 'd15fee',
'mediumorchid3' => 'b452cd',
'mediumorchid4' => '7a378b',
'mediumpurple' => '9370db',
'mediumpurple1' => 'ab82ff',
'mediumpurple2' => '9f79ee',
'mediumpurple3' => '8968cd',
'mediumpurple4' => '5d478b',
'mediumseagreen' => '3cb371',
'mediumslateblue' => '7b68ee',
'mediumspringgreen' => '00fa9a',
'mediumturquoise' => '48d1cc',
'mediumvioletred' => 'c71585',
'midnightblue' => '191970',
'mintcream' => 'f5fffa',
'mistyrose1' => 'ffe4e1',
'mistyrose2' => 'eed5d2',
'mistyrose3' => 'cdb7b5',
'mistyrose4' => '8b7d7b',
'moccasin' => 'ffe4b5',
'navajowhite1' => 'ffdead',
'navajowhite2' => 'eecfa1',
'navajowhite3' => 'cdb38b',
'navajowhite4' => '8b795e',
'navy' => '000080',
'navyblue' => '000080',
'oldlace' => 'fdf5e6',
'olive' => '808000',
'olivedrab' => '6b8e23',
'olivedrab1' => 'c0ff3e',
'olivedrab2' => 'b3ee3a',
'olivedrab4' => '698b22',
'orange' => 'ffa500',
'orange1' => 'ffa500',
'orange2' => 'ee9a00',
'orange3' => 'cd8500',
'orange4' => '8b5a00',
'orangered1' => 'ff4500',
'orangered2' => 'ee4000',
'orangered3' => 'cd3700',
'orangered4' => '8b2500',
'orchid' => 'da70d6',
'orchid1' => 'ff83fa',
'orchid2' => 'ee7ae9',
'orchid3' => 'cd69c9',
'orchid4' => '8b4789',
'pale' => 'db7093',
'palegoldenrod' => 'eee8aa',
'palegreen' => '98fb98',
'palegreen1' => '9aff9a',
'palegreen2' => '90ee90',
'palegreen3' => '7ccd7c',
'palegreen4' => '548b54',
'paleturquoise' => 'afeeee',
'paleturquoise1' => 'bbffff',
'paleturquoise2' => 'aeeeee',
'paleturquoise3' => '96cdcd',
'paleturquoise4' => '668b8b',
'palevioletred' => 'db7093',
'palevioletred1' => 'ff82ab',
'palevioletred2' => 'ee799f',
'palevioletred3' => 'cd6889',
'palevioletred4' => '8b475d',
'papayawhip' => 'ffefd5',
'peachpuff1' => 'ffdab9',
'peachpuff2' => 'eecbad',
'peachpuff3' => 'cdaf95',
'peachpuff4' => '8b7765',
'pink' => 'ffc0cb',
'pink1' => 'ffb5c5',
'pink2' => 'eea9b8',
'pink3' => 'cd919e',
'pink4' => '8b636c',
'plum' => 'dda0dd',
'plum1' => 'ffbbff',
'plum2' => 'eeaeee',
'plum3' => 'cd96cd',
'plum4' => '8b668b',
'powderblue' => 'b0e0e6',
'purple' => 'a020f0',
'rebeccapurple' => '663399',
'purple1' => '9b30ff',
'purple2' => '912cee',
'purple3' => '7d26cd',
'purple4' => '551a8b',
'red' => 'ff0000',
'red1' => 'ff0000',
'red2' => 'ee0000',
'red3' => 'cd0000',
'red4' => '8b0000',
'rosybrown' => 'bc8f8f',
'rosybrown1' => 'ffc1c1',
'rosybrown2' => 'eeb4b4',
'rosybrown3' => 'cd9b9b',
'rosybrown4' => '8b6969',
'royalblue' => '4169e1',
'royalblue1' => '4876ff',
'royalblue2' => '436eee',
'royalblue3' => '3a5fcd',
'royalblue4' => '27408b',
'saddlebrown' => '8b4513',
'salmon' => 'fa8072',
'salmon1' => 'ff8c69',
'salmon2' => 'ee8262',
'salmon3' => 'cd7054',
'salmon4' => '8b4c39',
'sandybrown' => 'f4a460',
'seagreen1' => '54ff9f',
'seagreen2' => '4eee94',
'seagreen3' => '43cd80',
'seagreen4' => '2e8b57',
'seashell1' => 'fff5ee',
'seashell2' => 'eee5de',
'seashell3' => 'cdc5bf',
'seashell4' => '8b8682',
'sienna' => 'a0522d',
'sienna1' => 'ff8247',
'sienna2' => 'ee7942',
'sienna3' => 'cd6839',
'sienna4' => '8b4726',
'silver' => 'c0c0c0',
'skyblue' => '87ceeb',
'skyblue1' => '87ceff',
'skyblue2' => '7ec0ee',
'skyblue3' => '6ca6cd',
'skyblue4' => '4a708b',
'slateblue' => '6a5acd',
'slateblue1' => '836fff',
'slateblue2' => '7a67ee',
'slateblue3' => '6959cd',
'slateblue4' => '473c8b',
'slategray' => '708090',
'slategray1' => 'c6e2ff',
'slategray2' => 'b9d3ee',
'slategray3' => '9fb6cd',
'slategray4' => '6c7b8b',
'snow1' => 'fffafa',
'snow2' => 'eee9e9',
'snow3' => 'cdc9c9',
'snow4' => '8b8989',
'springgreen1' => '00ff7f',
'springgreen2' => '00ee76',
'springgreen3' => '00cd66',
'springgreen4' => '008b45',
'steelblue' => '4682b4',
'steelblue1' => '63b8ff',
'steelblue2' => '5cacee',
'steelblue3' => '4f94cd',
'steelblue4' => '36648b',
'tan' => 'd2b48c',
'tan1' => 'ffa54f',
'tan2' => 'ee9a49',
'tan3' => 'cd853f',
'tan4' => '8b5a2b',
'teal' => '008080',
'thistle' => 'd8bfd8',
'thistle1' => 'ffe1ff',
'thistle2' => 'eed2ee',
'thistle3' => 'cdb5cd',
'thistle4' => '8b7b8b',
'tomato1' => 'ff6347',
'tomato2' => 'ee5c42',
'tomato3' => 'cd4f39',
'tomato4' => '8b3626',
'turquoise' => '40e0d0',
'turquoise1' => '00f5ff',
'turquoise2' => '00e5ee',
'turquoise3' => '00c5cd',
'turquoise4' => '00868b',
'violet' => 'ee82ee',
'violetred' => 'd02090',
'violetred1' => 'ff3e96',
'violetred2' => 'ee3a8c',
'violetred3' => 'cd3278',
'violetred4' => '8b2252',
'wheat' => 'f5deb3',
'wheat1' => 'ffe7ba',
'wheat2' => 'eed8ae',
'wheat3' => 'cdba96',
'wheat4' => '8b7e66',
'white' => 'ffffff',
'whitesmoke' => 'f5f5f5',
'yellow' => 'ffff00',
'yellow1' => 'ffff00',
'yellow2' => 'eeee00',
'yellow3' => 'cdcd00',
'yellow4' => '8b8b00',
'yellowgreen' => '9acd32',
];
/** @var ?string */
private $face;
/** @var ?string */
private $size;
/** @var ?string */
private $color;
/** @var bool */
private $bold = false;
/** @var bool */
private $italic = false;
/** @var bool */
private $underline = false;
/** @var bool */
private $superscript = false;
/** @var bool */
private $subscript = false;
/** @var bool */
private $strikethrough = false;
private const START_TAG_CALLBACKS = [
'font' => 'startFontTag',
'b' => 'startBoldTag',
'strong' => 'startBoldTag',
'i' => 'startItalicTag',
'em' => 'startItalicTag',
'u' => 'startUnderlineTag',
'ins' => 'startUnderlineTag',
'del' => 'startStrikethruTag',
'sup' => 'startSuperscriptTag',
'sub' => 'startSubscriptTag',
];
private const END_TAG_CALLBACKS = [
'font' => 'endFontTag',
'b' => 'endBoldTag',
'strong' => 'endBoldTag',
'i' => 'endItalicTag',
'em' => 'endItalicTag',
'u' => 'endUnderlineTag',
'ins' => 'endUnderlineTag',
'del' => 'endStrikethruTag',
'sup' => 'endSuperscriptTag',
'sub' => 'endSubscriptTag',
'br' => 'breakTag',
'p' => 'breakTag',
'h1' => 'breakTag',
'h2' => 'breakTag',
'h3' => 'breakTag',
'h4' => 'breakTag',
'h5' => 'breakTag',
'h6' => 'breakTag',
];
/** @var array */
private $stack = [];
/** @var string */
private $stringData = '';
/**
* @var RichText
*/
private $richTextObject;
private function initialise(): void
{
$this->face = $this->size = $this->color = null;
$this->bold = $this->italic = $this->underline = $this->superscript = $this->subscript = $this->strikethrough = false;
$this->stack = [];
$this->stringData = '';
}
/**
* Parse HTML formatting and return the resulting RichText.
*
* @param string $html
*
* @return RichText
*/
public function toRichTextObject($html)
{
$this->initialise();
// Create a new DOM object
$dom = new DOMDocument();
// Load the HTML file into the DOM object
// Note the use of error suppression, because typically this will be an html fragment, so not fully valid markup
$prefix = '<?xml encoding="UTF-8">';
/** @scrutinizer ignore-unhandled */
@$dom->loadHTML($prefix . $html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
// Discard excess white space
$dom->preserveWhiteSpace = false;
$this->richTextObject = new RichText();
$this->parseElements($dom);
// Clean any further spurious whitespace
$this->cleanWhitespace();
return $this->richTextObject;
}
private function cleanWhitespace(): void
{
foreach ($this->richTextObject->getRichTextElements() as $key => $element) {
$text = $element->getText();
// Trim any leading spaces on the first run
if ($key == 0) {
$text = ltrim($text);
}
// Trim any spaces immediately after a line break
$text = (string) preg_replace('/\n */mu', "\n", $text);
$element->setText($text);
}
}
private function buildTextRun(): void
{
$text = $this->stringData;
if (trim($text) === '') {
return;
}
$richtextRun = $this->richTextObject->createTextRun($this->stringData);
$font = $richtextRun->getFont();
if ($font !== null) {
if ($this->face) {
$font->setName($this->face);
}
if ($this->size) {
$font->setSize($this->size);
}
if ($this->color) {
$font->setColor(new Color('ff' . $this->color));
}
if ($this->bold) {
$font->setBold(true);
}
if ($this->italic) {
$font->setItalic(true);
}
if ($this->underline) {
$font->setUnderline(Font::UNDERLINE_SINGLE);
}
if ($this->superscript) {
$font->setSuperscript(true);
}
if ($this->subscript) {
$font->setSubscript(true);
}
if ($this->strikethrough) {
$font->setStrikethrough(true);
}
}
$this->stringData = '';
}
private function rgbToColour(string $rgbValue): string
{
preg_match_all('/\d+/', $rgbValue, $values);
foreach ($values[0] as &$value) {
$value = str_pad(dechex($value), 2, '0', STR_PAD_LEFT);
}
return implode('', $values[0]);
}
public static function colourNameLookup(string $colorName): string
{
return self::COLOUR_MAP[$colorName] ?? '';
}
protected function startFontTag(DOMElement $tag): void
{
$attrs = $tag->attributes;
if ($attrs !== null) {
foreach ($attrs as $attribute) {
$attributeName = strtolower($attribute->name);
$attributeValue = $attribute->value;
if ($attributeName == 'color') {
if (preg_match('/rgb\s*\(/', $attributeValue)) {
$this->$attributeName = $this->rgbToColour($attributeValue);
} elseif (strpos(trim($attributeValue), '#') === 0) {
$this->$attributeName = ltrim($attributeValue, '#');
} else {
$this->$attributeName = static::colourNameLookup($attributeValue);
}
} else {
$this->$attributeName = $attributeValue;
}
}
}
}
protected function endFontTag(): void
{
$this->face = $this->size = $this->color = null;
}
protected function startBoldTag(): void
{
$this->bold = true;
}
protected function endBoldTag(): void
{
$this->bold = false;
}
protected function startItalicTag(): void
{
$this->italic = true;
}
protected function endItalicTag(): void
{
$this->italic = false;
}
protected function startUnderlineTag(): void
{
$this->underline = true;
}
protected function endUnderlineTag(): void
{
$this->underline = false;
}
protected function startSubscriptTag(): void
{
$this->subscript = true;
}
protected function endSubscriptTag(): void
{
$this->subscript = false;
}
protected function startSuperscriptTag(): void
{
$this->superscript = true;
}
protected function endSuperscriptTag(): void
{
$this->superscript = false;
}
protected function startStrikethruTag(): void
{
$this->strikethrough = true;
}
protected function endStrikethruTag(): void
{
$this->strikethrough = false;
}
protected function breakTag(): void
{
$this->stringData .= "\n";
}
private function parseTextNode(DOMText $textNode): void
{
$domText = (string) preg_replace(
'/\s+/u',
' ',
str_replace(["\r", "\n"], ' ', $textNode->nodeValue ?? '')
);
$this->stringData .= $domText;
$this->buildTextRun();
}
/**
* @param string $callbackTag
*/
private function handleCallback(DOMElement $element, $callbackTag, array $callbacks): void
{
if (isset($callbacks[$callbackTag])) {
$elementHandler = $callbacks[$callbackTag];
if (method_exists($this, $elementHandler)) {
/** @var callable */
$callable = [$this, $elementHandler];
call_user_func($callable, $element);
}
}
}
private function parseElementNode(DOMElement $element): void
{
$callbackTag = strtolower($element->nodeName);
$this->stack[] = $callbackTag;
$this->handleCallback($element, $callbackTag, self::START_TAG_CALLBACKS);
$this->parseElements($element);
array_pop($this->stack);
$this->handleCallback($element, $callbackTag, self::END_TAG_CALLBACKS);
}
private function parseElements(DOMNode $element): void
{
foreach ($element->childNodes as $child) {
if ($child instanceof DOMText) {
$this->parseTextNode($child);
} elseif ($child instanceof DOMElement) {
$this->parseElementNode($child);
}
}
}
}
PK �8]|ʞ � 1 phpspreadsheet/src/PhpSpreadsheet/Helper/Size.phpnu �[��� <?php
namespace PhpOffice\PhpSpreadsheet\Helper;
class Size
{
const REGEXP_SIZE_VALIDATION = '/^(?P<size>\d*\.?\d+)(?P<unit>pt|px|em)?$/i';
/**
* @var bool
*/
protected $valid;
/**
* @var string
*/
protected $size = '';
/**
* @var string
*/
protected $unit = '';
public function __construct(string $size)
{
$this->valid = (bool) preg_match(self::REGEXP_SIZE_VALIDATION, $size, $matches);
if ($this->valid) {
$this->size = $matches['size'];
$this->unit = $matches['unit'] ?? 'pt';
}
}
public function valid(): bool
{
return $this->valid;
}
public function size(): string
{
return $this->size;
}
public function unit(): string
{
return $this->unit;
}
public function __toString()
{
return $this->size . $this->unit;
}
}
PK �8]9�8�
�
7 phpspreadsheet/src/PhpSpreadsheet/Helper/Downloader.phpnu �[��� <?php
namespace PhpOffice\PhpSpreadsheet\Helper;
use PhpOffice\PhpSpreadsheet\Exception;
class Downloader
{
protected string $filepath;
protected string $filename;
protected string $filetype;
protected const CONTENT_TYPES = [
'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'xls' => 'application/vnd.ms-excel',
'ods' => 'application/vnd.oasis.opendocument.spreadsheet',
'csv' => 'text/csv',
'html' => 'text/html',
'pdf' => 'application/pdf',
];
public function __construct(string $folder, string $filename, ?string $filetype = null)
{
if ((is_dir($folder) === false) || (is_readable($folder) === false)) {
throw new Exception("Folder {$folder} is not accessable");
}
$filepath = "{$folder}/{$filename}";
$this->filepath = (string) realpath($filepath);
$this->filename = basename($filepath);
if ((file_exists($this->filepath) === false) || (is_readable($this->filepath) === false)) {
throw new Exception("{$this->filename} not found, or cannot be read");
}
$filetype ??= pathinfo($filename, PATHINFO_EXTENSION);
if (array_key_exists(strtolower($filetype), self::CONTENT_TYPES) === false) {
throw new Exception("Invalid filetype: {$filetype} cannot be downloaded");
}
$this->filetype = strtolower($filetype);
}
public function download(): void
{
$this->headers();
readfile($this->filepath);
}
public function headers(): void
{
ob_clean();
$this->contentType();
$this->contentDisposition();
$this->cacheHeaders();
$this->fileSize();
flush();
}
protected function contentType(): void
{
header('Content-Type: ' . self::CONTENT_TYPES[$this->filetype]);
}
protected function contentDisposition(): void
{
header('Content-Disposition: attachment;filename="' . $this->filename . '"');
}
protected function cacheHeaders(): void
{
header('Cache-Control: max-age=0');
// If you're serving to IE 9, then the following may be needed
header('Cache-Control: max-age=1');
// If you're serving to IE over SSL, then the following may be needed
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); // Date in the past
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT'); // always modified
header('Cache-Control: cache, must-revalidate'); // HTTP/1.1
header('Pragma: public'); // HTTP/1.0
}
protected function fileSize(): void
{
header('Content-Length: ' . filesize($this->filepath));
}
}
PK �8]g�DW� � 6 phpspreadsheet/src/PhpSpreadsheet/Helper/Dimension.phpnu �[��� <?php
namespace PhpOffice\PhpSpreadsheet\Helper;
use PhpOffice\PhpSpreadsheet\Exception;
use PhpOffice\PhpSpreadsheet\Shared\Drawing;
use PhpOffice\PhpSpreadsheet\Style\Font;
class Dimension
{
public const UOM_CENTIMETERS = 'cm';
public const UOM_MILLIMETERS = 'mm';
public const UOM_INCHES = 'in';
public const UOM_PIXELS = 'px';
public const UOM_POINTS = 'pt';
public const UOM_PICA = 'pc';
/**
* Based on 96 dpi.
*/
const ABSOLUTE_UNITS = [
self::UOM_CENTIMETERS => 96.0 / 2.54,
self::UOM_MILLIMETERS => 96.0 / 25.4,
self::UOM_INCHES => 96.0,
self::UOM_PIXELS => 1.0,
self::UOM_POINTS => 96.0 / 72,
self::UOM_PICA => 96.0 * 12 / 72,
];
/**
* Based on a standard column width of 8.54 units in MS Excel.
*/
const RELATIVE_UNITS = [
'em' => 10.0 / 8.54,
'ex' => 10.0 / 8.54,
'ch' => 10.0 / 8.54,
'rem' => 10.0 / 8.54,
'vw' => 8.54,
'vh' => 8.54,
'vmin' => 8.54,
'vmax' => 8.54,
'%' => 8.54 / 100,
];
/**
* @var float|int If this is a width, then size is measured in pixels (if is set)
* or in Excel's default column width units if $unit is null.
* If this is a height, then size is measured in pixels ()
* or in points () if $unit is null.
*/
protected $size;
/**
* @var null|string
*/
protected $unit;
/**
* Phpstan bug has been fixed; this function allows us to
* pass Phpstan whether fixed or not.
*
* @param mixed $value
*/
private static function stanBugFixed($value): array
{
return is_array($value) ? $value : [null, null];
}
public function __construct(string $dimension)
{
[$size, $unit] = self::stanBugFixed(sscanf($dimension, '%[1234567890.]%s'));
$unit = strtolower(trim($unit ?? ''));
$size = (float) $size;
// If a UoM is specified, then convert the size to pixels for internal storage
if (isset(self::ABSOLUTE_UNITS[$unit])) {
$size *= self::ABSOLUTE_UNITS[$unit];
$this->unit = self::UOM_PIXELS;
} elseif (isset(self::RELATIVE_UNITS[$unit])) {
$size *= self::RELATIVE_UNITS[$unit];
$size = round($size, 4);
}
$this->size = $size;
}
public function width(): float
{
return (float) ($this->unit === null)
? $this->size
: round(Drawing::pixelsToCellDimension((int) $this->size, new Font(false)), 4);
}
public function height(): float
{
return (float) ($this->unit === null)
? $this->size
: $this->toUnit(self::UOM_POINTS);
}
public function toUnit(string $unitOfMeasure): float
{
$unitOfMeasure = strtolower($unitOfMeasure);
if (!array_key_exists($unitOfMeasure, self::ABSOLUTE_UNITS)) {
throw new Exception("{$unitOfMeasure} is not a vaid unit of measure");
}
$size = $this->size;
if ($this->unit === null) {
$size = Drawing::cellDimensionToPixels($size, new Font(false));
}
return $size / self::ABSOLUTE_UNITS[$unitOfMeasure];
}
}
PK �8]S
T��$ �$ 3 phpspreadsheet/src/PhpSpreadsheet/Helper/Sample.phpnu �[��� <?php
namespace PhpOffice\PhpSpreadsheet\Helper;
use PhpOffice\PhpSpreadsheet\Chart\Chart;
use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\Settings;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
use PhpOffice\PhpSpreadsheet\Writer\IWriter;
use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;
use RecursiveRegexIterator;
use ReflectionClass;
use RegexIterator;
use RuntimeException;
use Throwable;
/**
* Helper class to be used in sample code.
*/
class Sample
{
/**
* Returns whether we run on CLI or browser.
*
* @return bool
*/
public function isCli()
{
return PHP_SAPI === 'cli';
}
/**
* Return the filename currently being executed.
*
* @return string
*/
public function getScriptFilename()
{
return basename($_SERVER['SCRIPT_FILENAME'], '.php');
}
/**
* Whether we are executing the index page.
*
* @return bool
*/
public function isIndex()
{
return $this->getScriptFilename() === 'index';
}
/**
* Return the page title.
*
* @return string
*/
public function getPageTitle()
{
return $this->isIndex() ? 'PHPSpreadsheet' : $this->getScriptFilename();
}
/**
* Return the page heading.
*
* @return string
*/
public function getPageHeading()
{
return $this->isIndex() ? '' : '<h1>' . str_replace('_', ' ', $this->getScriptFilename()) . '</h1>';
}
/**
* Returns an array of all known samples.
*
* @return string[][] [$name => $path]
*/
public function getSamples()
{
// Populate samples
$baseDir = realpath(__DIR__ . '/../../../samples');
if ($baseDir === false) {
// @codeCoverageIgnoreStart
throw new RuntimeException('realpath returned false');
// @codeCoverageIgnoreEnd
}
$directory = new RecursiveDirectoryIterator($baseDir);
$iterator = new RecursiveIteratorIterator($directory);
$regex = new RegexIterator($iterator, '/^.+\.php$/', RecursiveRegexIterator::GET_MATCH);
$files = [];
foreach ($regex as $file) {
$file = str_replace(str_replace('\\', '/', $baseDir) . '/', '', str_replace('\\', '/', $file[0]));
if (is_array($file)) {
// @codeCoverageIgnoreStart
throw new RuntimeException('str_replace returned array');
// @codeCoverageIgnoreEnd
}
$info = pathinfo($file);
$category = str_replace('_', ' ', $info['dirname'] ?? '');
$name = str_replace('_', ' ', (string) preg_replace('/(|\.php)/', '', $info['filename']));
if (!in_array($category, ['.', 'boostrap', 'templates'])) {
if (!isset($files[$category])) {
$files[$category] = [];
}
$files[$category][$name] = $file;
}
}
// Sort everything
ksort($files);
foreach ($files as &$f) {
asort($f);
}
return $files;
}
/**
* Write documents.
*
* @param string $filename
* @param string[] $writers
*/
public function write(Spreadsheet $spreadsheet, $filename, array $writers = ['Xlsx', 'Xls'], bool $withCharts = false, ?callable $writerCallback = null): void
{
// Set active sheet index to the first sheet, so Excel opens this as the first sheet
$spreadsheet->setActiveSheetIndex(0);
// Write documents
foreach ($writers as $writerType) {
$path = $this->getFilename($filename, mb_strtolower($writerType));
$writer = IOFactory::createWriter($spreadsheet, $writerType);
$writer->setIncludeCharts($withCharts);
if ($writerCallback !== null) {
$writerCallback($writer);
}
$callStartTime = microtime(true);
$writer->save($path);
$this->logWrite($writer, $path, /** @scrutinizer ignore-type */ $callStartTime);
if ($this->isCli() === false) {
echo '<a href="/download.php?type=' . pathinfo($path, PATHINFO_EXTENSION) . '&name=' . basename($path) . '">Download ' . basename($path) . '</a><br />';
}
}
$this->logEndingNotes();
}
protected function isDirOrMkdir(string $folder): bool
{
return \is_dir($folder) || \mkdir($folder);
}
/**
* Returns the temporary directory and make sure it exists.
*
* @return string
*/
public function getTemporaryFolder()
{
$tempFolder = sys_get_temp_dir() . '/phpspreadsheet';
if (!$this->isDirOrMkdir($tempFolder)) {
throw new RuntimeException(sprintf('Directory "%s" was not created', $tempFolder));
}
return $tempFolder;
}
/**
* Returns the filename that should be used for sample output.
*
* @param string $filename
* @param string $extension
*/
public function getFilename($filename, $extension = 'xlsx'): string
{
$originalExtension = pathinfo($filename, PATHINFO_EXTENSION);
return $this->getTemporaryFolder() . '/' . str_replace('.' . /** @scrutinizer ignore-type */ $originalExtension, '.' . $extension, basename($filename));
}
/**
* Return a random temporary file name.
*
* @param string $extension
*
* @return string
*/
public function getTemporaryFilename($extension = 'xlsx')
{
$temporaryFilename = tempnam($this->getTemporaryFolder(), 'phpspreadsheet-');
if ($temporaryFilename === false) {
// @codeCoverageIgnoreStart
throw new RuntimeException('tempnam returned false');
// @codeCoverageIgnoreEnd
}
unlink($temporaryFilename);
return $temporaryFilename . '.' . $extension;
}
public function log(string $message): void
{
$eol = $this->isCli() ? PHP_EOL : '<br />';
echo($this->isCli() ? date('H:i:s ') : '') . $message . $eol;
}
public function renderChart(Chart $chart, string $fileName): void
{
if ($this->isCli() === true) {
return;
}
Settings::setChartRenderer(\PhpOffice\PhpSpreadsheet\Chart\Renderer\MtJpGraphRenderer::class);
$fileName = $this->getFilename($fileName, 'png');
try {
$chart->render($fileName);
$this->log('Rendered image: ' . $fileName);
$imageData = file_get_contents($fileName);
if ($imageData !== false) {
echo '<div><img src="data:image/gif;base64,' . base64_encode($imageData) . '" /></div>';
}
} catch (Throwable $e) {
$this->log('Error rendering chart: ' . $e->getMessage() . PHP_EOL);
}
}
public function titles(string $category, string $functionName, ?string $description = null): void
{
$this->log(sprintf('%s Functions:', $category));
$description === null
? $this->log(sprintf('Function: %s()', rtrim($functionName, '()')))
: $this->log(sprintf('Function: %s() - %s.', rtrim($functionName, '()'), rtrim($description, '.')));
}
public function displayGrid(array $matrix): void
{
$renderer = new TextGrid($matrix, $this->isCli());
echo $renderer->render();
}
public function logCalculationResult(
Worksheet $worksheet,
string $functionName,
string $formulaCell,
?string $descriptionCell = null
): void {
if ($descriptionCell !== null) {
$this->log($worksheet->getCell($descriptionCell)->getValue());
}
$this->log($worksheet->getCell($formulaCell)->getValue());
$this->log(sprintf('%s() Result is ', $functionName) . $worksheet->getCell($formulaCell)->getCalculatedValue());
}
/**
* Log ending notes.
*/
public function logEndingNotes(): void
{
// Do not show execution time for index
$this->log('Peak memory usage: ' . (memory_get_peak_usage(true) / 1024 / 1024) . 'MB');
}
/**
* Log a line about the write operation.
*
* @param string $path
* @param float $callStartTime
*/
public function logWrite(IWriter $writer, $path, $callStartTime): void
{
$callEndTime = microtime(true);
$callTime = $callEndTime - $callStartTime;
$reflection = new ReflectionClass($writer);
$format = $reflection->getShortName();
$message = ($this->isCli() === true)
? "Write {$format} format to {$path} in " . sprintf('%.4f', $callTime) . ' seconds'
: "Write {$format} format to <code>{$path}</code> in " . sprintf('%.4f', $callTime) . ' seconds';
$this->log($message);
}
/**
* Log a line about the read operation.
*
* @param string $format
* @param string $path
* @param float $callStartTime
*/
public function logRead($format, $path, $callStartTime): void
{
$callEndTime = microtime(true);
$callTime = $callEndTime - $callStartTime;
$message = "Read {$format} format from <code>{$path}</code> in " . sprintf('%.4f', $callTime) . ' seconds';
$this->log($message);
}
}
PK �8]$�] ] 5 phpspreadsheet/src/PhpSpreadsheet/Helper/TextGrid.phpnu �[��� <?php
namespace PhpOffice\PhpSpreadsheet\Helper;
class TextGrid
{
/**
* @var bool
*/
private $isCli = true;
/**
* @var array
*/
protected $matrix;
/**
* @var array
*/
protected $rows;
/**
* @var array
*/
protected $columns;
/**
* @var string
*/
private $gridDisplay;
public function __construct(array $matrix, bool $isCli = true)
{
$this->rows = array_keys($matrix);
$this->columns = array_keys($matrix[$this->rows[0]]);
$matrix = array_values($matrix);
array_walk(
$matrix,
function (&$row): void {
$row = array_values($row);
}
);
$this->matrix = $matrix;
$this->isCli = $isCli;
}
public function render(): string
{
$this->gridDisplay = $this->isCli ? '' : '<pre>';
$maxRow = max($this->rows);
$maxRowLength = mb_strlen((string) $maxRow) + 1;
$columnWidths = $this->getColumnWidths();
$this->renderColumnHeader($maxRowLength, $columnWidths);
$this->renderRows($maxRowLength, $columnWidths);
$this->renderFooter($maxRowLength, $columnWidths);
$this->gridDisplay .= $this->isCli ? '' : '</pre>';
return $this->gridDisplay;
}
private function renderRows(int $maxRowLength, array $columnWidths): void
{
foreach ($this->matrix as $row => $rowData) {
$this->gridDisplay .= '|' . str_pad((string) $this->rows[$row], $maxRowLength, ' ', STR_PAD_LEFT) . ' ';
$this->renderCells($rowData, $columnWidths);
$this->gridDisplay .= '|' . PHP_EOL;
}
}
private function renderCells(array $rowData, array $columnWidths): void
{
foreach ($rowData as $column => $cell) {
$displayCell = ($this->isCli) ? (string) $cell : htmlentities((string) $cell);
$this->gridDisplay .= '| ';
$this->gridDisplay .= $displayCell . str_repeat(' ', $columnWidths[$column] - mb_strlen($cell ?? '') + 1);
}
}
private function renderColumnHeader(int $maxRowLength, array $columnWidths): void
{
$this->gridDisplay .= str_repeat(' ', $maxRowLength + 2);
foreach ($this->columns as $column => $reference) {
$this->gridDisplay .= '+-' . str_repeat('-', $columnWidths[$column] + 1);
}
$this->gridDisplay .= '+' . PHP_EOL;
$this->gridDisplay .= str_repeat(' ', $maxRowLength + 2);
foreach ($this->columns as $column => $reference) {
$this->gridDisplay .= '| ' . str_pad((string) $reference, $columnWidths[$column] + 1, ' ');
}
$this->gridDisplay .= '|' . PHP_EOL;
$this->renderFooter($maxRowLength, $columnWidths);
}
private function renderFooter(int $maxRowLength, array $columnWidths): void
{
$this->gridDisplay .= '+' . str_repeat('-', $maxRowLength + 1);
foreach ($this->columns as $column => $reference) {
$this->gridDisplay .= '+-';
$this->gridDisplay .= str_pad((string) '', $columnWidths[$column] + 1, '-');
}
$this->gridDisplay .= '+' . PHP_EOL;
}
private function getColumnWidths(): array
{
$columnCount = count($this->matrix, COUNT_RECURSIVE) / count($this->matrix);
$columnWidths = [];
for ($column = 0; $column < $columnCount; ++$column) {
$columnWidths[] = $this->getColumnWidth(array_column($this->matrix, $column));
}
return $columnWidths;
}
private function getColumnWidth(array $columnData): int
{
$columnWidth = 0;
$columnData = array_values($columnData);
foreach ($columnData as $columnValue) {
if (is_string($columnValue)) {
$columnWidth = max($columnWidth, mb_strlen($columnValue));
} elseif (is_bool($columnValue)) {
$columnWidth = max($columnWidth, mb_strlen($columnValue ? 'TRUE' : 'FALSE'));
}
$columnWidth = max($columnWidth, mb_strlen((string) $columnWidth));
}
return $columnWidth;
}
}
PK �8]k�tF� � 2 phpspreadsheet/src/PhpSpreadsheet/NamedFormula.phpnu �[��� <?php
namespace PhpOffice\PhpSpreadsheet;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
class NamedFormula extends DefinedName
{
/**
* Create a new Named Formula.
*/
public function __construct(
string $name,
?Worksheet $worksheet = null,
?string $formula = null,
bool $localOnly = false,
?Worksheet $scope = null
) {
// Validate data
if (!isset($formula)) {
throw new Exception('You must specify a Formula value for a Named Formula');
}
parent::__construct($name, $worksheet, $formula, $localOnly, $scope);
}
/**
* Get the formula value.
*/
public function getFormula(): string
{
return $this->value;
}
/**
* Set the formula value.
*/
public function setFormula(string $formula): self
{
if (!empty($formula)) {
$this->value = $formula;
}
return $this;
}
}
PK �8]�or<# <# / phpspreadsheet/src/PhpSpreadsheet/IOFactory.phpnu �[��� <?php
namespace PhpOffice\PhpSpreadsheet;
use PhpOffice\PhpSpreadsheet\Reader\IReader;
use PhpOffice\PhpSpreadsheet\Shared\File;
use PhpOffice\PhpSpreadsheet\Writer\IWriter;
/**
* Factory to create readers and writers easily.
*
* It is not required to use this class, but it should make it easier to read and write files.
* Especially for reading files with an unknown format.
*/
abstract class IOFactory
{
public const READER_XLSX = 'Xlsx';
public const READER_XLS = 'Xls';
public const READER_XML = 'Xml';
public const READER_ODS = 'Ods';
public const READER_SYLK = 'Slk';
public const READER_SLK = 'Slk';
public const READER_GNUMERIC = 'Gnumeric';
public const READER_HTML = 'Html';
public const READER_CSV = 'Csv';
public const WRITER_XLSX = 'Xlsx';
public const WRITER_XLS = 'Xls';
public const WRITER_ODS = 'Ods';
public const WRITER_CSV = 'Csv';
public const WRITER_HTML = 'Html';
/** @var string[] */
private static $readers = [
self::READER_XLSX => Reader\Xlsx::class,
self::READER_XLS => Reader\Xls::class,
self::READER_XML => Reader\Xml::class,
self::READER_ODS => Reader\Ods::class,
self::READER_SLK => Reader\Slk::class,
self::READER_GNUMERIC => Reader\Gnumeric::class,
self::READER_HTML => Reader\Html::class,
self::READER_CSV => Reader\Csv::class,
];
/** @var string[] */
private static $writers = [
self::WRITER_XLS => Writer\Xls::class,
self::WRITER_XLSX => Writer\Xlsx::class,
self::WRITER_ODS => Writer\Ods::class,
self::WRITER_CSV => Writer\Csv::class,
self::WRITER_HTML => Writer\Html::class,
'Tcpdf' => Writer\Pdf\Tcpdf::class,
'Dompdf' => Writer\Pdf\Dompdf::class,
'Mpdf' => Writer\Pdf\Mpdf::class,
];
/**
* Create Writer\IWriter.
*/
public static function createWriter(Spreadsheet $spreadsheet, string $writerType): IWriter
{
if (!isset(self::$writers[$writerType])) {
throw new Writer\Exception("No writer found for type $writerType");
}
// Instantiate writer
/** @var IWriter */
$className = self::$writers[$writerType];
return new $className($spreadsheet);
}
/**
* Create IReader.
*/
public static function createReader(string $readerType): IReader
{
if (!isset(self::$readers[$readerType])) {
throw new Reader\Exception("No reader found for type $readerType");
}
// Instantiate reader
/** @var IReader */
$className = self::$readers[$readerType];
return new $className();
}
/**
* Loads Spreadsheet from file using automatic Reader\IReader resolution.
*
* @param string $filename The name of the spreadsheet file
* @param int $flags the optional second parameter flags may be used to identify specific elements
* that should be loaded, but which won't be loaded by default, using these values:
* IReader::LOAD_WITH_CHARTS - Include any charts that are defined in the loaded file.
* IReader::READ_DATA_ONLY - Read cell values only, not formatting or merge structure.
* IReader::IGNORE_EMPTY_CELLS - Don't load empty cells into the model.
* @param string[] $readers An array of Readers to use to identify the file type. By default, load() will try
* all possible Readers until it finds a match; but this allows you to pass in a
* list of Readers so it will only try the subset that you specify here.
* Values in this list can be any of the constant values defined in the set
* IOFactory::READER_*.
*/
public static function load(string $filename, int $flags = 0, ?array $readers = null): Spreadsheet
{
$reader = self::createReaderForFile($filename, $readers);
return $reader->load($filename, $flags);
}
/**
* Identify file type using automatic IReader resolution.
*/
public static function identify(string $filename, ?array $readers = null): string
{
$reader = self::createReaderForFile($filename, $readers);
$className = get_class($reader);
$classType = explode('\\', $className);
unset($reader);
return array_pop($classType);
}
/**
* Create Reader\IReader for file using automatic IReader resolution.
*
* @param string[] $readers An array of Readers to use to identify the file type. By default, load() will try
* all possible Readers until it finds a match; but this allows you to pass in a
* list of Readers so it will only try the subset that you specify here.
* Values in this list can be any of the constant values defined in the set
* IOFactory::READER_*.
*/
public static function createReaderForFile(string $filename, ?array $readers = null): IReader
{
File::assertFile($filename);
$testReaders = self::$readers;
if ($readers !== null) {
$readers = array_map('strtoupper', $readers);
$testReaders = array_filter(
self::$readers,
function (string $readerType) use ($readers) {
return in_array(strtoupper($readerType), $readers, true);
},
ARRAY_FILTER_USE_KEY
);
}
// First, lucky guess by inspecting file extension
$guessedReader = self::getReaderTypeFromExtension($filename);
if (($guessedReader !== null) && array_key_exists($guessedReader, $testReaders)) {
$reader = self::createReader($guessedReader);
// Let's see if we are lucky
if ($reader->canRead($filename)) {
return $reader;
}
}
// If we reach here then "lucky guess" didn't give any result
// Try walking through all the options in self::$readers (or the selected subset)
foreach ($testReaders as $readerType => $class) {
// Ignore our original guess, we know that won't work
if ($readerType !== $guessedReader) {
$reader = self::createReader($readerType);
if ($reader->canRead($filename)) {
return $reader;
}
}
}
throw new Reader\Exception('Unable to identify a reader for this file');
}
/**
* Guess a reader type from the file extension, if any.
*/
private static function getReaderTypeFromExtension(string $filename): ?string
{
$pathinfo = pathinfo($filename);
if (!isset($pathinfo['extension'])) {
return null;
}
switch (strtolower($pathinfo['extension'])) {
case 'xlsx': // Excel (OfficeOpenXML) Spreadsheet
case 'xlsm': // Excel (OfficeOpenXML) Macro Spreadsheet (macros will be discarded)
case 'xltx': // Excel (OfficeOpenXML) Template
case 'xltm': // Excel (OfficeOpenXML) Macro Template (macros will be discarded)
return 'Xlsx';
case 'xls': // Excel (BIFF) Spreadsheet
case 'xlt': // Excel (BIFF) Template
return 'Xls';
case 'ods': // Open/Libre Offic Calc
case 'ots': // Open/Libre Offic Calc Template
return 'Ods';
case 'slk':
return 'Slk';
case 'xml': // Excel 2003 SpreadSheetML
return 'Xml';
case 'gnumeric':
return 'Gnumeric';
case 'htm':
case 'html':
return 'Html';
case 'csv':
// Do nothing
// We must not try to use CSV reader since it loads
// all files including Excel files etc.
return null;
default:
return null;
}
}
/**
* Register a writer with its type and class name.
*/
public static function registerWriter(string $writerType, string $writerClass): void
{
if (!is_a($writerClass, IWriter::class, true)) {
throw new Writer\Exception('Registered writers must implement ' . IWriter::class);
}
self::$writers[$writerType] = $writerClass;
}
/**
* Register a reader with its type and class name.
*/
public static function registerReader(string $readerType, string $readerClass): void
{
if (!is_a($readerClass, IReader::class, true)) {
throw new Reader\Exception('Registered readers must implement ' . IReader::class);
}
self::$readers[$readerType] = $readerClass;
}
}
PK �8]Z�� 8 phpspreadsheet/src/PhpSpreadsheet/Cell/DataValidator.phpnu �[��� <?php
namespace PhpOffice\PhpSpreadsheet\Cell;
use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
use PhpOffice\PhpSpreadsheet\Calculation\Information\ExcelError;
use PhpOffice\PhpSpreadsheet\Exception;
/**
* Validate a cell value according to its validation rules.
*/
class DataValidator
{
/**
* Does this cell contain valid value?
*
* @param Cell $cell Cell to check the value
*
* @return bool
*/
public function isValid(Cell $cell)
{
if (!$cell->hasDataValidation() || $cell->getDataValidation()->getType() === DataValidation::TYPE_NONE) {
return true;
}
$cellValue = $cell->getValue();
$dataValidation = $cell->getDataValidation();
if (!$dataValidation->getAllowBlank() && ($cellValue === null || $cellValue === '')) {
return false;
}
$returnValue = false;
$type = $dataValidation->getType();
if ($type === DataValidation::TYPE_LIST) {
$returnValue = $this->isValueInList($cell);
} elseif ($type === DataValidation::TYPE_WHOLE) {
if (!is_numeric($cellValue) || fmod((float) $cellValue, 1) != 0) {
$returnValue = false;
} else {
$returnValue = $this->numericOperator($dataValidation, (int) $cellValue);
}
} elseif ($type === DataValidation::TYPE_DECIMAL || $type === DataValidation::TYPE_DATE || $type === DataValidation::TYPE_TIME) {
if (!is_numeric($cellValue)) {
$returnValue = false;
} else {
$returnValue = $this->numericOperator($dataValidation, (float) $cellValue);
}
} elseif ($type === DataValidation::TYPE_TEXTLENGTH) {
$returnValue = $this->numericOperator($dataValidation, mb_strlen((string) $cellValue));
}
return $returnValue;
}
/** @param float|int $cellValue */
private function numericOperator(DataValidation $dataValidation, $cellValue): bool
{
$operator = $dataValidation->getOperator();
$formula1 = $dataValidation->getFormula1();
$formula2 = $dataValidation->getFormula2();
$returnValue = false;
if ($operator === DataValidation::OPERATOR_BETWEEN) {
$returnValue = $cellValue >= $formula1 && $cellValue <= $formula2;
} elseif ($operator === DataValidation::OPERATOR_NOTBETWEEN) {
$returnValue = $cellValue < $formula1 || $cellValue > $formula2;
} elseif ($operator === DataValidation::OPERATOR_EQUAL) {
$returnValue = $cellValue == $formula1;
} elseif ($operator === DataValidation::OPERATOR_NOTEQUAL) {
$returnValue = $cellValue != $formula1;
} elseif ($operator === DataValidation::OPERATOR_LESSTHAN) {
$returnValue = $cellValue < $formula1;
} elseif ($operator === DataValidation::OPERATOR_LESSTHANOREQUAL) {
$returnValue = $cellValue <= $formula1;
} elseif ($operator === DataValidation::OPERATOR_GREATERTHAN) {
$returnValue = $cellValue > $formula1;
} elseif ($operator === DataValidation::OPERATOR_GREATERTHANOREQUAL) {
$returnValue = $cellValue >= $formula1;
}
return $returnValue;
}
/**
* Does this cell contain valid value, based on list?
*
* @param Cell $cell Cell to check the value
*
* @return bool
*/
private function isValueInList(Cell $cell)
{
$cellValue = $cell->getValue();
$dataValidation = $cell->getDataValidation();
$formula1 = $dataValidation->getFormula1();
if (!empty($formula1)) {
// inline values list
if ($formula1[0] === '"') {
return in_array(strtolower($cellValue), explode(',', strtolower(trim($formula1, '"'))), true);
} elseif (strpos($formula1, ':') > 0) {
// values list cells
$matchFormula = '=MATCH(' . $cell->getCoordinate() . ', ' . $formula1 . ', 0)';
$calculation = Calculation::getInstance($cell->getWorksheet()->getParent());
try {
$result = $calculation->calculateFormula($matchFormula, $cell->getCoordinate(), $cell);
while (is_array($result)) {
$result = array_pop($result);
}
return $result !== ExcelError::NA();
} catch (Exception $ex) {
return false;
}
}
}
return true;
}
}
PK �8]��� � 4 phpspreadsheet/src/PhpSpreadsheet/Cell/CellRange.phpnu �[��� <?php
namespace PhpOffice\PhpSpreadsheet\Cell;
use PhpOffice\PhpSpreadsheet\Exception;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
class CellRange implements AddressRange
{
/**
* @var CellAddress
*/
protected $from;
/**
* @var CellAddress
*/
protected $to;
public function __construct(CellAddress $from, CellAddress $to)
{
$this->validateFromTo($from, $to);
}
private function validateFromTo(CellAddress $from, CellAddress $to): void
{
// Identify actual top-left and bottom-right values (in case we've been given top-right and bottom-left)
$firstColumn = min($from->columnId(), $to->columnId());
$firstRow = min($from->rowId(), $to->rowId());
$lastColumn = max($from->columnId(), $to->columnId());
$lastRow = max($from->rowId(), $to->rowId());
$fromWorksheet = $from->worksheet();
$toWorksheet = $to->worksheet();
$this->validateWorksheets($fromWorksheet, $toWorksheet);
$this->from = $this->cellAddressWrapper($firstColumn, $firstRow, $fromWorksheet);
$this->to = $this->cellAddressWrapper($lastColumn, $lastRow, $toWorksheet);
}
private function validateWorksheets(?Worksheet $fromWorksheet, ?Worksheet $toWorksheet): void
{
if ($fromWorksheet !== null && $toWorksheet !== null) {
// We could simply compare worksheets rather than worksheet titles; but at some point we may introduce
// support for 3d ranges; and at that point we drop this check and let the validation fall through
// to the check for same workbook; but unless we check on titles, this test will also detect if the
// worksheets are in different spreadsheets, and the next check will never execute or throw its
// own exception.
if ($fromWorksheet->getTitle() !== $toWorksheet->getTitle()) {
throw new Exception('3d Cell Ranges are not supported');
} elseif ($fromWorksheet->getParent() !== $toWorksheet->getParent()) {
throw new Exception('Worksheets must be in the same spreadsheet');
}
}
}
private function cellAddressWrapper(int $column, int $row, ?Worksheet $worksheet = null): CellAddress
{
$cellAddress = Coordinate::stringFromColumnIndex($column) . (string) $row;
return new class ($cellAddress, $worksheet) extends CellAddress {
public function nextRow(int $offset = 1): CellAddress
{
/** @var CellAddress $result */
$result = parent::nextRow($offset);
$this->rowId = $result->rowId;
$this->cellAddress = $result->cellAddress;
return $this;
}
public function previousRow(int $offset = 1): CellAddress
{
/** @var CellAddress $result */
$result = parent::previousRow($offset);
$this->rowId = $result->rowId;
$this->cellAddress = $result->cellAddress;
return $this;
}
public function nextColumn(int $offset = 1): CellAddress
{
/** @var CellAddress $result */
$result = parent::nextColumn($offset);
$this->columnId = $result->columnId;
$this->columnName = $result->columnName;
$this->cellAddress = $result->cellAddress;
return $this;
}
public function previousColumn(int $offset = 1): CellAddress
{
/** @var CellAddress $result */
$result = parent::previousColumn($offset);
$this->columnId = $result->columnId;
$this->columnName = $result->columnName;
$this->cellAddress = $result->cellAddress;
return $this;
}
};
}
public function from(): CellAddress
{
// Re-order from/to in case the cell addresses have been modified
$this->validateFromTo($this->from, $this->to);
return $this->from;
}
public function to(): CellAddress
{
// Re-order from/to in case the cell addresses have been modified
$this->validateFromTo($this->from, $this->to);
return $this->to;
}
public function __toString(): string
{
// Re-order from/to in case the cell addresses have been modified
$this->validateFromTo($this->from, $this->to);
if ($this->from->cellAddress() === $this->to->cellAddress()) {
return "{$this->from->fullCellAddress()}";
}
$fromAddress = $this->from->fullCellAddress();
$toAddress = $this->to->cellAddress();
return "{$fromAddress}:{$toAddress}";
}
}
PK �8]�&)�
�
= phpspreadsheet/src/PhpSpreadsheet/Cell/DefaultValueBinder.phpnu �[��� <?php
namespace PhpOffice\PhpSpreadsheet\Cell;
use DateTimeInterface;
use PhpOffice\PhpSpreadsheet\RichText\RichText;
use PhpOffice\PhpSpreadsheet\Shared\StringHelper;
class DefaultValueBinder implements IValueBinder
{
/**
* Bind value to a cell.
*
* @param Cell $cell Cell to bind value to
* @param mixed $value Value to bind in cell
*
* @return bool
*/
public function bindValue(Cell $cell, $value)
{
// sanitize UTF-8 strings
if (is_string($value)) {
$value = StringHelper::sanitizeUTF8($value);
} elseif (is_object($value)) {
// Handle any objects that might be injected
if ($value instanceof DateTimeInterface) {
$value = $value->format('Y-m-d H:i:s');
} elseif (!($value instanceof RichText)) {
// Attempt to cast any unexpected objects to string
$value = (string) $value; // @phpstan-ignore-line
}
}
// Set value explicit
$cell->setValueExplicit($value, static::dataTypeForValue($value));
// Done!
return true;
}
/**
* DataType for value.
*
* @param mixed $value
*
* @return string
*/
public static function dataTypeForValue($value)
{
// Match the value against a few data types
if ($value === null) {
return DataType::TYPE_NULL;
} elseif (is_float($value) || is_int($value)) {
return DataType::TYPE_NUMERIC;
} elseif (is_bool($value)) {
return DataType::TYPE_BOOL;
} elseif ($value === '') {
return DataType::TYPE_STRING;
} elseif ($value instanceof RichText) {
return DataType::TYPE_INLINE;
} elseif (is_string($value) && strlen($value) > 1 && $value[0] === '=') {
return DataType::TYPE_FORMULA;
} elseif (preg_match('/^[\+\-]?(\d+\\.?\d*|\d*\\.?\d+)([Ee][\-\+]?[0-2]?\d{1,3})?$/', $value)) {
$tValue = ltrim($value, '+-');
if (is_string($value) && strlen($tValue) > 1 && $tValue[0] === '0' && $tValue[1] !== '.') {
return DataType::TYPE_STRING;
} elseif ((strpos($value, '.') === false) && ($value > PHP_INT_MAX)) {
return DataType::TYPE_STRING;
} elseif (!is_numeric($value)) {
return DataType::TYPE_STRING;
}
return DataType::TYPE_NUMERIC;
} elseif (is_string($value)) {
$errorCodes = DataType::getErrorCodes();
if (isset($errorCodes[$value])) {
return DataType::TYPE_ERROR;
}
}
return DataType::TYPE_STRING;
}
}
PK �8]��)�. . 7 phpspreadsheet/src/PhpSpreadsheet/Cell/IValueBinder.phpnu �[��� <?php
namespace PhpOffice\PhpSpreadsheet\Cell;
interface IValueBinder
{
/**
* Bind value to a cell.
*
* @param Cell $cell Cell to bind value to
* @param mixed $value Value to bind in cell
*
* @return bool
*/
public function bindValue(Cell $cell, $value);
}
PK �8]Q��~JR JR 5 phpspreadsheet/src/PhpSpreadsheet/Cell/Coordinate.phpnu �[��� <?php
namespace PhpOffice\PhpSpreadsheet\Cell;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Exception;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
/**
* Helper class to manipulate cell coordinates.
*
* Columns indexes and rows are always based on 1, **not** on 0. This match the behavior
* that Excel users are used to, and also match the Excel functions `COLUMN()` and `ROW()`.
*/
abstract class Coordinate
{
public const A1_COORDINATE_REGEX = '/^(?<col>\$?[A-Z]{1,3})(?<row>\$?\d{1,7})$/i';
/**
* Default range variable constant.
*
* @var string
*/
const DEFAULT_RANGE = 'A1:A1';
/**
* Convert string coordinate to [0 => int column index, 1 => int row index].
*
* @param string $cellAddress eg: 'A1'
*
* @return array{0: string, 1: string} Array containing column and row (indexes 0 and 1)
*/
public static function coordinateFromString($cellAddress): array
{
if (preg_match(self::A1_COORDINATE_REGEX, $cellAddress, $matches)) {
return [$matches['col'], $matches['row']];
} elseif (self::coordinateIsRange($cellAddress)) {
throw new Exception('Cell coordinate string can not be a range of cells');
} elseif ($cellAddress == '') {
throw new Exception('Cell coordinate can not be zero-length string');
}
throw new Exception('Invalid cell coordinate ' . $cellAddress);
}
/**
* Convert string coordinate to [0 => int column index, 1 => int row index, 2 => string column string].
*
* @param string $coordinates eg: 'A1', '$B$12'
*
* @return array{0: int, 1: int, 2: string} Array containing column and row index, and column string
*/
public static function indexesFromString(string $coordinates): array
{
[$column, $row] = self::coordinateFromString($coordinates);
$column = ltrim($column, '$');
return [
self::columnIndexFromString($column),
(int) ltrim($row, '$'),
$column,
];
}
/**
* Checks if a Cell Address represents a range of cells.
*
* @param string $cellAddress eg: 'A1' or 'A1:A2' or 'A1:A2,C1:C2'
*
* @return bool Whether the coordinate represents a range of cells
*/
public static function coordinateIsRange($cellAddress)
{
return (strpos($cellAddress, ':') !== false) || (strpos($cellAddress, ',') !== false);
}
/**
* Make string row, column or cell coordinate absolute.
*
* @param string $cellAddress e.g. 'A' or '1' or 'A1'
* Note that this value can be a row or column reference as well as a cell reference
*
* @return string Absolute coordinate e.g. '$A' or '$1' or '$A$1'
*/
public static function absoluteReference($cellAddress)
{
if (self::coordinateIsRange($cellAddress)) {
throw new Exception('Cell coordinate string can not be a range of cells');
}
// Split out any worksheet name from the reference
[$worksheet, $cellAddress] = Worksheet::extractSheetTitle($cellAddress, true);
if ($worksheet > '') {
$worksheet .= '!';
}
// Create absolute coordinate
$cellAddress = "$cellAddress";
if (ctype_digit($cellAddress)) {
return $worksheet . '$' . $cellAddress;
} elseif (ctype_alpha($cellAddress)) {
return $worksheet . '$' . strtoupper($cellAddress);
}
return $worksheet . self::absoluteCoordinate($cellAddress);
}
/**
* Make string coordinate absolute.
*
* @param string $cellAddress e.g. 'A1'
*
* @return string Absolute coordinate e.g. '$A$1'
*/
public static function absoluteCoordinate($cellAddress)
{
if (self::coordinateIsRange($cellAddress)) {
throw new Exception('Cell coordinate string can not be a range of cells');
}
// Split out any worksheet name from the coordinate
[$worksheet, $cellAddress] = Worksheet::extractSheetTitle($cellAddress, true);
if ($worksheet > '') {
$worksheet .= '!';
}
// Create absolute coordinate
[$column, $row] = self::coordinateFromString($cellAddress);
$column = ltrim($column, '$');
$row = ltrim($row, '$');
return $worksheet . '$' . $column . '$' . $row;
}
/**
* Split range into coordinate strings.
*
* @param string $range e.g. 'B4:D9' or 'B4:D9,H2:O11' or 'B4'
*
* @return array Array containing one or more arrays containing one or two coordinate strings
* e.g. ['B4','D9'] or [['B4','D9'], ['H2','O11']]
* or ['B4']
*/
public static function splitRange($range)
{
// Ensure $pRange is a valid range
if (empty($range)) {
$range = self::DEFAULT_RANGE;
}
$exploded = explode(',', $range);
$counter = count($exploded);
for ($i = 0; $i < $counter; ++$i) {
// @phpstan-ignore-next-line
$exploded[$i] = explode(':', $exploded[$i]);
}
return $exploded;
}
/**
* Build range from coordinate strings.
*
* @param array $range Array containing one or more arrays containing one or two coordinate strings
*
* @return string String representation of $pRange
*/
public static function buildRange(array $range)
{
// Verify range
if (empty($range) || !is_array($range[0])) {
throw new Exception('Range does not contain any information');
}
// Build range
$counter = count($range);
for ($i = 0; $i < $counter; ++$i) {
$range[$i] = implode(':', $range[$i]);
}
return implode(',', $range);
}
/**
* Calculate range boundaries.
*
* @param string $range Cell range, Single Cell, Row/Column Range (e.g. A1:A1, B2, B:C, 2:3)
*
* @return array Range coordinates [Start Cell, End Cell]
* where Start Cell and End Cell are arrays (Column Number, Row Number)
*/
public static function rangeBoundaries(string $range): array
{
// Ensure $pRange is a valid range
if (empty($range)) {
$range = self::DEFAULT_RANGE;
}
// Uppercase coordinate
$range = strtoupper($range);
// Extract range
if (strpos($range, ':') === false) {
$rangeA = $rangeB = $range;
} else {
[$rangeA, $rangeB] = explode(':', $range);
}
if (is_numeric($rangeA) && is_numeric($rangeB)) {
$rangeA = 'A' . $rangeA;
$rangeB = AddressRange::MAX_COLUMN . $rangeB;
}
if (ctype_alpha($rangeA) && ctype_alpha($rangeB)) {
$rangeA = $rangeA . '1';
$rangeB = $rangeB . AddressRange::MAX_ROW;
}
// Calculate range outer borders
$rangeStart = self::coordinateFromString($rangeA);
$rangeEnd = self::coordinateFromString($rangeB);
// Translate column into index
$rangeStart[0] = self::columnIndexFromString($rangeStart[0]);
$rangeEnd[0] = self::columnIndexFromString($rangeEnd[0]);
return [$rangeStart, $rangeEnd];
}
/**
* Calculate range dimension.
*
* @param string $range Cell range, Single Cell, Row/Column Range (e.g. A1:A1, B2, B:C, 2:3)
*
* @return array Range dimension (width, height)
*/
public static function rangeDimension($range)
{
// Calculate range outer borders
[$rangeStart, $rangeEnd] = self::rangeBoundaries($range);
return [($rangeEnd[0] - $rangeStart[0] + 1), ($rangeEnd[1] - $rangeStart[1] + 1)];
}
/**
* Calculate range boundaries.
*
* @param string $range Cell range, Single Cell, Row/Column Range (e.g. A1:A1, B2, B:C, 2:3)
*
* @return array Range coordinates [Start Cell, End Cell]
* where Start Cell and End Cell are arrays [Column ID, Row Number]
*/
public static function getRangeBoundaries($range)
{
[$rangeA, $rangeB] = self::rangeBoundaries($range);
return [
[self::stringFromColumnIndex($rangeA[0]), $rangeA[1]],
[self::stringFromColumnIndex($rangeB[0]), $rangeB[1]],
];
}
/**
* Column index from string.
*
* @param ?string $columnAddress eg 'A'
*
* @return int Column index (A = 1)
*/
public static function columnIndexFromString($columnAddress)
{
// Using a lookup cache adds a slight memory overhead, but boosts speed
// caching using a static within the method is faster than a class static,
// though it's additional memory overhead
static $indexCache = [];
$columnAddress = $columnAddress ?? '';
if (isset($indexCache[$columnAddress])) {
return $indexCache[$columnAddress];
}
// It's surprising how costly the strtoupper() and ord() calls actually are, so we use a lookup array
// rather than use ord() and make it case insensitive to get rid of the strtoupper() as well.
// Because it's a static, there's no significant memory overhead either.
static $columnLookup = [
'A' => 1, 'B' => 2, 'C' => 3, 'D' => 4, 'E' => 5, 'F' => 6, 'G' => 7, 'H' => 8, 'I' => 9, 'J' => 10,
'K' => 11, 'L' => 12, 'M' => 13, 'N' => 14, 'O' => 15, 'P' => 16, 'Q' => 17, 'R' => 18, 'S' => 19,
'T' => 20, 'U' => 21, 'V' => 22, 'W' => 23, 'X' => 24, 'Y' => 25, 'Z' => 26,
'a' => 1, 'b' => 2, 'c' => 3, 'd' => 4, 'e' => 5, 'f' => 6, 'g' => 7, 'h' => 8, 'i' => 9, 'j' => 10,
'k' => 11, 'l' => 12, 'm' => 13, 'n' => 14, 'o' => 15, 'p' => 16, 'q' => 17, 'r' => 18, 's' => 19,
't' => 20, 'u' => 21, 'v' => 22, 'w' => 23, 'x' => 24, 'y' => 25, 'z' => 26,
];
// We also use the language construct isset() rather than the more costly strlen() function to match the
// length of $columnAddress for improved performance
if (isset($columnAddress[0])) {
if (!isset($columnAddress[1])) {
$indexCache[$columnAddress] = $columnLookup[$columnAddress];
return $indexCache[$columnAddress];
} elseif (!isset($columnAddress[2])) {
$indexCache[$columnAddress] = $columnLookup[$columnAddress[0]] * 26
+ $columnLookup[$columnAddress[1]];
return $indexCache[$columnAddress];
} elseif (!isset($columnAddress[3])) {
$indexCache[$columnAddress] = $columnLookup[$columnAddress[0]] * 676
+ $columnLookup[$columnAddress[1]] * 26
+ $columnLookup[$columnAddress[2]];
return $indexCache[$columnAddress];
}
}
throw new Exception(
'Column string index can not be ' . ((isset($columnAddress[0])) ? 'longer than 3 characters' : 'empty')
);
}
/**
* String from column index.
*
* @param int $columnIndex Column index (A = 1)
*
* @return string
*/
public static function stringFromColumnIndex($columnIndex)
{
static $indexCache = [];
static $lookupCache = ' ABCDEFGHIJKLMNOPQRSTUVWXYZ';
if (!isset($indexCache[$columnIndex])) {
$indexValue = $columnIndex;
$base26 = '';
do {
$characterValue = ($indexValue % 26) ?: 26;
$indexValue = ($indexValue - $characterValue) / 26;
$base26 = $lookupCache[$characterValue] . $base26;
} while ($indexValue > 0);
$indexCache[$columnIndex] = $base26;
}
return $indexCache[$columnIndex];
}
/**
* Extract all cell references in range, which may be comprised of multiple cell ranges.
*
* @param string $cellRange Range: e.g. 'A1' or 'A1:C10' or 'A1:E10,A20:E25' or 'A1:E5 C3:G7' or 'A1:C1,A3:C3 B1:C3'
*
* @return array Array containing single cell references
*/
public static function extractAllCellReferencesInRange($cellRange): array
{
if (substr_count($cellRange, '!') > 1) {
throw new Exception('3-D Range References are not supported');
}
[$worksheet, $cellRange] = Worksheet::extractSheetTitle($cellRange, true);
$quoted = '';
if ($worksheet > '') {
$quoted = Worksheet::nameRequiresQuotes($worksheet) ? "'" : '';
if (substr($worksheet, 0, 1) === "'" && substr($worksheet, -1, 1) === "'") {
$worksheet = substr($worksheet, 1, -1);
}
$worksheet = str_replace("'", "''", $worksheet);
}
[$ranges, $operators] = self::getCellBlocksFromRangeString($cellRange);
$cells = [];
foreach ($ranges as $range) {
$cells[] = self::getReferencesForCellBlock($range);
}
$cells = self::processRangeSetOperators($operators, $cells);
if (empty($cells)) {
return [];
}
$cellList = array_merge(...$cells);
return array_map(
function ($cellAddress) use ($worksheet, $quoted) {
return ($worksheet !== '') ? "{$quoted}{$worksheet}{$quoted}!{$cellAddress}" : $cellAddress;
},
self::sortCellReferenceArray($cellList)
);
}
private static function processRangeSetOperators(array $operators, array $cells): array
{
$operatorCount = count($operators);
for ($offset = 0; $offset < $operatorCount; ++$offset) {
$operator = $operators[$offset];
if ($operator !== ' ') {
continue;
}
$cells[$offset] = array_intersect($cells[$offset], $cells[$offset + 1]);
unset($operators[$offset], $cells[$offset + 1]);
$operators = array_values($operators);
$cells = array_values($cells);
--$offset;
--$operatorCount;
}
return $cells;
}
private static function sortCellReferenceArray(array $cellList): array
{
// Sort the result by column and row
$sortKeys = [];
foreach ($cellList as $coordinate) {
$column = '';
$row = 0;
sscanf($coordinate, '%[A-Z]%d', $column, $row);
$key = (--$row * 16384) + self::columnIndexFromString((string) $column);
$sortKeys[$key] = $coordinate;
}
ksort($sortKeys);
return array_values($sortKeys);
}
/**
* Get all cell references for an individual cell block.
*
* @param string $cellBlock A cell range e.g. A4:B5
*
* @return array All individual cells in that range
*/
private static function getReferencesForCellBlock($cellBlock)
{
$returnValue = [];
// Single cell?
if (!self::coordinateIsRange($cellBlock)) {
return (array) $cellBlock;
}
// Range...
$ranges = self::splitRange($cellBlock);
foreach ($ranges as $range) {
// Single cell?
if (!isset($range[1])) {
$returnValue[] = $range[0];
continue;
}
// Range...
[$rangeStart, $rangeEnd] = $range;
[$startColumn, $startRow] = self::coordinateFromString($rangeStart);
[$endColumn, $endRow] = self::coordinateFromString($rangeEnd);
$startColumnIndex = self::columnIndexFromString($startColumn);
$endColumnIndex = self::columnIndexFromString($endColumn);
++$endColumnIndex;
// Current data
$currentColumnIndex = $startColumnIndex;
$currentRow = $startRow;
self::validateRange($cellBlock, $startColumnIndex, $endColumnIndex, (int) $currentRow, (int) $endRow);
// Loop cells
while ($currentColumnIndex < $endColumnIndex) {
while ($currentRow <= $endRow) {
$returnValue[] = self::stringFromColumnIndex($currentColumnIndex) . $currentRow;
++$currentRow;
}
++$currentColumnIndex;
$currentRow = $startRow;
}
}
return $returnValue;
}
/**
* Convert an associative array of single cell coordinates to values to an associative array
* of cell ranges to values. Only adjacent cell coordinates with the same
* value will be merged. If the value is an object, it must implement the method getHashCode().
*
* For example, this function converts:
*
* [ 'A1' => 'x', 'A2' => 'x', 'A3' => 'x', 'A4' => 'y' ]
*
* to:
*
* [ 'A1:A3' => 'x', 'A4' => 'y' ]
*
* @param array $coordinateCollection associative array mapping coordinates to values
*
* @return array associative array mapping coordinate ranges to valuea
*/
public static function mergeRangesInCollection(array $coordinateCollection)
{
$hashedValues = [];
$mergedCoordCollection = [];
foreach ($coordinateCollection as $coord => $value) {
if (self::coordinateIsRange($coord)) {
$mergedCoordCollection[$coord] = $value;
continue;
}
[$column, $row] = self::coordinateFromString($coord);
$row = (int) (ltrim($row, '$'));
$hashCode = $column . '-' . ((is_object($value) && method_exists($value, 'getHashCode')) ? $value->getHashCode() : $value);
if (!isset($hashedValues[$hashCode])) {
$hashedValues[$hashCode] = (object) [
'value' => $value,
'col' => $column,
'rows' => [$row],
];
} else {
$hashedValues[$hashCode]->rows[] = $row;
}
}
ksort($hashedValues);
foreach ($hashedValues as $hashedValue) {
sort($hashedValue->rows);
$rowStart = null;
$rowEnd = null;
$ranges = [];
foreach ($hashedValue->rows as $row) {
if ($rowStart === null) {
$rowStart = $row;
$rowEnd = $row;
} elseif ($rowEnd === $row - 1) {
$rowEnd = $row;
} else {
if ($rowStart == $rowEnd) {
$ranges[] = $hashedValue->col . $rowStart;
} else {
$ranges[] = $hashedValue->col . $rowStart . ':' . $hashedValue->col . $rowEnd;
}
$rowStart = $row;
$rowEnd = $row;
}
}
if ($rowStart !== null) {
if ($rowStart == $rowEnd) {
$ranges[] = $hashedValue->col . $rowStart;
} else {
$ranges[] = $hashedValue->col . $rowStart . ':' . $hashedValue->col . $rowEnd;
}
}
foreach ($ranges as $range) {
$mergedCoordCollection[$range] = $hashedValue->value;
}
}
return $mergedCoordCollection;
}
/**
* Get the individual cell blocks from a range string, removing any $ characters.
* then splitting by operators and returning an array with ranges and operators.
*
* @param string $rangeString
*
* @return array[]
*/
private static function getCellBlocksFromRangeString($rangeString)
{
$rangeString = str_replace('$', '', strtoupper($rangeString));
// split range sets on intersection (space) or union (,) operators
$tokens = preg_split('/([ ,])/', $rangeString, -1, PREG_SPLIT_DELIM_CAPTURE);
/** @phpstan-ignore-next-line */
$split = array_chunk($tokens, 2);
$ranges = array_column($split, 0);
$operators = array_column($split, 1);
return [$ranges, $operators];
}
/**
* Check that the given range is valid, i.e. that the start column and row are not greater than the end column and
* row.
*
* @param string $cellBlock The original range, for displaying a meaningful error message
* @param int $startColumnIndex
* @param int $endColumnIndex
* @param int $currentRow
* @param int $endRow
*/
private static function validateRange($cellBlock, $startColumnIndex, $endColumnIndex, $currentRow, $endRow): void
{
if ($startColumnIndex >= $endColumnIndex || $currentRow > $endRow) {
throw new Exception('Invalid range: "' . $cellBlock . '"');
}
}
}
PK �8]f�F� 6 phpspreadsheet/src/PhpSpreadsheet/Cell/CellAddress.phpnu �[��� <?php
namespace PhpOffice\PhpSpreadsheet\Cell;
use PhpOffice\PhpSpreadsheet\Exception;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
class CellAddress
{
/**
* @var ?Worksheet
*/
protected $worksheet;
/**
* @var string
*/
protected $cellAddress;
/**
* @var string
*/
protected $columnName;
/**
* @var int
*/
protected $columnId;
/**
* @var int
*/
protected $rowId;
public function __construct(string $cellAddress, ?Worksheet $worksheet = null)
{
$this->cellAddress = str_replace('$', '', $cellAddress);
[$this->columnId, $this->rowId, $this->columnName] = Coordinate::indexesFromString($this->cellAddress);
$this->worksheet = $worksheet;
}
/**
* @param mixed $columnId
* @param mixed $rowId
*/
private static function validateColumnAndRow($columnId, $rowId): void
{
if (!is_numeric($columnId) || $columnId <= 0 || !is_numeric($rowId) || $rowId <= 0) {
throw new Exception('Row and Column Ids must be positive integer values');
}
}
/**
* @param mixed $columnId
* @param mixed $rowId
*/
public static function fromColumnAndRow($columnId, $rowId, ?Worksheet $worksheet = null): self
{
self::validateColumnAndRow($columnId, $rowId);
/** @phpstan-ignore-next-line */
return new static(Coordinate::stringFromColumnIndex($columnId) . ((string) $rowId), $worksheet);
}
public static function fromColumnRowArray(array $array, ?Worksheet $worksheet = null): self
{
[$columnId, $rowId] = $array;
return static::fromColumnAndRow($columnId, $rowId, $worksheet);
}
/**
* @param mixed $cellAddress
*/
public static function fromCellAddress($cellAddress, ?Worksheet $worksheet = null): self
{
/** @phpstan-ignore-next-line */
return new static($cellAddress, $worksheet);
}
/**
* The returned address string will contain the worksheet name as well, if available,
* (ie. if a Worksheet was provided to the constructor).
* e.g. "'Mark''s Worksheet'!C5".
*/
public function fullCellAddress(): string
{
if ($this->worksheet !== null) {
$title = str_replace("'", "''", $this->worksheet->getTitle());
return "'{$title}'!{$this->cellAddress}";
}
return $this->cellAddress;
}
public function worksheet(): ?Worksheet
{
return $this->worksheet;
}
/**
* The returned address string will contain just the column/row address,
* (even if a Worksheet was provided to the constructor).
* e.g. "C5".
*/
public function cellAddress(): string
{
return $this->cellAddress;
}
public function rowId(): int
{
return $this->rowId;
}
public function columnId(): int
{
return $this->columnId;
}
public function columnName(): string
{
return $this->columnName;
}
public function nextRow(int $offset = 1): self
{
$newRowId = $this->rowId + $offset;
if ($newRowId < 1) {
$newRowId = 1;
}
return static::fromColumnAndRow($this->columnId, $newRowId);
}
public function previousRow(int $offset = 1): self
{
return $this->nextRow(0 - $offset);
}
public function nextColumn(int $offset = 1): self
{
$newColumnId = $this->columnId + $offset;
if ($newColumnId < 1) {
$newColumnId = 1;
}
return static::fromColumnAndRow($newColumnId, $this->rowId);
}
public function previousColumn(int $offset = 1): self
{
return $this->nextColumn(0 - $offset);
}
/**
* The returned address string will contain the worksheet name as well, if available,
* (ie. if a Worksheet was provided to the constructor).
* e.g. "'Mark''s Worksheet'!C5".
*/
public function __toString()
{
return $this->fullCellAddress();
}
}
PK �8]��(! (! 9 phpspreadsheet/src/PhpSpreadsheet/Cell/DataValidation.phpnu �[��� <?php
namespace PhpOffice\PhpSpreadsheet\Cell;
class DataValidation
{
// Data validation types
const TYPE_NONE = 'none';
const TYPE_CUSTOM = 'custom';
const TYPE_DATE = 'date';
const TYPE_DECIMAL = 'decimal';
const TYPE_LIST = 'list';
const TYPE_TEXTLENGTH = 'textLength';
const TYPE_TIME = 'time';
const TYPE_WHOLE = 'whole';
// Data validation error styles
const STYLE_STOP = 'stop';
const STYLE_WARNING = 'warning';
const STYLE_INFORMATION = 'information';
// Data validation operators
const OPERATOR_BETWEEN = 'between';
const OPERATOR_EQUAL = 'equal';
const OPERATOR_GREATERTHAN = 'greaterThan';
const OPERATOR_GREATERTHANOREQUAL = 'greaterThanOrEqual';
const OPERATOR_LESSTHAN = 'lessThan';
const OPERATOR_LESSTHANOREQUAL = 'lessThanOrEqual';
const OPERATOR_NOTBETWEEN = 'notBetween';
const OPERATOR_NOTEQUAL = 'notEqual';
/**
* Formula 1.
*
* @var string
*/
private $formula1 = '';
/**
* Formula 2.
*
* @var string
*/
private $formula2 = '';
/**
* Type.
*
* @var string
*/
private $type = self::TYPE_NONE;
/**
* Error style.
*
* @var string
*/
private $errorStyle = self::STYLE_STOP;
/**
* Operator.
*
* @var string
*/
private $operator = self::OPERATOR_BETWEEN;
/**
* Allow Blank.
*
* @var bool
*/
private $allowBlank = false;
/**
* Show DropDown.
*
* @var bool
*/
private $showDropDown = false;
/**
* Show InputMessage.
*
* @var bool
*/
private $showInputMessage = false;
/**
* Show ErrorMessage.
*
* @var bool
*/
private $showErrorMessage = false;
/**
* Error title.
*
* @var string
*/
private $errorTitle = '';
/**
* Error.
*
* @var string
*/
private $error = '';
/**
* Prompt title.
*
* @var string
*/
private $promptTitle = '';
/**
* Prompt.
*
* @var string
*/
private $prompt = '';
/**
* Create a new DataValidation.
*/
public function __construct()
{
}
/**
* Get Formula 1.
*
* @return string
*/
public function getFormula1()
{
return $this->formula1;
}
/**
* Set Formula 1.
*
* @param string $formula
*
* @return $this
*/
public function setFormula1($formula)
{
$this->formula1 = $formula;
return $this;
}
/**
* Get Formula 2.
*
* @return string
*/
public function getFormula2()
{
return $this->formula2;
}
/**
* Set Formula 2.
*
* @param string $formula
*
* @return $this
*/
public function setFormula2($formula)
{
$this->formula2 = $formula;
return $this;
}
/**
* Get Type.
*
* @return string
*/
public function getType()
{
return $this->type;
}
/**
* Set Type.
*
* @param string $type
*
* @return $this
*/
public function setType($type)
{
$this->type = $type;
return $this;
}
/**
* Get Error style.
*
* @return string
*/
public function getErrorStyle()
{
return $this->errorStyle;
}
/**
* Set Error style.
*
* @param string $errorStyle see self::STYLE_*
*
* @return $this
*/
public function setErrorStyle($errorStyle)
{
$this->errorStyle = $errorStyle;
return $this;
}
/**
* Get Operator.
*
* @return string
*/
public function getOperator()
{
return $this->operator;
}
/**
* Set Operator.
*
* @param string $operator
*
* @return $this
*/
public function setOperator($operator)
{
$this->operator = $operator;
return $this;
}
/**
* Get Allow Blank.
*
* @return bool
*/
public function getAllowBlank()
{
return $this->allowBlank;
}
/**
* Set Allow Blank.
*
* @param bool $allowBlank
*
* @return $this
*/
public function setAllowBlank($allowBlank)
{
$this->allowBlank = $allowBlank;
return $this;
}
/**
* Get Show DropDown.
*
* @return bool
*/
public function getShowDropDown()
{
return $this->showDropDown;
}
/**
* Set Show DropDown.
*
* @param bool $showDropDown
*
* @return $this
*/
public function setShowDropDown($showDropDown)
{
$this->showDropDown = $showDropDown;
return $this;
}
/**
* Get Show InputMessage.
*
* @return bool
*/
public function getShowInputMessage()
{
return $this->showInputMessage;
}
/**
* Set Show InputMessage.
*
* @param bool $showInputMessage
*
* @return $this
*/
public function setShowInputMessage($showInputMessage)
{
$this->showInputMessage = $showInputMessage;
return $this;
}
/**
* Get Show ErrorMessage.
*
* @return bool
*/
public function getShowErrorMessage()
{
return $this->showErrorMessage;
}
/**
* Set Show ErrorMessage.
*
* @param bool $showErrorMessage
*
* @return $this
*/
public function setShowErrorMessage($showErrorMessage)
{
$this->showErrorMessage = $showErrorMessage;
return $this;
}
/**
* Get Error title.
*
* @return string
*/
public function getErrorTitle()
{
return $this->errorTitle;
}
/**
* Set Error title.
*
* @param string $errorTitle
*
* @return $this
*/
public function setErrorTitle($errorTitle)
{
$this->errorTitle = $errorTitle;
return $this;
}
/**
* Get Error.
*
* @return string
*/
public function getError()
{
return $this->error;
}
/**
* Set Error.
*
* @param string $error
*
* @return $this
*/
public function setError($error)
{
$this->error = $error;
return $this;
}
/**
* Get Prompt title.
*
* @return string
*/
public function getPromptTitle()
{
return $this->promptTitle;
}
/**
* Set Prompt title.
*
* @param string $promptTitle
*
* @return $this
*/
public function setPromptTitle($promptTitle)
{
$this->promptTitle = $promptTitle;
return $this;
}
/**
* Get Prompt.
*
* @return string
*/
public function getPrompt()
{
return $this->prompt;
}
/**
* Set Prompt.
*
* @param string $prompt
*
* @return $this
*/
public function setPrompt($prompt)
{
$this->prompt = $prompt;
return $this;
}
/**
* Get hash code.
*
* @return string Hash code
*/
public function getHashCode()
{
return md5(
$this->formula1 .
$this->formula2 .
$this->type .
$this->errorStyle .
$this->operator .
($this->allowBlank ? 't' : 'f') .
($this->showDropDown ? 't' : 'f') .
($this->showInputMessage ? 't' : 'f') .
($this->showErrorMessage ? 't' : 'f') .
$this->errorTitle .
$this->error .
$this->promptTitle .
$this->prompt .
$this->sqref .
__CLASS__
);
}
/**
* Implement PHP __clone to create a deep clone, not just a shallow copy.
*/
public function __clone()
{
$vars = get_object_vars($this);
foreach ($vars as $key => $value) {
if (is_object($value)) {
$this->$key = clone $value;
} else {
$this->$key = $value;
}
}
}
/** @var ?string */
private $sqref;
public function getSqref(): ?string
{
return $this->sqref;
}
public function setSqref(?string $str): self
{
$this->sqref = $str;
return $this;
}
}
PK �8]��K�R R 8 phpspreadsheet/src/PhpSpreadsheet/Cell/AddressHelper.phpnu �[��� <?php
namespace PhpOffice\PhpSpreadsheet\Cell;
use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Exception;
class AddressHelper
{
public const R1C1_COORDINATE_REGEX = '/(R((?:\[-?\d*\])|(?:\d*))?)(C((?:\[-?\d*\])|(?:\d*))?)/i';
/** @return string[] */
public static function getRowAndColumnChars()
{
$rowChar = 'R';
$colChar = 'C';
if (Functions::getCompatibilityMode() === Functions::COMPATIBILITY_EXCEL) {
$rowColChars = Calculation::localeFunc('*RC');
if (mb_strlen($rowColChars) === 2) {
$rowChar = mb_substr($rowColChars, 0, 1);
$colChar = mb_substr($rowColChars, 1, 1);
}
}
return [$rowChar, $colChar];
}
/**
* Converts an R1C1 format cell address to an A1 format cell address.
*/
public static function convertToA1(
string $address,
int $currentRowNumber = 1,
int $currentColumnNumber = 1,
bool $useLocale = true
): string {
[$rowChar, $colChar] = $useLocale ? self::getRowAndColumnChars() : ['R', 'C'];
$regex = '/^(' . $rowChar . '(\[?[-+]?\d*\]?))(' . $colChar . '(\[?[-+]?\d*\]?))$/i';
$validityCheck = preg_match($regex, $address, $cellReference);
if (empty($validityCheck)) {
throw new Exception('Invalid R1C1-format Cell Reference');
}
$rowReference = $cellReference[2];
// Empty R reference is the current row
if ($rowReference === '') {
$rowReference = (string) $currentRowNumber;
}
// Bracketed R references are relative to the current row
if ($rowReference[0] === '[') {
$rowReference = $currentRowNumber + (int) trim($rowReference, '[]');
}
$columnReference = $cellReference[4];
// Empty C reference is the current column
if ($columnReference === '') {
$columnReference = (string) $currentColumnNumber;
}
// Bracketed C references are relative to the current column
if (is_string($columnReference) && $columnReference[0] === '[') {
$columnReference = $currentColumnNumber + (int) trim($columnReference, '[]');
}
$columnReference = (int) $columnReference;
if ($columnReference <= 0 || $rowReference <= 0) {
throw new Exception('Invalid R1C1-format Cell Reference, Value out of range');
}
$A1CellReference = Coordinate::stringFromColumnIndex($columnReference) . $rowReference;
return $A1CellReference;
}
protected static function convertSpreadsheetMLFormula(string $formula): string
{
$formula = substr($formula, 3);
$temp = explode('"', $formula);
$key = false;
foreach ($temp as &$value) {
// Only replace in alternate array entries (i.e. non-quoted blocks)
$key = $key === false;
if ($key) {
$value = str_replace(['[.', ':.', ']'], ['', ':', ''], $value);
}
}
unset($value);
return implode('"', $temp);
}
/**
* Converts a formula that uses R1C1/SpreadsheetXML format cell address to an A1 format cell address.
*/
public static function convertFormulaToA1(
string $formula,
int $currentRowNumber = 1,
int $currentColumnNumber = 1
): string {
if (substr($formula, 0, 3) == 'of:') {
// We have an old-style SpreadsheetML Formula
return self::convertSpreadsheetMLFormula($formula);
}
// Convert R1C1 style references to A1 style references (but only when not quoted)
$temp = explode('"', $formula);
$key = false;
foreach ($temp as &$value) {
// Only replace in alternate array entries (i.e. non-quoted blocks)
$key = $key === false;
if ($key) {
preg_match_all(self::R1C1_COORDINATE_REGEX, $value, $cellReferences, PREG_SET_ORDER + PREG_OFFSET_CAPTURE);
// Reverse the matches array, otherwise all our offsets will become incorrect if we modify our way
// through the formula from left to right. Reversing means that we work right to left.through
// the formula
$cellReferences = array_reverse($cellReferences);
// Loop through each R1C1 style reference in turn, converting it to its A1 style equivalent,
// then modify the formula to use that new reference
foreach ($cellReferences as $cellReference) {
$A1CellReference = self::convertToA1($cellReference[0][0], $currentRowNumber, $currentColumnNumber, false);
$value = substr_replace($value, $A1CellReference, $cellReference[0][1], strlen($cellReference[0][0]));
}
}
}
unset($value);
// Then rebuild the formula string
return implode('"', $temp);
}
/**
* Converts an A1 format cell address to an R1C1 format cell address.
* If $currentRowNumber or $currentColumnNumber are provided, then the R1C1 address will be formatted as a relative address.
*/
public static function convertToR1C1(
string $address,
?int $currentRowNumber = null,
?int $currentColumnNumber = null
): string {
$validityCheck = preg_match(Coordinate::A1_COORDINATE_REGEX, $address, $cellReference);
if ($validityCheck === 0) {
throw new Exception('Invalid A1-format Cell Reference');
}
if ($cellReference['col'][0] === '$') {
// Column must be absolute address
$currentColumnNumber = null;
}
$columnId = Coordinate::columnIndexFromString(ltrim($cellReference['col'], '$'));
if ($cellReference['row'][0] === '$') {
// Row must be absolute address
$currentRowNumber = null;
}
$rowId = (int) ltrim($cellReference['row'], '$');
if ($currentRowNumber !== null) {
if ($rowId === $currentRowNumber) {
$rowId = '';
} else {
$rowId = '[' . ($rowId - $currentRowNumber) . ']';
}
}
if ($currentColumnNumber !== null) {
if ($columnId === $currentColumnNumber) {
$columnId = '';
} else {
$columnId = '[' . ($columnId - $currentColumnNumber) . ']';
}
}
$R1C1Address = "R{$rowId}C{$columnId}";
return $R1C1Address;
}
}
PK �8]G�� � 8 phpspreadsheet/src/PhpSpreadsheet/Cell/IgnoredErrors.phpnu �[��� <?php
namespace PhpOffice\PhpSpreadsheet\Cell;
class IgnoredErrors
{
/** @var bool */
private $numberStoredAsText = false;
/** @var bool */
private $formula = false;
/** @var bool */
private $twoDigitTextYear = false;
/** @var bool */
private $evalError = false;
public function setNumberStoredAsText(bool $value): self
{
$this->numberStoredAsText = $value;
return $this;
}
public function getNumberStoredAsText(): bool
{
return $this->numberStoredAsText;
}
public function setFormula(bool $value): self
{
$this->formula = $value;
return $this;
}
public function getFormula(): bool
{
return $this->formula;
}
public function setTwoDigitTextYear(bool $value): self
{
$this->twoDigitTextYear = $value;
return $this;
}
public function getTwoDigitTextYear(): bool
{
return $this->twoDigitTextYear;
}
public function setEvalError(bool $value): self
{
$this->evalError = $value;
return $this;
}
public function getEvalError(): bool
{
return $this->evalError;
}
}
PK �8]Mx�@ 6 phpspreadsheet/src/PhpSpreadsheet/Cell/ColumnRange.phpnu �[��� <?php
namespace PhpOffice\PhpSpreadsheet\Cell;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
class ColumnRange implements AddressRange
{
/**
* @var ?Worksheet
*/
protected $worksheet;
/**
* @var int
*/
protected $from;
/**
* @var int
*/
protected $to;
public function __construct(string $from, ?string $to = null, ?Worksheet $worksheet = null)
{
$this->validateFromTo(
Coordinate::columnIndexFromString($from),
Coordinate::columnIndexFromString($to ?? $from)
);
$this->worksheet = $worksheet;
}
public static function fromColumnIndexes(int $from, int $to, ?Worksheet $worksheet = null): self
{
return new self(Coordinate::stringFromColumnIndex($from), Coordinate::stringFromColumnIndex($to), $worksheet);
}
/**
* @param array<int|string> $array
*/
public static function fromArray(array $array, ?Worksheet $worksheet = null): self
{
array_walk(
$array,
function (&$column): void {
$column = is_numeric($column) ? Coordinate::stringFromColumnIndex((int) $column) : $column;
}
);
/** @var string $from */
/** @var string $to */
[$from, $to] = $array;
return new self($from, $to, $worksheet);
}
private function validateFromTo(int $from, int $to): void
{
// Identify actual top and bottom values (in case we've been given bottom and top)
$this->from = min($from, $to);
$this->to = max($from, $to);
}
public function columnCount(): int
{
return $this->to - $this->from + 1;
}
public function shiftDown(int $offset = 1): self
{
$newFrom = $this->from + $offset;
$newFrom = ($newFrom < 1) ? 1 : $newFrom;
$newTo = $this->to + $offset;
$newTo = ($newTo < 1) ? 1 : $newTo;
return self::fromColumnIndexes($newFrom, $newTo, $this->worksheet);
}
public function shiftUp(int $offset = 1): self
{
return $this->shiftDown(0 - $offset);
}
public function from(): string
{
return Coordinate::stringFromColumnIndex($this->from);
}
public function to(): string
{
return Coordinate::stringFromColumnIndex($this->to);
}
public function fromIndex(): int
{
return $this->from;
}
public function toIndex(): int
{
return $this->to;
}
public function toCellRange(): CellRange
{
return new CellRange(
CellAddress::fromColumnAndRow($this->from, 1, $this->worksheet),
CellAddress::fromColumnAndRow($this->to, AddressRange::MAX_ROW)
);
}
public function __toString(): string
{
$from = $this->from();
$to = $this->to();
if ($this->worksheet !== null) {
$title = str_replace("'", "''", $this->worksheet->getTitle());
return "'{$title}'!{$from}:{$to}";
}
return "{$from}:{$to}";
}
}
PK �8]�4��m m 7 phpspreadsheet/src/PhpSpreadsheet/Cell/AddressRange.phpnu �[��� <?php
namespace PhpOffice\PhpSpreadsheet\Cell;
interface AddressRange
{
public const MAX_ROW = 1048576;
public const MAX_COLUMN = 'XFD';
public const MAX_COLUMN_INT = 16384;
/**
* @return mixed
*/
public function from();
/**
* @return mixed
*/
public function to();
public function __toString(): string;
}
PK �8],�_�
�
<