fjffk简�的咖啡店科开�2方法2
环æ»�皆山也。其西å�—诸峰,林壑尤美,望之蔚然而深秀者,ç�…ç�Šä¹Ÿã€‚山行å…七里,æ¸�闻水声潺潺,而泻出于两峰之间者,酿泉也
???????????????????????????????
??????????????/?????????????????
............/...................
.........................../...
???????????????????????????????
>>>>>>>>>>>>>/>>>>>>>>>>>>>>>>>
ÿØÿà JFIF ÿÛ „ ( %!1!%)+//.383,7(-.+
-%%-////---/-.+/--+------/------/--0+--/-/-----.-----ÿÀ ¥2" ÿÄ ÿÄ J ! 1AQ"aq�2‘#BR‚¡�Ñ3br’¢±Âð$CSƒ²á4c“%DsÓñÿÄ ÿÄ * !1AQa‘"2q3�±ð#b¡ÿÚ ? ¼QxJQa�uò¸Zö Úü8,�Úú
"SSn<rçù–´âE—^ªBÖ9À\†¸Â�ÔÂ�Ã�TÂÃÛ5
ëd´³Ã�#Ã�;Þ38ϔÂ� ¶H£M:wÃŽ3…³…âpÔF&‚FK¸9„â4à GEõªfÂ�ÿ ‘ñ(ßwÂpŽF|È¥ù®häðÃ�Ѷ¹‘[Ã’inÙW¶ùñYËœQ{›K"išÒ[Ú8žë\F¹@-?v"ÔUâ€�,ìöžkÿ {I‡£šÃ�?e
rÂ�ÃV
?>
.........................................
.............................................................................
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
>>>>>>>>>>>>>/>>>>>>>>>>>>>>>>>>
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
dsdfphpspreadsheet/LICENSE 0000644 00000002074 15266563261 0010607 0 ustar 00 MIT License
Copyright (c) 2019-2025 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.
phpspreadsheet/README.md 0000644 00000007246 15266563261 0011067 0 ustar 00 # PhpSpreadsheet
[](https://github.com/PHPOffice/PhpSpreadsheet/actions)
[](https://scrutinizer-ci.com/g/PHPOffice/PhpSpreadsheet/?branch=master)
[](https://scrutinizer-ci.com/g/PHPOffice/PhpSpreadsheet/?branch=master)
[](https://packagist.org/packages/phpoffice/phpspreadsheet)
[](https://packagist.org/packages/phpoffice/phpspreadsheet)
[](https://packagist.org/packages/phpoffice/phpspreadsheet)
[](https://gitter.im/PHPOffice/PhpSpreadsheet)
PhpSpreadsheet is a library written in pure PHP and offers a set of classes that
allow you to read and write various spreadsheet file formats such as Excel and LibreOffice Calc.
## Installation
See the [install instructions](https://phpspreadsheet.readthedocs.io/en/latest/#installation).
## Documentation
Read more about it, including install instructions, in the [official documentation](https://phpspreadsheet.readthedocs.io). Or check out the [API documentation](https://phpoffice.github.io/PhpSpreadsheet).
Please ask your support questions on [StackOverflow](https://stackoverflow.com/questions/tagged/phpspreadsheet), or have a quick chat on [Gitter](https://gitter.im/PHPOffice/PhpSpreadsheet).
## Patreon
I am now running a [Patreon](https://www.patreon.com/MarkBaker) to support the work that I do on PhpSpreadsheet.
Supporters will receive access to articles about working with PhpSpreadsheet, and how to use some of its more advanced features.
Posts already available to Patreon supporters:
- The Dating Game
- A look at how MS Excel (and PhpSpreadsheet) handle date and time values.
- Looping the Loop
- Advice on Iterating through the rows and cells in a worksheet.
And for Patrons at levels actively using PhpSpreadsheet:
- Behind the Mask
- A look at Number Format Masks.
The Next Article (currently Work in Progress):
- Formula for Success
- How to debug formulae that don't produce the expected result.
My aim is to post at least one article each month, taking a detailed look at some feature of MS Excel and how to use that feature in PhpSpreadsheet, or on how to perform different activities in PhpSpreadsheet.
Planned posts for the future include topics like:
- Tables
- Structured References
- AutoFiltering
- Array Formulae
- Conditional Formatting
- Data Validation
- Value Binders
- Images
- Charts
After a period of six months exclusive to Patreon supporters, articles will be incorporated into the public documentation for the library.
## PHPExcel vs PhpSpreadsheet ?
PhpSpreadsheet is the next version of PHPExcel. It breaks compatibility to dramatically improve the code base quality (namespaces, PSR compliance, use of latest PHP language features, etc.).
Because all efforts have shifted to PhpSpreadsheet, PHPExcel will no longer be maintained. All contributions for PHPExcel, patches and new features, should target PhpSpreadsheet `master` branch.
Do you need to migrate? There is [an automated tool](/docs/topics/migration-from-PHPExcel.md) for that.
## License
PhpSpreadsheet is licensed under [MIT](https://github.com/PHPOffice/PhpSpreadsheet/blob/master/LICENSE).
phpspreadsheet/src/PhpSpreadsheet/Style/Conditional.php 0000644 00000020471 15266563261 0017365 0 ustar 00 style = new Style(false, true);
}
public function getPriority(): int
{
return $this->priority;
}
public function setPriority(int $priority): self
{
$this->priority = $priority;
return $this;
}
public function getNoFormatSet(): bool
{
return $this->noFormatSet;
}
public function setNoFormatSet(bool $noFormatSet): self
{
$this->noFormatSet = $noFormatSet;
return $this;
}
/**
* Get Condition type.
*/
public function getConditionType(): string
{
return $this->conditionType;
}
/**
* Set Condition type.
*
* @param string $type Condition type, see self::CONDITION_*
*
* @return $this
*/
public function setConditionType(string $type): static
{
$this->conditionType = $type;
return $this;
}
/**
* Get Operator type.
*/
public function getOperatorType(): string
{
return $this->operatorType;
}
/**
* Set Operator type.
*
* @param string $type Conditional operator type, see self::OPERATOR_*
*
* @return $this
*/
public function setOperatorType(string $type): static
{
$this->operatorType = $type;
return $this;
}
/**
* Get text.
*/
public function getText(): string
{
return $this->text;
}
/**
* Set text.
*
* @return $this
*/
public function setText(string $text): static
{
$this->text = $text;
return $this;
}
/**
* Get StopIfTrue.
*/
public function getStopIfTrue(): bool
{
return $this->stopIfTrue;
}
/**
* Set StopIfTrue.
*
* @return $this
*/
public function setStopIfTrue(bool $stopIfTrue): static
{
$this->stopIfTrue = $stopIfTrue;
return $this;
}
/**
* Get Conditions.
*
* @return (bool|float|int|string)[]
*/
public function getConditions(): array
{
return $this->condition;
}
/**
* Set Conditions.
*
* @param bool|(bool|float|int|string)[]|float|int|string $conditions Condition
*
* @return $this
*/
public function setConditions($conditions): static
{
if (!is_array($conditions)) {
$conditions = [$conditions];
}
$this->condition = $conditions;
return $this;
}
/**
* Add Condition.
*
* @param bool|float|int|string $condition Condition
*
* @return $this
*/
public function addCondition($condition): static
{
$this->condition[] = $condition;
return $this;
}
/**
* Get Style.
*/
public function getStyle(mixed $cellData = null): Style
{
if ($this->conditionType === self::CONDITION_COLORSCALE && $cellData !== null && $this->colorScale !== null && is_numeric($cellData)) {
$style = new Style(isConditional: true);
$style->getFill()->setFillType(Fill::FILL_SOLID);
$style->getFill()->getStartColor()->setARGB($this->colorScale->getColorForValue((float) $cellData));
return $style;
}
return $this->style;
}
/**
* Set Style.
*
* @return $this
*/
public function setStyle(Style $style): static
{
$this->style = $style;
return $this;
}
public function getDataBar(): ?ConditionalDataBar
{
return $this->dataBar;
}
public function setDataBar(ConditionalDataBar $dataBar): static
{
$this->dataBar = $dataBar;
return $this;
}
public function getColorScale(): ?ConditionalColorScale
{
return $this->colorScale;
}
public function setColorScale(ConditionalColorScale $colorScale): static
{
$this->colorScale = $colorScale;
return $this;
}
/**
* Get hash code.
*
* @return string Hash code
*/
public function getHashCode(): string
{
return md5(
$this->conditionType
. $this->operatorType
. implode(';', $this->condition)
. $this->style->getHashCode()
. __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;
}
}
}
/**
* Verify if param is valid condition type.
*/
public static function isValidConditionType(string $type): bool
{
return in_array($type, self::CONDITION_TYPES);
}
}
phpspreadsheet/src/PhpSpreadsheet/Style/NumberFormat.php 0000644 00000042205 15266563261 0017522 0 ustar 00 formatCode = null;
$this->builtInFormatCode = false;
}
}
/**
* Get the shared style component for the currently active cell in currently active sheet.
* Only used for style supervisor.
*/
public function getSharedComponent(): self
{
/** @var Style $parent */
$parent = $this->parent;
return $parent->getSharedComponent()->getNumberFormat();
}
/**
* Build style array from subcomponents.
*
* @param mixed[] $array
*
* @return array{numberFormat: mixed[]}
*/
public function getStyleArray(array $array): array
{
return ['numberFormat' => $array];
}
/**
* Apply styles from array.
*
*
* $spreadsheet->getActiveSheet()->getStyle('B2')->getNumberFormat()->applyFromArray(
* [
* 'formatCode' => NumberFormat::FORMAT_CURRENCY_EUR_SIMPLE
* ]
* );
*
*
* @param string[] $styleArray Array containing style information
*
* @return $this
*/
public function applyFromArray(array $styleArray): static
{
if ($this->isSupervisor) {
$this->getActiveSheet()->getStyle($this->getSelectedCells())->applyFromArray($this->getStyleArray($styleArray));
} else {
if (isset($styleArray['formatCode'])) {
$this->setFormatCode($styleArray['formatCode']);
}
}
return $this;
}
/**
* Get Format Code.
*/
public function getFormatCode(bool $extended = false): ?string
{
if ($this->isSupervisor) {
return $this->getSharedComponent()->getFormatCode($extended);
}
$builtin = $this->getBuiltInFormatCode();
if (is_int($builtin)) {
if ($extended) {
if ($builtin === self::SHORT_DATE_INDEX) {
return self::$shortDateFormat;
}
if ($builtin === self::DATE_TIME_INDEX) {
return self::$dateTimeFormat;
}
}
return self::builtInFormatCode($builtin);
}
return $extended ? self::convertSystemFormats($this->formatCode) : $this->formatCode;
}
public static function convertSystemFormats(?string $formatCode): ?string
{
if (is_string($formatCode)) {
if (stripos($formatCode, self::FORMAT_SYSDATE_F800) !== false || stripos($formatCode, self::FORMAT_SYSDATE_X) !== false) {
return self::$longDateFormat;
}
if (stripos($formatCode, self::FORMAT_SYSTIME_F400) !== false || stripos($formatCode, self::FORMAT_SYSTIME_X) !== false) {
return self::$timeFormat;
}
}
return $formatCode;
}
/**
* Set Format Code.
*
* @param string $formatCode see self::FORMAT_*
*
* @return $this
*/
public function setFormatCode(string $formatCode): static
{
if ($formatCode == '') {
$formatCode = self::FORMAT_GENERAL;
}
if ($this->isSupervisor) {
$styleArray = $this->getStyleArray(['formatCode' => $formatCode]);
$this->getActiveSheet()->getStyle($this->getSelectedCells())->applyFromArray($styleArray);
} else {
$this->formatCode = $formatCode;
$this->builtInFormatCode = self::builtInFormatCodeIndex($formatCode);
}
return $this;
}
/**
* Get Built-In Format Code.
*
* @return false|int
*/
public function getBuiltInFormatCode()
{
if ($this->isSupervisor) {
return $this->getSharedComponent()->getBuiltInFormatCode();
}
return $this->builtInFormatCode;
}
/**
* Set Built-In Format Code.
*
* @param int $formatCodeIndex Id of the built-in format code to use
*
* @return $this
*/
public function setBuiltInFormatCode(int $formatCodeIndex): static
{
if ($this->isSupervisor) {
$styleArray = $this->getStyleArray(['formatCode' => self::builtInFormatCode($formatCodeIndex)]);
$this->getActiveSheet()->getStyle($this->getSelectedCells())->applyFromArray($styleArray);
} else {
$this->builtInFormatCode = $formatCodeIndex;
$this->formatCode = self::builtInFormatCode($formatCodeIndex);
}
return $this;
}
/**
* Fill built-in format codes.
*/
private static function fillBuiltInFormatCodes(): void
{
// [MS-OI29500: Microsoft Office Implementation Information for ISO/IEC-29500 Standard Compliance]
// 18.8.30. numFmt (Number Format)
//
// The ECMA standard defines built-in format IDs
// 14: "mm-dd-yy"
// 22: "m/d/yy h:mm"
// 37: "#,##0 ;(#,##0)"
// 38: "#,##0 ;[Red](#,##0)"
// 39: "#,##0.00;(#,##0.00)"
// 40: "#,##0.00;[Red](#,##0.00)"
// 47: "mmss.0"
// KOR fmt 55: "yyyy-mm-dd"
// Excel defines built-in format IDs
// 14: "m/d/yyyy"
// 22: "m/d/yyyy h:mm"
// 37: "#,##0_);(#,##0)"
// 38: "#,##0_);[Red](#,##0)"
// 39: "#,##0.00_);(#,##0.00)"
// 40: "#,##0.00_);[Red](#,##0.00)"
// 47: "mm:ss.0"
// KOR fmt 55: "yyyy/mm/dd"
// Built-in format codes
if (empty(self::$builtInFormats)) {
self::$builtInFormats = [];
// General
self::$builtInFormats[0] = self::FORMAT_GENERAL;
self::$builtInFormats[1] = '0';
self::$builtInFormats[2] = '0.00';
self::$builtInFormats[3] = '#,##0';
self::$builtInFormats[4] = '#,##0.00';
self::$builtInFormats[9] = '0%';
self::$builtInFormats[10] = '0.00%';
self::$builtInFormats[11] = '0.00E+00';
self::$builtInFormats[12] = '# ?/?';
self::$builtInFormats[13] = '# ??/??';
self::$builtInFormats[14] = self::FORMAT_DATE_XLSX14_ACTUAL; // Despite ECMA 'mm-dd-yy';
self::$builtInFormats[15] = self::FORMAT_DATE_XLSX15;
self::$builtInFormats[16] = 'd-mmm';
self::$builtInFormats[17] = 'mmm-yy';
self::$builtInFormats[18] = 'h:mm AM/PM';
self::$builtInFormats[19] = 'h:mm:ss AM/PM';
self::$builtInFormats[20] = 'h:mm';
self::$builtInFormats[21] = 'h:mm:ss';
self::$builtInFormats[22] = self::FORMAT_DATE_XLSX22_ACTUAL; // Despite ECMA 'm/d/yy h:mm';
self::$builtInFormats[37] = '#,##0_);(#,##0)'; // Despite ECMA '#,##0 ;(#,##0)';
self::$builtInFormats[38] = '#,##0_);[Red](#,##0)'; // Despite ECMA '#,##0 ;[Red](#,##0)';
self::$builtInFormats[39] = '#,##0.00_);(#,##0.00)'; // Despite ECMA '#,##0.00;(#,##0.00)';
self::$builtInFormats[40] = '#,##0.00_);[Red](#,##0.00)'; // Despite ECMA '#,##0.00;[Red](#,##0.00)';
self::$builtInFormats[44] = '_("$"* #,##0.00_);_("$"* \(#,##0.00\);_("$"* "-"??_);_(@_)';
self::$builtInFormats[45] = 'mm:ss';
self::$builtInFormats[46] = '[h]:mm:ss';
self::$builtInFormats[47] = 'mm:ss.0'; // Despite ECMA 'mmss.0';
self::$builtInFormats[48] = '##0.0E+0';
self::$builtInFormats[49] = '@';
// CHT
self::$builtInFormats[27] = '[$-404]e/m/d';
self::$builtInFormats[30] = 'm/d/yy';
self::$builtInFormats[36] = '[$-404]e/m/d';
self::$builtInFormats[50] = '[$-404]e/m/d';
self::$builtInFormats[57] = '[$-404]e/m/d';
// THA
self::$builtInFormats[59] = 't0';
self::$builtInFormats[60] = 't0.00';
self::$builtInFormats[61] = 't#,##0';
self::$builtInFormats[62] = 't#,##0.00';
self::$builtInFormats[67] = 't0%';
self::$builtInFormats[68] = 't0.00%';
self::$builtInFormats[69] = 't# ?/?';
self::$builtInFormats[70] = 't# ??/??';
// JPN
self::$builtInFormats[28] = '[$-411]ggge"年"m"月"d"日"';
self::$builtInFormats[29] = '[$-411]ggge"年"m"月"d"日"';
self::$builtInFormats[31] = 'yyyy"年"m"月"d"日"';
self::$builtInFormats[32] = 'h"時"mm"分"';
self::$builtInFormats[33] = 'h"時"mm"分"ss"秒"';
self::$builtInFormats[34] = 'yyyy"年"m"月"';
self::$builtInFormats[35] = 'm"月"d"日"';
self::$builtInFormats[51] = '[$-411]ggge"年"m"月"d"日"';
self::$builtInFormats[52] = 'yyyy"年"m"月"';
self::$builtInFormats[53] = 'm"月"d"日"';
self::$builtInFormats[54] = '[$-411]ggge"年"m"月"d"日"';
self::$builtInFormats[55] = 'yyyy"年"m"月"';
self::$builtInFormats[56] = 'm"月"d"日"';
self::$builtInFormats[58] = '[$-411]ggge"年"m"月"d"日"';
// Flip array (for faster lookups)
self::$flippedBuiltInFormats = array_flip(self::$builtInFormats);
}
}
/**
* Get built-in format code.
*/
public static function builtInFormatCode(int $index): string
{
// Clean parameter
$index = (int) $index;
// Ensure built-in format codes are available
self::fillBuiltInFormatCodes();
// Lookup format code
if (isset(self::$builtInFormats[$index])) {
return self::$builtInFormats[$index];
}
return '';
}
/**
* Get built-in format code index.
*
* @return false|int
*/
public static function builtInFormatCodeIndex(string $formatCodeIndex)
{
// Ensure built-in format codes are available
self::fillBuiltInFormatCodes();
// Lookup format code
if (array_key_exists($formatCodeIndex, self::$flippedBuiltInFormats)) {
return self::$flippedBuiltInFormats[$formatCodeIndex];
}
return false;
}
/**
* Get hash code.
*
* @return string Hash code
*/
public function getHashCode(): string
{
if ($this->isSupervisor) {
return $this->getSharedComponent()->getHashCode();
}
return md5(
$this->formatCode
. $this->builtInFormatCode
. __CLASS__
);
}
/**
* Convert a value in a pre-defined format to a PHP string.
*
* @param null|bool|float|int|RichText|string $value Value to format
* @param string $format Format code: see = self::FORMAT_* for predefined values;
* or can be any valid MS Excel custom format string
* @param ?mixed[] $callBack Callback function for additional formatting of string
*
* @return string Formatted string
*/
public static function toFormattedString(mixed $value, string $format, ?array $callBack = null): string
{
return NumberFormat\Formatter::toFormattedString($value, $format, $callBack);
}
/** @return mixed[] */
protected function exportArray1(): array
{
$exportedArray = [];
$this->exportArray2($exportedArray, 'formatCode', $this->getFormatCode());
return $exportedArray;
}
public static function getShortDateFormat(): string
{
return self::$shortDateFormat;
}
public static function setShortDateFormat(string $shortDateFormat): void
{
self::$shortDateFormat = $shortDateFormat;
}
public static function getLongDateFormat(): string
{
return self::$longDateFormat;
}
public static function setLongDateFormat(string $longDateFormat): void
{
self::$longDateFormat = $longDateFormat;
}
public static function getDateTimeFormat(): string
{
return self::$dateTimeFormat;
}
public static function setDateTimeFormat(string $dateTimeFormat): void
{
self::$dateTimeFormat = $dateTimeFormat;
}
public static function getTimeFormat(): string
{
return self::$timeFormat;
}
public static function setTimeFormat(string $timeFormat): void
{
self::$timeFormat = $timeFormat;
}
}
phpspreadsheet/src/PhpSpreadsheet/Style/Color.php 0000644 00000036433 15266563261 0016205 0 ustar 00 self::COLOR_BLACK,
'White' => self::COLOR_WHITE,
'Red' => self::COLOR_RED,
'Green' => self::COLOR_GREEN,
'Blue' => self::COLOR_BLUE,
'Yellow' => self::COLOR_YELLOW,
'Magenta' => self::COLOR_MAGENTA,
'Cyan' => self::COLOR_CYAN,
];
const VALIDATE_ARGB_SIZE = 8;
const VALIDATE_RGB_SIZE = 6;
const VALIDATE_COLOR_6 = '/^[A-F0-9]{6}$/i';
const VALIDATE_COLOR_8 = '/^[A-F0-9]{8}$/i';
private const INDEXED_COLORS = [
1 => 'FF000000', // System Colour #1 - Black
2 => 'FFFFFFFF', // System Colour #2 - White
3 => 'FFFF0000', // System Colour #3 - Red
4 => 'FF00FF00', // System Colour #4 - Green
5 => 'FF0000FF', // System Colour #5 - Blue
6 => 'FFFFFF00', // System Colour #6 - Yellow
7 => 'FFFF00FF', // System Colour #7- Magenta
8 => 'FF00FFFF', // System Colour #8- Cyan
9 => 'FF800000', // Standard Colour #9
10 => 'FF008000', // Standard Colour #10
11 => 'FF000080', // Standard Colour #11
12 => 'FF808000', // Standard Colour #12
13 => 'FF800080', // Standard Colour #13
14 => 'FF008080', // Standard Colour #14
15 => 'FFC0C0C0', // Standard Colour #15
16 => 'FF808080', // Standard Colour #16
17 => 'FF9999FF', // Chart Fill Colour #17
18 => 'FF993366', // Chart Fill Colour #18
19 => 'FFFFFFCC', // Chart Fill Colour #19
20 => 'FFCCFFFF', // Chart Fill Colour #20
21 => 'FF660066', // Chart Fill Colour #21
22 => 'FFFF8080', // Chart Fill Colour #22
23 => 'FF0066CC', // Chart Fill Colour #23
24 => 'FFCCCCFF', // Chart Fill Colour #24
25 => 'FF000080', // Chart Line Colour #25
26 => 'FFFF00FF', // Chart Line Colour #26
27 => 'FFFFFF00', // Chart Line Colour #27
28 => 'FF00FFFF', // Chart Line Colour #28
29 => 'FF800080', // Chart Line Colour #29
30 => 'FF800000', // Chart Line Colour #30
31 => 'FF008080', // Chart Line Colour #31
32 => 'FF0000FF', // Chart Line Colour #32
33 => 'FF00CCFF', // Standard Colour #33
34 => 'FFCCFFFF', // Standard Colour #34
35 => 'FFCCFFCC', // Standard Colour #35
36 => 'FFFFFF99', // Standard Colour #36
37 => 'FF99CCFF', // Standard Colour #37
38 => 'FFFF99CC', // Standard Colour #38
39 => 'FFCC99FF', // Standard Colour #39
40 => 'FFFFCC99', // Standard Colour #40
41 => 'FF3366FF', // Standard Colour #41
42 => 'FF33CCCC', // Standard Colour #42
43 => 'FF99CC00', // Standard Colour #43
44 => 'FFFFCC00', // Standard Colour #44
45 => 'FFFF9900', // Standard Colour #45
46 => 'FFFF6600', // Standard Colour #46
47 => 'FF666699', // Standard Colour #47
48 => 'FF969696', // Standard Colour #48
49 => 'FF003366', // Standard Colour #49
50 => 'FF339966', // Standard Colour #50
51 => 'FF003300', // Standard Colour #51
52 => 'FF333300', // Standard Colour #52
53 => 'FF993300', // Standard Colour #53
54 => 'FF993366', // Standard Colour #54
55 => 'FF333399', // Standard Colour #55
56 => 'FF333333', // Standard Colour #56
];
/**
* ARGB - Alpha RGB.
*/
protected ?string $argb = null;
private bool $hasChanged = false;
private int $theme = -1;
/**
* Create a new Color.
*
* @param string $colorValue ARGB value for the colour, or named colour
* @param bool $isSupervisor Flag indicating if this is a supervisor or not
* Leave this value at default unless you understand exactly what
* its ramifications are
* @param bool $isConditional Flag indicating if this is a conditional style or not
* Leave this value at default unless you understand exactly what
* its ramifications are
*/
public function __construct(string $colorValue = self::COLOR_BLACK, bool $isSupervisor = false, bool $isConditional = false)
{
// Supervisor?
parent::__construct($isSupervisor);
// Initialise values
if (!$isConditional) {
$this->argb = $this->validateColor($colorValue) ?: self::COLOR_BLACK;
}
}
/**
* Get the shared style component for the currently active cell in currently active sheet.
* Only used for style supervisor.
*/
public function getSharedComponent(): self
{
/** @var Style $parent */
$parent = $this->parent;
/** @var Border|Fill $sharedComponent */
$sharedComponent = $parent->getSharedComponent();
if ($sharedComponent instanceof Fill) {
if ($this->parentPropertyName === 'endColor') {
return $sharedComponent->getEndColor();
}
return $sharedComponent->getStartColor();
}
return $sharedComponent->getColor();
}
/**
* Build style array from subcomponents.
*
* @param mixed[] $array
*
* @return mixed[]
*/
public function getStyleArray(array $array): array
{
/** @var Style $parent */
$parent = $this->parent;
return $parent->getStyleArray([$this->parentPropertyName => $array]);
}
/**
* Apply styles from array.
*
*
* $spreadsheet->getActiveSheet()->getStyle('B2')->getFont()->getColor()->applyFromArray(['rgb' => '808080']);
*
*
* @param array{rgb?: string, argb?: string, theme?: int} $styleArray Array containing style information
*
* @return $this
*/
public function applyFromArray(array $styleArray): static
{
if ($this->isSupervisor) {
$this->getActiveSheet()
->getStyle($this->getSelectedCells())
->applyFromArray(
$this->getStyleArray($styleArray)
);
} else {
if (isset($styleArray['rgb'])) {
$this->setRGB($styleArray['rgb']);
}
if (isset($styleArray['argb'])) {
$this->setARGB($styleArray['argb']);
}
if (isset($styleArray['theme'])) {
$this->setTheme($styleArray['theme']);
}
}
return $this;
}
private function validateColor(?string $colorValue): string
{
if ($colorValue === null || $colorValue === '') {
return self::COLOR_BLACK;
}
$named = ucfirst(strtolower($colorValue));
if (array_key_exists($named, self::NAMED_COLOR_TRANSLATIONS)) {
return self::NAMED_COLOR_TRANSLATIONS[$named];
}
if (preg_match(self::VALIDATE_COLOR_8, $colorValue) === 1) {
return $colorValue;
}
if (preg_match(self::VALIDATE_COLOR_6, $colorValue) === 1) {
return 'FF' . $colorValue;
}
return '';
}
/**
* Get ARGB.
*/
public function getARGB(): ?string
{
if ($this->isSupervisor) {
return $this->getSharedComponent()->getARGB();
}
return $this->argb;
}
/**
* Set ARGB.
*
* @param ?string $colorValue ARGB value, or a named color
*
* @return $this
*/
public function setARGB(?string $colorValue = self::COLOR_BLACK, bool $nullStringOkay = false): static
{
$this->hasChanged = true;
$this->setTheme(-1);
if (!$nullStringOkay || $colorValue !== '') {
$colorValue = $this->validateColor($colorValue);
if ($colorValue === '') {
return $this;
}
}
if ($this->isSupervisor) {
$styleArray = $this->getStyleArray(['argb' => $colorValue]);
$this->getActiveSheet()->getStyle($this->getSelectedCells())->applyFromArray($styleArray);
} else {
$this->argb = $colorValue;
}
return $this;
}
/**
* Get RGB.
*/
public function getRGB(): string
{
if ($this->isSupervisor) {
return $this->getSharedComponent()->getRGB();
}
return substr($this->argb ?? '', 2);
}
/**
* Set RGB.
*
* @param ?string $colorValue RGB value, or a named color
*
* @return $this
*/
public function setRGB(?string $colorValue = self::COLOR_BLACK): static
{
return $this->setARGB($colorValue);
}
/**
* Get a specified colour component of an RGB value.
*
* @param string $rgbValue The colour as an RGB value (e.g. FF00CCCC or CCDDEE
* @param int $offset Position within the RGB value to extract
* @param bool $hex Flag indicating whether the component should be returned as a hex or a
* decimal value
*
* @return int|string The extracted colour component
*/
private static function getColourComponent(string $rgbValue, int $offset, bool $hex = true): string|int
{
$colour = substr($rgbValue, $offset, 2) ?: '';
if (preg_match('/^[0-9a-f]{2}$/i', $colour) !== 1) {
$colour = '00';
}
return ($hex) ? $colour : (int) hexdec($colour);
}
/**
* Get the red colour component of an RGB value.
*
* @param string $rgbValue The colour as an RGB value (e.g. FF00CCCC or CCDDEE
* @param bool $hex Flag indicating whether the component should be returned as a hex or a
* decimal value
*
* @return int|string The red colour component
*/
public static function getRed(string $rgbValue, bool $hex = true)
{
return self::getColourComponent($rgbValue, strlen($rgbValue) - 6, $hex);
}
/**
* Get the green colour component of an RGB value.
*
* @param string $rgbValue The colour as an RGB value (e.g. FF00CCCC or CCDDEE
* @param bool $hex Flag indicating whether the component should be returned as a hex or a
* decimal value
*
* @return int|string The green colour component
*/
public static function getGreen(string $rgbValue, bool $hex = true)
{
return self::getColourComponent($rgbValue, strlen($rgbValue) - 4, $hex);
}
/**
* Get the blue colour component of an RGB value.
*
* @param string $rgbValue The colour as an RGB value (e.g. FF00CCCC or CCDDEE
* @param bool $hex Flag indicating whether the component should be returned as a hex or a
* decimal value
*
* @return int|string The blue colour component
*/
public static function getBlue(string $rgbValue, bool $hex = true)
{
return self::getColourComponent($rgbValue, strlen($rgbValue) - 2, $hex);
}
/**
* Adjust the brightness of a color.
*
* @param string $hexColourValue The colour as an RGBA or RGB value (e.g. FF00CCCC or CCDDEE)
* @param float $adjustPercentage The percentage by which to adjust the colour as a float from -1 to 1
*
* @return string The adjusted colour as an RGBA or RGB value (e.g. FF00CCCC or CCDDEE)
*/
public static function changeBrightness(string $hexColourValue, float $adjustPercentage): string
{
$rgba = (strlen($hexColourValue) === 8);
$adjustPercentage = max(-1.0, min(1.0, $adjustPercentage));
/** @var int $red */
$red = self::getRed($hexColourValue, false);
/** @var int $green */
$green = self::getGreen($hexColourValue, false);
/** @var int $blue */
$blue = self::getBlue($hexColourValue, false);
return (($rgba) ? 'FF' : '') . RgbTint::rgbAndTintToRgb($red, $green, $blue, $adjustPercentage);
}
/**
* Get indexed color.
*
* @param int $colorIndex Index entry point into the colour array
* @param bool $background Flag to indicate whether default background or foreground colour
* should be returned if the indexed colour doesn't exist
* @param null|string[] $palette
*/
public static function indexedColor(int $colorIndex, bool $background = false, ?array $palette = null): self
{
// Clean parameter
$colorIndex = (int) $colorIndex;
if (empty($palette)) {
if (isset(self::INDEXED_COLORS[$colorIndex])) {
return new self(self::INDEXED_COLORS[$colorIndex]);
}
} else {
if (isset($palette[$colorIndex])) {
return new self($palette[$colorIndex]);
}
}
return ($background) ? new self(self::COLOR_WHITE) : new self(self::COLOR_BLACK);
}
/**
* Get hash code.
*
* @return string Hash code
*/
public function getHashCode(): string
{
if ($this->isSupervisor) {
return $this->getSharedComponent()->getHashCode();
}
return md5(
$this->argb
. (string) $this->theme
. __CLASS__
);
}
/** @return mixed[] */
protected function exportArray1(): array
{
$exportedArray = [];
$this->exportArray2($exportedArray, 'argb', $this->getARGB());
$this->exportArray2($exportedArray, 'theme', $this->getTheme());
return $exportedArray;
}
public function getHasChanged(): bool
{
if ($this->isSupervisor) {
return $this->getSharedComponent()->hasChanged;
}
return $this->hasChanged;
}
public function getTheme(): int
{
if ($this->isSupervisor) {
return $this->getSharedComponent()->getTheme();
}
return $this->theme;
}
public function setTheme(int $theme): self
{
$this->hasChanged = true;
if ($this->isSupervisor) {
$styleArray = $this->getStyleArray(['theme' => $theme]);
$this->getActiveSheet()
->getStyle($this->getSelectedCells())
->applyFromArray($styleArray);
} else {
$this->theme = $theme;
}
return $this;
}
public function setHyperlinkTheme(): self
{
$rgb = $this->getActiveSheet()
->getParent()
?->getTheme()
->getThemeColors();
if (is_array($rgb) && array_key_exists('hlink', $rgb)) {
$this->setRGB($rgb['hlink']);
}
return $this->setTheme(Theme::HYPERLINK_THEME);
}
}
phpspreadsheet/src/PhpSpreadsheet/Style/Supervisor.php 0000644 00000010517 15266563261 0017303 0 ustar 00 isSupervisor = $isSupervisor;
}
/**
* Bind parent. Only used for supervisor.
*
* @return $this
*/
public function bindParent(Spreadsheet|self $parent, ?string $parentPropertyName = null)
{
$this->parent = $parent;
$this->parentPropertyName = $parentPropertyName;
return $this;
}
/**
* Is this a supervisor or a cell style component?
*/
public function getIsSupervisor(): bool
{
return $this->isSupervisor;
}
/**
* Get the currently active sheet. Only used for supervisor.
*/
public function getActiveSheet(): Worksheet
{
return $this->parent->getActiveSheet();
}
/**
* Get the currently active cell coordinate in currently active sheet.
* Only used for supervisor.
*
* @return string E.g. 'A1'
*/
public function getSelectedCells(): string
{
return $this->getActiveSheet()->getSelectedCells();
}
/**
* Get the currently active cell coordinate in currently active sheet.
* Only used for supervisor.
*
* @return string E.g. 'A1'
*/
public function getActiveCell(): string
{
return $this->getActiveSheet()->getActiveCell();
}
/**
* 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)) && ($key != 'parent')) {
$this->$key = clone $value;
} else {
$this->$key = $value;
}
}
}
/**
* Export style as array.
*
* Available to anything which extends this class:
* Alignment, Border, Borders, Color, Fill, Font,
* NumberFormat, Protection, and Style.
*
* @return mixed[]
*/
final public function exportArray(): array
{
return $this->exportArray1();
}
/**
* Abstract method to be implemented in anything which
* extends this class.
*
* This method invokes exportArray2 with the names and values
* of all properties to be included in output array,
* returning that array to exportArray, then to caller.
*
* @return mixed[]
*/
abstract protected function exportArray1(): array;
/**
* Populate array from exportArray1.
* This method is available to anything which extends this class.
* The parameter index is the key to be added to the array.
* The parameter objOrValue is either a primitive type,
* which is the value added to the array,
* or a Style object to be recursively added via exportArray.
*
* @param mixed[] $exportedArray
*/
final protected function exportArray2(array &$exportedArray, string $index, mixed $objOrValue): void
{
if ($objOrValue instanceof self) {
$exportedArray[$index] = $objOrValue->exportArray();
} else {
$exportedArray[$index] = $objOrValue;
}
}
/**
* Get the shared style component for the currently active cell in currently active sheet.
* Only used for style supervisor.
*/
abstract public function getSharedComponent(): mixed;
/**
* Build style array from subcomponents.
*
* @param mixed[] $array
*
* @return mixed[]
*/
abstract public function getStyleArray(array $array): array;
}
phpspreadsheet/src/PhpSpreadsheet/Style/Border.php 0000644 00000014614 15266563261 0016341 0 ustar 00 color = new Color(Color::COLOR_BLACK, $isSupervisor);
// bind parent if we are a supervisor
if ($isSupervisor) {
$this->color->bindParent($this, 'color');
}
if ($isConditional) {
$this->borderStyle = self::BORDER_OMIT;
}
}
/**
* Get the shared style component for the currently active cell in currently active sheet.
* Only used for style supervisor.
*/
public function getSharedComponent(): self
{
/** @var Style $parent */
$parent = $this->parent;
/** @var Borders $sharedComponent */
$sharedComponent = $parent->getSharedComponent();
return match ($this->parentPropertyName) {
'bottom' => $sharedComponent->getBottom(),
'diagonal' => $sharedComponent->getDiagonal(),
'left' => $sharedComponent->getLeft(),
'right' => $sharedComponent->getRight(),
'top' => $sharedComponent->getTop(),
default => throw new PhpSpreadsheetException('Cannot get shared component for a pseudo-border.'),
};
}
/**
* Build style array from subcomponents.
*
* @param mixed[] $array
*
* @return mixed[]
*/
public function getStyleArray(array $array): array
{
/** @var Style $parent */
$parent = $this->parent;
return $parent->getStyleArray([$this->parentPropertyName => $array]);
}
/**
* Apply styles from array.
*
*
* $spreadsheet->getActiveSheet()->getStyle('B2')->getBorders()->getTop()->applyFromArray(
* [
* 'borderStyle' => Border::BORDER_DASHDOT,
* 'color' => [
* 'rgb' => '808080'
* ]
* ]
* );
*
*
* @param mixed[] $styleArray Array containing style information
*
* @return $this
*/
public function applyFromArray(array $styleArray): static
{
if ($this->isSupervisor) {
$this->getActiveSheet()->getStyle($this->getSelectedCells())->applyFromArray($this->getStyleArray($styleArray));
} else {
/** @var array{borderStyle?: string, color?: array{rgb?: string, argb?: string}} $styleArray */
if (isset($styleArray['borderStyle'])) {
$this->setBorderStyle($styleArray['borderStyle']);
}
if (isset($styleArray['color'])) {
$this->getColor()
->applyFromArray($styleArray['color']);
}
}
return $this;
}
/**
* Get Border style.
*/
public function getBorderStyle(): string
{
if ($this->isSupervisor) {
return $this->getSharedComponent()->getBorderStyle();
}
return $this->borderStyle;
}
/**
* Set Border style.
*
* @param bool|string $style When passing a boolean, FALSE equates Border::BORDER_NONE
* and TRUE to Border::BORDER_MEDIUM
*
* @return $this
*/
public function setBorderStyle(bool|string $style): static
{
if (empty($style)) {
$style = self::BORDER_NONE;
} elseif (is_bool($style)) {
$style = self::BORDER_MEDIUM;
}
if ($this->isSupervisor) {
$styleArray = $this->getStyleArray(['borderStyle' => $style]);
$this->getActiveSheet()->getStyle($this->getSelectedCells())->applyFromArray($styleArray);
} else {
$this->borderStyle = $style;
}
return $this;
}
/**
* Get Border Color.
*/
public function getColor(): Color
{
return $this->color;
}
/**
* Set Border Color.
*
* @return $this
*/
public function setColor(Color $color): static
{
// make sure parameter is a real color and not a supervisor
$color = $color->getIsSupervisor() ? $color->getSharedComponent() : $color;
if ($this->isSupervisor) {
$styleArray = $this->getColor()->getStyleArray(['argb' => $color->getARGB()]);
$this->getActiveSheet()->getStyle($this->getSelectedCells())->applyFromArray($styleArray);
} else {
$this->color = $color;
}
return $this;
}
/**
* Get hash code.
*
* @return string Hash code
*/
public function getHashCode(): string
{
if ($this->isSupervisor) {
return $this->getSharedComponent()->getHashCode();
}
return md5(
$this->borderStyle
. $this->color->getHashCode()
. __CLASS__
);
}
/** @return mixed[] */
protected function exportArray1(): array
{
$exportedArray = [];
$this->exportArray2($exportedArray, 'borderStyle', $this->getBorderStyle());
$this->exportArray2($exportedArray, 'color', $this->getColor());
return $exportedArray;
}
}
phpspreadsheet/src/PhpSpreadsheet/Style/Borders.php 0000644 00000024755 15266563261 0016533 0 ustar 00 left = new Border($isSupervisor, $isConditional);
$this->right = new Border($isSupervisor, $isConditional);
$this->top = new Border($isSupervisor, $isConditional);
$this->bottom = new Border($isSupervisor, $isConditional);
$this->diagonal = new Border($isSupervisor, $isConditional);
$this->diagonalDirection = self::DIAGONAL_NONE;
// Specially for supervisor
if ($isSupervisor) {
// Initialize pseudo-borders
$this->allBorders = new Border(true, $isConditional);
$this->outline = new Border(true, $isConditional);
$this->inside = new Border(true, $isConditional);
$this->vertical = new Border(true, $isConditional);
$this->horizontal = new Border(true, $isConditional);
// bind parent if we are a supervisor
$this->left->bindParent($this, 'left');
$this->right->bindParent($this, 'right');
$this->top->bindParent($this, 'top');
$this->bottom->bindParent($this, 'bottom');
$this->diagonal->bindParent($this, 'diagonal');
$this->allBorders->bindParent($this, 'allBorders');
$this->outline->bindParent($this, 'outline');
$this->inside->bindParent($this, 'inside');
$this->vertical->bindParent($this, 'vertical');
$this->horizontal->bindParent($this, 'horizontal');
}
}
/**
* Get the shared style component for the currently active cell in currently active sheet.
* Only used for style supervisor.
*/
public function getSharedComponent(): self
{
/** @var Style $parent */
$parent = $this->parent;
return $parent->getSharedComponent()->getBorders();
}
/**
* Build style array from subcomponents.
*
* @param mixed[] $array
*
* @return array{borders: mixed[]}
*/
public function getStyleArray(array $array): array
{
return ['borders' => $array];
}
/**
* Apply styles from array.
*
*
* $spreadsheet->getActiveSheet()->getStyle('B2')->getBorders()->applyFromArray(
* [
* 'bottom' => [
* 'borderStyle' => Border::BORDER_DASHDOT,
* 'color' => [
* 'rgb' => '808080'
* ]
* ],
* 'top' => [
* 'borderStyle' => Border::BORDER_DASHDOT,
* 'color' => [
* 'rgb' => '808080'
* ]
* ]
* ]
* );
*
*
*
* $spreadsheet->getActiveSheet()->getStyle('B2')->getBorders()->applyFromArray(
* [
* 'allBorders' => [
* 'borderStyle' => Border::BORDER_DASHDOT,
* 'color' => [
* 'rgb' => '808080'
* ]
* ]
* ]
* );
*
*
* @param mixed[] $styleArray Array containing style information
*
* @return $this
*/
public function applyFromArray(array $styleArray): static
{
if ($this->isSupervisor) {
$this->getActiveSheet()->getStyle($this->getSelectedCells())->applyFromArray($this->getStyleArray($styleArray));
} else {
/** @var array{left?: float[], right?: float[], top?: float[], bottom?: float[], diagonal?: mixed[], diagonalDirection?: int, allBorders?: mixed[][]} $styleArray */
if (isset($styleArray['left'])) {
$this->getLeft()->applyFromArray($styleArray['left']);
}
if (isset($styleArray['right'])) {
$this->getRight()->applyFromArray($styleArray['right']);
}
if (isset($styleArray['top'])) {
$this->getTop()->applyFromArray($styleArray['top']);
}
if (isset($styleArray['bottom'])) {
$this->getBottom()->applyFromArray($styleArray['bottom']);
}
if (isset($styleArray['diagonal'])) {
$this->getDiagonal()->applyFromArray($styleArray['diagonal']);
}
if (isset($styleArray['diagonalDirection'])) {
$this->setDiagonalDirection($styleArray['diagonalDirection']);
}
if (isset($styleArray['allBorders'])) {
$this->getLeft()->applyFromArray($styleArray['allBorders']);
$this->getRight()->applyFromArray($styleArray['allBorders']);
$this->getTop()->applyFromArray($styleArray['allBorders']);
$this->getBottom()->applyFromArray($styleArray['allBorders']);
}
}
return $this;
}
/**
* Get Left.
*/
public function getLeft(): Border
{
return $this->left;
}
/**
* Get Right.
*/
public function getRight(): Border
{
return $this->right;
}
/**
* Get Top.
*/
public function getTop(): Border
{
return $this->top;
}
/**
* Get Bottom.
*/
public function getBottom(): Border
{
return $this->bottom;
}
/**
* Get Diagonal.
*/
public function getDiagonal(): Border
{
return $this->diagonal;
}
/**
* Get AllBorders (pseudo-border). Only applies to supervisor.
*/
public function getAllBorders(): Border
{
if (!$this->isSupervisor) {
throw new PhpSpreadsheetException('Can only get pseudo-border for supervisor.');
}
return $this->allBorders;
}
/**
* Get Outline (pseudo-border). Only applies to supervisor.
*/
public function getOutline(): Border
{
if (!$this->isSupervisor) {
throw new PhpSpreadsheetException('Can only get pseudo-border for supervisor.');
}
return $this->outline;
}
/**
* Get Inside (pseudo-border). Only applies to supervisor.
*/
public function getInside(): Border
{
if (!$this->isSupervisor) {
throw new PhpSpreadsheetException('Can only get pseudo-border for supervisor.');
}
return $this->inside;
}
/**
* Get Vertical (pseudo-border). Only applies to supervisor.
*/
public function getVertical(): Border
{
if (!$this->isSupervisor) {
throw new PhpSpreadsheetException('Can only get pseudo-border for supervisor.');
}
return $this->vertical;
}
/**
* Get Horizontal (pseudo-border). Only applies to supervisor.
*/
public function getHorizontal(): Border
{
if (!$this->isSupervisor) {
throw new PhpSpreadsheetException('Can only get pseudo-border for supervisor.');
}
return $this->horizontal;
}
/**
* Get DiagonalDirection.
*/
public function getDiagonalDirection(): int
{
if ($this->isSupervisor) {
return $this->getSharedComponent()->getDiagonalDirection();
}
return $this->diagonalDirection;
}
/**
* Set DiagonalDirection.
*
* @param int $direction see self::DIAGONAL_*
*
* @return $this
*/
public function setDiagonalDirection(int $direction): static
{
if ($this->isSupervisor) {
$styleArray = $this->getStyleArray(['diagonalDirection' => $direction]);
$this->getActiveSheet()->getStyle($this->getSelectedCells())->applyFromArray($styleArray);
} else {
$this->diagonalDirection = $direction;
}
return $this;
}
/**
* Get hash code.
*
* @return string Hash code
*/
public function getHashCode(): string
{
if ($this->isSupervisor) {
return $this->getSharedComponent()->getHashcode();
}
return md5(
$this->getLeft()->getHashCode()
. $this->getRight()->getHashCode()
. $this->getTop()->getHashCode()
. $this->getBottom()->getHashCode()
. $this->getDiagonal()->getHashCode()
. $this->getDiagonalDirection()
. __CLASS__
);
}
/** @return mixed[][] */
protected function exportArray1(): array
{
$exportedArray = [];
$this->exportArray2($exportedArray, 'bottom', $this->getBottom());
$this->exportArray2($exportedArray, 'diagonal', $this->getDiagonal());
$this->exportArray2($exportedArray, 'diagonalDirection', $this->getDiagonalDirection());
$this->exportArray2($exportedArray, 'left', $this->getLeft());
$this->exportArray2($exportedArray, 'right', $this->getRight());
$this->exportArray2($exportedArray, 'top', $this->getTop());
/** @var mixed[][] $exportedArray */
return $exportedArray;
}
}
phpspreadsheet/src/PhpSpreadsheet/Style/NumberFormat/FractionFormatter.php 0000644 00000004570 15266563261 0023156 0 ustar 00 0);
return [
implode('.', $masks),
implode('.', array_reverse($postDecimalMasks)),
];
}
private static function processComplexNumberFormatMask(mixed $number, string $mask): string
{
/** @var string $result */
$result = $number;
$maskingBlockCount = preg_match_all('/0+/', $mask, $maskingBlocks, PREG_OFFSET_CAPTURE);
if ($maskingBlockCount > 1) {
$maskingBlocks = array_reverse($maskingBlocks[0]);
$offset = 0;
foreach ($maskingBlocks as $block) {
$size = strlen($block[0]);
$divisor = 10 ** $size;
$offset = $block[1];
/** @var float $numberFloat */
$numberFloat = $number;
$blockValue = sprintf("%0{$size}d", fmod($numberFloat, $divisor));
$number = floor($numberFloat / $divisor);
$mask = substr_replace($mask, $blockValue, $offset, $size);
}
/** @var string $numberString */
$numberString = $number;
if ($number > 0) {
$mask = substr_replace($mask, $numberString, $offset, 0);
}
$result = $mask;
}
return self::makeString($result);
}
private static function complexNumberFormatMask(mixed $number, string $mask, bool $splitOnPoint = true): string
{
/** @var float $numberFloat */
$numberFloat = $number;
if ($splitOnPoint) {
$masks = explode('.', $mask);
if (count($masks) <= 2) {
$decmask = $masks[1] ?? '';
$decpos = substr_count($decmask, '0');
$numberFloat = round($numberFloat, $decpos);
}
}
$sign = ($numberFloat < 0.0) ? '-' : '';
$number = self::f2s(abs($numberFloat));
if ($splitOnPoint && str_contains($mask, '.') && str_contains($number, '.')) {
$numbers = explode('.', $number);
$masks = explode('.', $mask);
if (count($masks) > 2) {
$masks = self::mergeComplexNumberFormatMasks($numbers, $masks);
}
/** @var string[] $masks */
$integerPart = self::complexNumberFormatMask($numbers[0], $masks[0], false);
$numlen = strlen($numbers[1]);
$msklen = strlen($masks[1]);
if ($numlen < $msklen) {
$numbers[1] .= str_repeat('0', $msklen - $numlen);
}
$decimalPart = strrev(self::complexNumberFormatMask(strrev($numbers[1]), strrev($masks[1]), false));
$decimalPart = substr($decimalPart, 0, $msklen);
return "{$sign}{$integerPart}.{$decimalPart}";
}
if (strlen($number) < strlen($mask)) {
$number = str_repeat('0', strlen($mask) - strlen($number)) . $number;
}
$result = self::processComplexNumberFormatMask($number, $mask);
return "{$sign}{$result}";
}
public static function f2s(float $f): string
{
return self::floatStringConvertScientific((string) $f);
}
public static function floatStringConvertScientific(string $s): string
{
// convert only normalized form of scientific notation:
// optional sign, single digit 1-9,
// decimal point and digits (allowed to be omitted),
// E (e permitted), optional sign, one or more digits
if (preg_match('/^([+-])?([1-9])([.]([0-9]+))?[eE]([+-]?[0-9]+)$/', $s, $matches) === 1) {
$exponent = (int) $matches[5];
$sign = ($matches[1] === '-') ? '-' : '';
if ($exponent >= 0) {
$exponentPlus1 = $exponent + 1;
$out = $matches[2] . $matches[4];
$len = strlen($out);
if ($len < $exponentPlus1) {
$out .= str_repeat('0', $exponentPlus1 - $len);
}
$out = substr($out, 0, $exponentPlus1) . ((strlen($out) === $exponentPlus1) ? '' : ('.' . substr($out, $exponentPlus1)));
$s = "$sign$out";
} else {
$s = $sign . '0.' . str_repeat('0', -$exponent - 1) . $matches[2] . $matches[4];
}
}
return $s;
}
/** @param string[] $matches */
private static function formatStraightNumericValue(mixed $value, string $format, array $matches, bool $useThousands): string
{
/** @var float $valueFloat */
$valueFloat = $value;
$left = $matches[1];
$dec = $matches[2];
$right = $matches[3];
// minimun width of formatted number (including dot)
$minWidth = strlen($left) + strlen($dec) + strlen($right);
if ($useThousands) {
$value = number_format(
$valueFloat,
strlen($right),
StringHelper::getDecimalSeparator(),
StringHelper::getThousandsSeparator()
);
return self::pregReplace(self::NUMBER_REGEX, $value, $format);
}
if (preg_match('/[0#]E[+-]0/i', $format)) {
// Scientific format
$decimals = strlen($right);
$size = $decimals + 3;
return sprintf("%{$size}.{$decimals}E", $valueFloat);
}
if (preg_match('/0([^\d\.]+)0/', $format) || substr_count($format, '.') > 1) {
if ($valueFloat == floor($valueFloat) && substr_count($format, '.') === 1) {
$value *= 10 ** strlen(explode('.', $format)[1]); //* @phpstan-ignore-line
}
$result = self::complexNumberFormatMask($value, $format);
if (str_contains($result, 'E')) {
// This is a hack and doesn't match Excel.
// It will, at least, be an accurate representation,
// even if formatted incorrectly.
// This is needed for absolute values >=1E18.
$result = self::f2s($valueFloat);
}
return $result;
}
$sprintf_pattern = "%0$minWidth." . strlen($right) . 'F';
/** @var float $valueFloat */
$valueFloat = $value;
$value = self::adjustSeparators(sprintf($sprintf_pattern, round($valueFloat, strlen($right))));
return self::pregReplace(self::NUMBER_REGEX, $value, $format);
}
/** @param float|int|numeric-string $value value to be formatted */
public static function format(mixed $value, string $format): string
{
// The "_" in this string has already been stripped out,
// so this test is never true. Furthermore, testing
// on Excel shows this format uses Euro symbol, not "EUR".
// if ($format === NumberFormat::FORMAT_CURRENCY_EUR_SIMPLE) {
// return 'EUR ' . sprintf('%1.2f', $value);
// }
$baseFormat = $format;
$useThousands = self::areThousandsRequired($format);
$scale = self::scaleThousandsMillions($format);
if (preg_match('/[#\?0]?.*[#\?0]\/(\?+|\d+|#)/', $format)) {
// It's a dirty hack; but replace # and 0 digit placeholders with ?
$format = (string) preg_replace('/[#0]+\//', '?/', $format);
$format = (string) preg_replace('/\/[#0]+/', '/?', $format);
$value = FractionFormatter::format($value, $format);
} else {
// Handle the number itself
// scale number
$value = $value / $scale;
$paddingPlaceholder = (str_contains($format, '?'));
// Replace # or ? with 0
$format = self::pregReplace('/[\#\?](?=(?:[^"]*"[^"]*")*[^"]*\Z)/', '0', $format);
// Remove locale code [$-###] for an LCID
$format = self::pregReplace('/\[\$\-.*\]/', '', $format);
$n = '/\[[^\]]+\]/';
$m = self::pregReplace($n, '', $format);
// Some non-number strings are quoted, so we'll get rid of the quotes, likewise any positional * symbols
$format = self::makeString(str_replace(['"', '*'], '', $format));
if (preg_match(self::NUMBER_REGEX, $m, $matches)) {
// There are placeholders for digits, so inject digits from the value into the mask
$value = self::formatStraightNumericValue($value, $format, $matches, $useThousands);
if ($paddingPlaceholder === true) {
$value = self::padValue($value, $baseFormat);
}
} elseif ($format !== NumberFormat::FORMAT_GENERAL) {
// Yes, I know that this is basically just a hack;
// if there's no placeholders for digits, just return the format mask "as is"
$value = self::makeString(str_replace('?', '', $format));
}
}
if (preg_match('/\[\$(.*)\]/u', $format, $m)) {
// Currency or Accounting
$value = preg_replace('/-0+(( |\xc2\xa0))?\[/', '- [', (string) $value) ?? $value;
$currencyCode = $m[1];
[$currencyCode] = explode('-', $currencyCode);
if ($currencyCode == '') {
$currencyCode = StringHelper::getCurrencyCode();
}
$value = self::pregReplace('/\[\$([^\]]*)\]/u', $currencyCode, (string) $value);
}
if (
(str_contains((string) $value, '0.'))
&& ((str_contains($baseFormat, '#.')) || (str_contains($baseFormat, '?.')))
) {
$value = preg_replace('/(\b)0\.|([^\d])0\./', '${2}.', (string) $value);
}
return (string) $value;
}
/** @param mixed[]|string $value */
private static function makeString(array|string $value): string
{
return is_array($value) ? '' : "$value";
}
private static function pregReplace(string $pattern, string $replacement, string $subject): string
{
return self::makeString(preg_replace($pattern, $replacement, $subject) ?? '');
}
public static function padValue(string $value, string $baseFormat): string
{
$preDecimal = $postDecimal = '';
$pregArray = preg_split('/\.(?=(?:[^"]*"[^"]*")*[^"]*\Z)/miu', $baseFormat . '.?');
if (is_array($pregArray)) {
$preDecimal = $pregArray[0];
$postDecimal = $pregArray[1] ?? '';
}
$length = strlen($value);
if (str_contains($postDecimal, '?')) {
$value = str_pad(rtrim($value, '0. '), $length, ' ', STR_PAD_RIGHT);
}
if (str_contains($preDecimal, '?')) {
$value = str_pad(ltrim($value, '0, '), $length, ' ', STR_PAD_LEFT);
}
return $value;
}
/**
* Find out if we need thousands separator
* This is indicated by a comma enclosed by a digit placeholders: #, 0 or ?
*/
public static function areThousandsRequired(string &$format): bool
{
$useThousands = (bool) preg_match('/([#\?0]),([#\?0])/', $format);
if ($useThousands) {
$format = self::pregReplace('/([#\?0]),([#\?0])/', '${1}${2}', $format);
}
return $useThousands;
}
/**
* Scale thousands, millions,...
* This is indicated by a number of commas after a digit placeholder: #, or 0.0,, or ?,.
*/
public static function scaleThousandsMillions(string &$format): int
{
$scale = 1; // same as no scale
if (preg_match('/(#|0|\?)(,+)/', $format, $matches)) {
$scale = 1000 ** strlen($matches[2]);
// strip the commas
$format = self::pregReplace('/([#\?0]),+/', '${1}', $format);
}
return $scale;
}
}
phpspreadsheet/src/PhpSpreadsheet/Style/NumberFormat/DateFormatter.php 0000644 00000020111 15266563261 0022253 0 ustar 00 '',
// 12-hour suffix
'am/pm' => 'A',
// 4-digit year
'e' => 'Y',
'yyyy' => 'Y',
// 2-digit year
'yy' => 'y',
// first letter of month - no php equivalent
'mmmmm' => 'M',
// full month name
'mmmm' => 'F',
// short month name
'mmm' => 'M',
// mm is minutes if time, but can also be month w/leading zero
// so we try to identify times be the inclusion of a : separator in the mask
// It isn't perfect, but the best way I know how
':mm' => ':i',
'mm:' => 'i:',
// full day of week name
'dddd' => 'l',
// short day of week name
'ddd' => 'D',
// days leading zero
'dd' => 'd',
// days no leading zero
'd' => 'j',
// fractional seconds - no php equivalent
'.s' => '',
];
/**
* Search/replace values to convert Excel date/time format masks hours to PHP format masks (24 hr clock).
*/
private const DATE_FORMAT_REPLACEMENTS24 = [
'hh' => 'H',
'h' => 'G',
// month leading zero
'mm' => 'm',
// month no leading zero
'm' => 'n',
// seconds
'ss' => 's',
];
/**
* Search/replace values to convert Excel date/time format masks hours to PHP format masks (12 hr clock).
*/
private const DATE_FORMAT_REPLACEMENTS12 = [
'hh' => 'h',
'h' => 'g',
// month leading zero
'mm' => 'm',
// month no leading zero
'm' => 'n',
// seconds
'ss' => 's',
];
private const HOURS_IN_DAY = 24;
private const MINUTES_IN_DAY = 60 * self::HOURS_IN_DAY;
private const SECONDS_IN_DAY = 60 * self::MINUTES_IN_DAY;
private const INTERVAL_PRECISION = 10;
private const INTERVAL_LEADING_ZERO = [
'[hh]',
'[mm]',
'[ss]',
];
private const INTERVAL_ROUND_PRECISION = [
// hours and minutes truncate
'[h]' => self::INTERVAL_PRECISION,
'[hh]' => self::INTERVAL_PRECISION,
'[m]' => self::INTERVAL_PRECISION,
'[mm]' => self::INTERVAL_PRECISION,
// seconds round
'[s]' => 0,
'[ss]' => 0,
];
private const INTERVAL_MULTIPLIER = [
'[h]' => self::HOURS_IN_DAY,
'[hh]' => self::HOURS_IN_DAY,
'[m]' => self::MINUTES_IN_DAY,
'[mm]' => self::MINUTES_IN_DAY,
'[s]' => self::SECONDS_IN_DAY,
'[ss]' => self::SECONDS_IN_DAY,
];
/** @param float|int|numeric-string $value */
private static function tryInterval(bool &$seekingBracket, string &$block, mixed $value, string $format): void
{
if ($seekingBracket) {
if (str_contains($block, $format)) {
$hours = (string) (int) round(
self::INTERVAL_MULTIPLIER[$format] * $value,
self::INTERVAL_ROUND_PRECISION[$format]
);
if (strlen($hours) === 1 && in_array($format, self::INTERVAL_LEADING_ZERO, true)) {
$hours = "0$hours";
}
$block = str_replace($format, $hours, $block);
$seekingBracket = false;
}
}
}
/** @param float|int $value value to be formatted */
public static function format(mixed $value, string $format): string
{
// strip off first part containing e.g. [$-F800] or [$USD-409]
// general syntax: [$-]
// language info is in hexadecimal
// strip off chinese part like [DBNum1][$-804]
$format = (string) preg_replace('/^(\[DBNum\d\])*(\[\$[^\]]*\])/i', '', $format);
// OpenOffice.org uses upper-case number formats, e.g. 'YYYY', convert to lower-case;
// but we don't want to change any quoted strings
/** @var callable $callable */
$callable = [self::class, 'setLowercaseCallback'];
$format = (string) preg_replace_callback('/(?:^|")([^"]*)(?:$|")/', $callable, $format);
// Only process the non-quoted blocks for date format characters
$blocks = explode('"', $format);
foreach ($blocks as $key => &$block) {
if ($key % 2 == 0) {
$block = strtr($block, self::DATE_FORMAT_REPLACEMENTS);
if (!strpos($block, 'A')) {
// 24-hour time format
// when [h]:mm format, the [h] should replace to the hours of the value * 24
$seekingBracket = true;
self::tryInterval($seekingBracket, $block, $value, '[h]');
self::tryInterval($seekingBracket, $block, $value, '[hh]');
self::tryInterval($seekingBracket, $block, $value, '[mm]');
self::tryInterval($seekingBracket, $block, $value, '[m]');
self::tryInterval($seekingBracket, $block, $value, '[s]');
self::tryInterval($seekingBracket, $block, $value, '[ss]');
$block = strtr($block, self::DATE_FORMAT_REPLACEMENTS24);
} else {
// 12-hour time format
$block = strtr($block, self::DATE_FORMAT_REPLACEMENTS12);
}
}
}
$format = implode('"', $blocks);
// escape any quoted characters so that DateTime format() will render them correctly
/** @var callable $callback */
$callback = [self::class, 'escapeQuotesCallback'];
$format = (string) preg_replace_callback('/"(.*)"/U', $callback, $format);
$dateObj = Date::excelToDateTimeObject($value);
// If the colon preceding minute had been quoted, as happens in
// Excel 2003 XML formats, m will not have been changed to i above.
// Change it now.
$format = (string) \preg_replace('/\\\:m/', ':i', $format);
$microseconds = (int) $dateObj->format('u');
if (str_contains($format, ':s.000')) {
$milliseconds = (int) round($microseconds / 1000.0);
if ($milliseconds === 1000) {
$milliseconds = 0;
$dateObj->modify('+1 second');
}
$dateObj->modify("-$microseconds microseconds");
$format = str_replace(':s.000', ':s.' . sprintf('%03d', $milliseconds), $format);
} elseif (str_contains($format, ':s.00')) {
$centiseconds = (int) round($microseconds / 10000.0);
if ($centiseconds === 100) {
$centiseconds = 0;
$dateObj->modify('+1 second');
}
$dateObj->modify("-$microseconds microseconds");
$format = str_replace(':s.00', ':s.' . sprintf('%02d', $centiseconds), $format);
} elseif (str_contains($format, ':s.0')) {
$deciseconds = (int) round($microseconds / 100000.0);
if ($deciseconds === 10) {
$deciseconds = 0;
$dateObj->modify('+1 second');
}
$dateObj->modify("-$microseconds microseconds");
$format = str_replace(':s.0', ':s.' . sprintf('%1d', $deciseconds), $format);
} else { // no fractional second
if ($microseconds >= 500000) {
$dateObj->modify('+1 second');
}
$dateObj->modify("-$microseconds microseconds");
}
return $dateObj->format($format);
}
/** @param string[] $matches */
private static function setLowercaseCallback(array $matches): string
{
return mb_strtolower($matches[0]);
}
/** @param string[] $matches */
private static function escapeQuotesCallback(array $matches): string
{
return '\\' . implode('\\', mb_str_split($matches[1], 1, 'UTF-8'));
}
}
phpspreadsheet/src/PhpSpreadsheet/Style/NumberFormat/Wizard/Wizard.php 0000644 00000000201 15266563261 0022210 0 ustar 00 setDecimals($decimals);
$this->setThousandsSeparator($thousandsSeparator);
$this->setLocale($locale);
}
public function setThousandsSeparator(bool $thousandsSeparator = self::WITH_THOUSANDS_SEPARATOR): void
{
$this->thousandsSeparator = $thousandsSeparator;
}
/**
* As MS Excel cannot easily handle Lakh, which is the only locale-specific Number format variant,
* we don't use locale with Numbers.
*/
protected function getLocaleFormat(): string
{
return $this->format();
}
public function format(): string
{
return sprintf(
'%s0%s',
$this->thousandsSeparator ? '#,##' : null,
$this->decimals > 0 ? '.' . str_repeat('0', $this->decimals) : null
);
}
}
phpspreadsheet/src/PhpSpreadsheet/Style/NumberFormat/Wizard/DateTime.php 0000644 00000002567 15266563261 0022465 0 ustar 00
*/
protected array $formatBlocks;
/**
* @param null|string|string[] $separators
* If you want to use only a single format block, then pass a null as the separator argument
* @param DateTimeWizard|string ...$formatBlocks
*/
public function __construct($separators, ...$formatBlocks)
{
$this->separators = $this->padSeparatorArray(
is_array($separators) ? $separators : [$separators], //* @phpstan-ignore-line
count($formatBlocks) - 1
);
$this->formatBlocks = array_map([$this, 'mapFormatBlocks'], $formatBlocks);
}
private function mapFormatBlocks(DateTimeWizard|string $value): string
{
// Any date masking codes are returned as lower case values
if ($value instanceof DateTimeWizard) {
return $value->__toString();
}
// Wrap any string literals in quotes, so that they're clearly defined as string literals
return $this->wrapLiteral($value);
}
public function format(): string
{
return implode('', array_map([$this, 'intersperse'], $this->formatBlocks, $this->separators));
}
}
phpspreadsheet/src/PhpSpreadsheet/Style/NumberFormat/Wizard/Date.php 0000644 00000006704 15266563261 0021643 0 ustar 00 separators = $this->padSeparatorArray(
is_array($separators) ? $separators : [$separators],
count($formatBlocks) - 1
);
$this->formatBlocks = array_map([$this, 'mapFormatBlocks'], $formatBlocks);
}
private function mapFormatBlocks(string $value): string
{
// Any date masking codes are returned as lower case values
if (in_array(mb_strtolower($value), self::DATE_BLOCKS, true)) {
return mb_strtolower($value);
}
// Wrap any string literals in quotes, so that they're clearly defined as string literals
return $this->wrapLiteral($value);
}
public function format(): string
{
return implode('', array_map([$this, 'intersperse'], $this->formatBlocks, $this->separators));
}
}
phpspreadsheet/src/PhpSpreadsheet/Style/NumberFormat/Wizard/NumberBase.php 0000644 00000004453 15266563261 0023010 0 ustar 00 decimals = ($decimals > self::MAX_DECIMALS) ? self::MAX_DECIMALS : max($decimals, 0);
}
/**
* Setting a locale will override any settings defined in this class.
*
* @throws Exception If the locale code is not a valid format
*/
public function setLocale(?string $locale = null): void
{
if ($locale === null) {
$this->localeFormat = $this->locale = $this->fullLocale = null;
return;
}
$this->locale = $this->validateLocale($locale);
if (class_exists(NumberFormatter::class)) {
$this->localeFormat = $this->getLocaleFormat();
}
}
/**
* Stub: should be implemented as a concrete method in concrete wizards.
*/
abstract protected function getLocaleFormat(): string;
/**
* @throws Exception If the locale code is not a valid format
*/
private function validateLocale(string $locale): string
{
if (preg_match(Locale::STRUCTURE, $locale, $matches, PREG_UNMATCHED_AS_NULL) !== 1) {
throw new Exception("Invalid locale code '{$locale}'");
}
['language' => $language, 'script' => $script, 'country' => $country] = $matches;
// Set case and separator to match standardised locale case
$language = strtolower($language);
$script = ($script === null) ? null : ucfirst(strtolower($script));
$country = ($country === null) ? null : strtoupper($country);
$this->fullLocale = implode('-', array_filter([$language, $script, $country]));
return $country === null ? $language : "{$language}-{$country}";
}
public function format(): string
{
return NumberFormat::FORMAT_GENERAL;
}
public function __toString(): string
{
return $this->format();
}
}
phpspreadsheet/src/PhpSpreadsheet/Style/NumberFormat/Wizard/Time.php 0000644 00000005711 15266563261 0021661 0 ustar 00 separators = $this->padSeparatorArray(
is_array($separators) ? $separators : [$separators],
count($formatBlocks) - 1
);
$this->formatBlocks = array_map([$this, 'mapFormatBlocks'], $formatBlocks);
}
private function mapFormatBlocks(string $value): string
{
// Any date masking codes are returned as lower case values
// except for AM/PM, which is set to uppercase
if (in_array(mb_strtolower($value), self::TIME_BLOCKS, true)) {
return mb_strtolower($value);
} elseif (mb_strtoupper($value) === self::MORNING_AFTERNOON) {
return mb_strtoupper($value);
}
// Wrap any string literals in quotes, so that they're clearly defined as string literals
return $this->wrapLiteral($value);
}
public function format(): string
{
return implode('', array_map([$this, 'intersperse'], $this->formatBlocks, $this->separators));
}
}
phpspreadsheet/src/PhpSpreadsheet/Style/NumberFormat/Wizard/CurrencyNegative.php 0000644 00000001411 15266563261 0024231 0 ustar 00 '-',
self::parentheses, self::redParentheses => '\(',
};
}
public function end(): string
{
return match ($this) {
self::minus, self::redMinus => '',
self::parentheses, self::redParentheses => '\)',
};
}
public function color(): string
{
return match ($this) {
self::redParentheses, self::redMinus => '[Red]',
self::parentheses, self::minus => '',
};
}
}
phpspreadsheet/src/PhpSpreadsheet/Style/NumberFormat/Wizard/CurrencyBase.php 0000644 00000021661 15266563261 0023352 0 ustar 00 setCurrencyCode($currencyCode);
$this->setThousandsSeparator($thousandsSeparator);
$this->setDecimals($decimals);
$this->setCurrencySymbolPosition($currencySymbolPosition);
$this->setCurrencySymbolSpacing($currencySymbolSpacing);
$this->setLocale($locale);
$this->stripLeadingRLM = $stripLeadingRLM;
$this->negative = $negative;
}
public function setCurrencyCode(string $currencyCode): void
{
$this->currencyCode = $currencyCode;
}
public function setCurrencySymbolPosition(bool $currencySymbolPosition = self::LEADING_SYMBOL): void
{
$this->currencySymbolPosition = $currencySymbolPosition;
}
public function setCurrencySymbolSpacing(bool $currencySymbolSpacing = self::SYMBOL_WITHOUT_SPACING): void
{
$this->currencySymbolSpacing = $currencySymbolSpacing;
}
public function setStripLeadingRLM(bool $stripLeadingRLM): void
{
$this->stripLeadingRLM = $stripLeadingRLM;
}
public function setNegative(CurrencyNegative $negative): void
{
$this->negative = $negative;
}
protected function getLocaleFormat(): string
{
$formatter = new Locale($this->fullLocale, NumberFormatter::CURRENCY);
$mask = $formatter->format($this->stripLeadingRLM);
if ($this->decimals === 0) {
$mask = (string) preg_replace('/\.0+/miu', '', $mask);
}
return str_replace('¤', $this->formatCurrencyCode(), $mask);
}
private function formatCurrencyCode(): string
{
if ($this->locale === null) {
return $this->currencyCode;
}
return "[\${$this->currencyCode}-{$this->locale}]";
}
public function format(): string
{
if ($this->localeFormat !== null) {
return $this->localeFormat;
}
$symbolWithSpacing = $this->overrideSpacing ?? ($this->currencySymbolSpacing === self::SYMBOL_WITH_SPACING);
$negative = $this->overrideNegative ?? $this->negative;
// format if positive
$format = '_(';
if ($this->currencySymbolPosition === self::LEADING_SYMBOL) {
$format .= '"' . $this->currencyCode . '"';
if (preg_match('/^[A-Z]{3}$/i', $this->currencyCode) === 1) {
$format .= $this->spaceOrNbsp;
}
if (preg_match('/^[A-Z]{3}$/i', $this->currencyCode) === 1) {
$format .= $this->spaceOrNbsp;
}
if ($symbolWithSpacing) {
$format .= '*' . $this->spaceOrNbsp;
}
}
$format .= $this->thousandsSeparator ? '#,##0' : '0';
if ($this->decimals > 0) {
$format .= '.' . str_repeat('0', $this->decimals);
}
if ($this->currencySymbolPosition === self::TRAILING_SYMBOL) {
if ($symbolWithSpacing) {
$format .= $this->spaceOrNbsp;
} elseif (preg_match('/^[A-Z]{3}$/i', $this->currencyCode) === 1) {
$format .= $this->spaceOrNbsp;
}
$format .= '[$' . $this->currencyCode . ']';
}
$format .= '_)';
// format if negative
$format .= ';_(';
$format .= $negative->color();
$negativeStart = $negative->start();
if ($this->currencySymbolPosition === self::LEADING_SYMBOL) {
if ($negativeStart === '-' && !$symbolWithSpacing) {
$format .= $negativeStart;
}
$format .= '"' . $this->currencyCode . '"';
if (preg_match('/^[A-Z]{3}$/i', $this->currencyCode) === 1) {
$format .= $this->spaceOrNbsp;
}
if ($symbolWithSpacing) {
$format .= '*' . $this->spaceOrNbsp;
}
if ($negativeStart === '\(' || ($symbolWithSpacing && $negativeStart === '-')) {
$format .= $negativeStart;
}
} else {
$format .= $negative->start();
}
$format .= $this->thousandsSeparator ? '#,##0' : '0';
if ($this->decimals > 0) {
$format .= '.' . str_repeat('0', $this->decimals);
}
$format .= $negative->end();
if ($this->currencySymbolPosition === self::TRAILING_SYMBOL) {
if ($symbolWithSpacing) {
// Do nothing - I can't figure out how to get
// everything to align if I put any kind of space here.
//$format .= "\u{2009}";
} elseif (preg_match('/^[A-Z]{3}$/i', $this->currencyCode) === 1) {
$format .= $this->spaceOrNbsp;
}
$format .= '[$' . $this->currencyCode . ']';
}
if ($this->currencySymbolPosition === self::TRAILING_SYMBOL) {
$format .= '_)';
} elseif ($symbolWithSpacing && $negativeStart === '-') {
$format .= ' ';
}
// format if zero
$format .= ';_(';
if ($this->currencySymbolPosition === self::LEADING_SYMBOL) {
$format .= '"' . $this->currencyCode . '"';
}
if ($symbolWithSpacing) {
if ($this->currencySymbolPosition === self::LEADING_SYMBOL) {
$format .= '*' . $this->spaceOrNbsp;
}
$format .= '"-"';
if ($this->decimals > 0) {
$format .= str_repeat('?', $this->decimals);
}
} else {
if (preg_match('/^[A-Z]{3}$/i', $this->currencyCode) === 1) {
$format .= $this->spaceOrNbsp;
}
$format .= '0';
if ($this->decimals > 0) {
$format .= '.' . str_repeat('0', $this->decimals);
}
}
if ($this->currencySymbolPosition === self::TRAILING_SYMBOL) {
if ($symbolWithSpacing) {
$format .= $this->spaceOrNbsp;
}
$format .= '[$' . $this->currencyCode . ']';
}
$format .= '_)';
// format if text
$format .= ';_(@_)';
return $format;
}
}
phpspreadsheet/src/PhpSpreadsheet/Style/NumberFormat/Wizard/DateTimeWizard.php 0000644 00000002427 15266563261 0023641 0 ustar 00 = ";
/**
* @param string[] $separators
*
* @return string[]
*/
protected function padSeparatorArray(array $separators, int $count): array
{
$lastSeparator = (string) array_pop($separators);
return $separators + array_fill(0, $count, $lastSeparator);
}
protected function escapeSingleCharacter(string $value): string
{
if (str_contains(self::NO_ESCAPING_NEEDED, $value)) {
return $value;
}
return "\\{$value}";
}
protected function wrapLiteral(string $value): string
{
if (mb_strlen($value, 'UTF-8') === 1) {
return $this->escapeSingleCharacter($value);
}
// Wrap any other string literals in quotes, so that they're clearly defined as string literals
return '"' . str_replace('"', '""', $value) . '"';
}
protected function intersperse(string $formatBlock, ?string $separator): string
{
return "{$formatBlock}{$separator}";
}
public function __toString(): string
{
return $this->format();
}
}
phpspreadsheet/src/PhpSpreadsheet/Style/NumberFormat/Wizard/Currency.php 0000644 00000000327 15266563261 0022553 0 ustar 00 fullLocale, NumberFormatter::CURRENCY_ACCOUNTING);
$mask = $formatter->format($this->stripLeadingRLM);
if ($this->decimals === 0) {
$mask = (string) preg_replace('/\.0+/miu', '', $mask);
}
return str_replace('¤', $this->formatCurrencyCode(), $mask);
}
public static function icuVersion(): float
{
[$major, $minor] = explode('.', INTL_ICU_VERSION);
return (float) "{$major}.{$minor}";
}
private function formatCurrencyCode(): string
{
if ($this->locale === null) {
return $this->currencyCode . '*';
}
return "[\${$this->currencyCode}-{$this->locale}]";
}
}
phpspreadsheet/src/PhpSpreadsheet/Style/NumberFormat/Wizard/Scientific.php 0000644 00000002146 15266563261 0023042 0 ustar 00 setDecimals($decimals);
$this->setLocale($locale);
}
protected function getLocaleFormat(): string
{
return $this->format();
}
public function format(): string
{
return sprintf('0%sE+00', $this->decimals > 0 ? '.' . str_repeat('0', $this->decimals) : null);
}
}
phpspreadsheet/src/PhpSpreadsheet/Style/NumberFormat/Wizard/Locale.php 0000644 00000002302 15266563261 0022153 0 ustar 00 [a-z]{2})([-_](?P