├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── composer.json └── src └── PhpSpreadsheet ├── Calculation ├── ArrayEnabled.php ├── BinaryComparison.php ├── Calculation.php ├── CalculationBase.php ├── CalculationLocale.php ├── Category.php ├── Database │ ├── DAverage.php │ ├── DCount.php │ ├── DCountA.php │ ├── DGet.php │ ├── DMax.php │ ├── DMin.php │ ├── DProduct.php │ ├── DStDev.php │ ├── DStDevP.php │ ├── DSum.php │ ├── DVar.php │ ├── DVarP.php │ └── DatabaseAbstract.php ├── DateTimeExcel │ ├── Constants.php │ ├── Current.php │ ├── Date.php │ ├── DateParts.php │ ├── DateValue.php │ ├── Days.php │ ├── Days360.php │ ├── Difference.php │ ├── Helpers.php │ ├── Month.php │ ├── NetworkDays.php │ ├── Time.php │ ├── TimeParts.php │ ├── TimeValue.php │ ├── Week.php │ ├── WorkDay.php │ └── YearFrac.php ├── Engine │ ├── ArrayArgumentHelper.php │ ├── ArrayArgumentProcessor.php │ ├── BranchPruner.php │ ├── CyclicReferenceStack.php │ ├── FormattedNumber.php │ ├── Logger.php │ └── Operands │ │ ├── Operand.php │ │ └── StructuredReference.php ├── Engineering │ ├── BesselI.php │ ├── BesselJ.php │ ├── BesselK.php │ ├── BesselY.php │ ├── BitWise.php │ ├── Compare.php │ ├── Complex.php │ ├── ComplexFunctions.php │ ├── ComplexOperations.php │ ├── Constants.php │ ├── ConvertBase.php │ ├── ConvertBinary.php │ ├── ConvertDecimal.php │ ├── ConvertHex.php │ ├── ConvertOctal.php │ ├── ConvertUOM.php │ ├── EngineeringValidations.php │ ├── Erf.php │ └── ErfC.php ├── Exception.php ├── ExceptionHandler.php ├── Financial │ ├── Amortization.php │ ├── CashFlow │ │ ├── CashFlowValidations.php │ │ ├── Constant │ │ │ ├── Periodic.php │ │ │ └── Periodic │ │ │ │ ├── Cumulative.php │ │ │ │ ├── Interest.php │ │ │ │ ├── InterestAndPrincipal.php │ │ │ │ └── Payments.php │ │ ├── Single.php │ │ └── Variable │ │ │ ├── NonPeriodic.php │ │ │ └── Periodic.php │ ├── Constants.php │ ├── Coupons.php │ ├── Depreciation.php │ ├── Dollar.php │ ├── FinancialValidations.php │ ├── Helpers.php │ ├── InterestRate.php │ ├── Securities │ │ ├── AccruedInterest.php │ │ ├── Price.php │ │ ├── Rates.php │ │ ├── SecurityValidations.php │ │ └── Yields.php │ └── TreasuryBill.php ├── FormulaParser.php ├── FormulaToken.php ├── FunctionArray.php ├── Functions.php ├── Information │ ├── ErrorValue.php │ ├── ExcelError.php │ └── Value.php ├── Internal │ ├── ExcelArrayPseudoFunctions.php │ ├── MakeMatrix.php │ └── WildcardMatch.php ├── Logical │ ├── Boolean.php │ ├── Conditional.php │ └── Operations.php ├── LookupRef │ ├── Address.php │ ├── ChooseRowsEtc.php │ ├── ExcelMatch.php │ ├── Filter.php │ ├── Formula.php │ ├── HLookup.php │ ├── Helpers.php │ ├── Hstack.php │ ├── Hyperlink.php │ ├── Indirect.php │ ├── Lookup.php │ ├── LookupBase.php │ ├── LookupRefValidations.php │ ├── Matrix.php │ ├── Offset.php │ ├── RowColumnInformation.php │ ├── Selection.php │ ├── Sort.php │ ├── TorowTocol.php │ ├── Unique.php │ ├── VLookup.php │ └── Vstack.php ├── MathTrig │ ├── Absolute.php │ ├── Angle.php │ ├── Arabic.php │ ├── Base.php │ ├── Ceiling.php │ ├── Combinations.php │ ├── Exp.php │ ├── Factorial.php │ ├── Floor.php │ ├── Gcd.php │ ├── Helpers.php │ ├── IntClass.php │ ├── Lcm.php │ ├── Logarithms.php │ ├── MatrixFunctions.php │ ├── Operations.php │ ├── Random.php │ ├── Roman.php │ ├── Round.php │ ├── SeriesSum.php │ ├── Sign.php │ ├── Sqrt.php │ ├── Subtotal.php │ ├── Sum.php │ ├── SumSquares.php │ ├── Trig │ │ ├── Cosecant.php │ │ ├── Cosine.php │ │ ├── Cotangent.php │ │ ├── Secant.php │ │ ├── Sine.php │ │ └── Tangent.php │ └── Trunc.php ├── Statistical │ ├── AggregateBase.php │ ├── Averages.php │ ├── Averages │ │ └── Mean.php │ ├── Conditional.php │ ├── Confidence.php │ ├── Counts.php │ ├── Deviations.php │ ├── Distributions │ │ ├── Beta.php │ │ ├── Binomial.php │ │ ├── ChiSquared.php │ │ ├── DistributionValidations.php │ │ ├── Exponential.php │ │ ├── F.php │ │ ├── Fisher.php │ │ ├── Gamma.php │ │ ├── GammaBase.php │ │ ├── HyperGeometric.php │ │ ├── LogNormal.php │ │ ├── NewtonRaphson.php │ │ ├── Normal.php │ │ ├── Poisson.php │ │ ├── StandardNormal.php │ │ ├── StudentT.php │ │ └── Weibull.php │ ├── MaxMinBase.php │ ├── Maximum.php │ ├── Minimum.php │ ├── Percentiles.php │ ├── Permutations.php │ ├── Size.php │ ├── StandardDeviations.php │ ├── Standardize.php │ ├── StatisticalValidations.php │ ├── Trends.php │ ├── VarianceBase.php │ └── Variances.php ├── TextData │ ├── CaseConvert.php │ ├── CharacterConvert.php │ ├── Concatenate.php │ ├── Extract.php │ ├── Format.php │ ├── Helpers.php │ ├── Replace.php │ ├── Search.php │ ├── Text.php │ └── Trim.php ├── Token │ └── Stack.php ├── Web │ └── Service.php └── locale │ ├── Translations.xlsx │ ├── bg │ ├── config │ └── functions │ ├── cs │ ├── config │ └── functions │ ├── da │ ├── config │ └── functions │ ├── de │ ├── config │ └── functions │ ├── en │ └── uk │ │ └── config │ ├── es │ ├── config │ └── functions │ ├── fi │ ├── config │ └── functions │ ├── fr │ ├── config │ └── functions │ ├── hu │ ├── config │ └── functions │ ├── it │ ├── config │ └── functions │ ├── nb │ ├── config │ └── functions │ ├── nl │ ├── config │ └── functions │ ├── pl │ ├── config │ └── functions │ ├── pt │ ├── br │ │ ├── config │ │ └── functions │ ├── config │ └── functions │ ├── ru │ ├── config │ └── functions │ ├── sv │ ├── config │ └── functions │ └── tr │ ├── config │ └── functions ├── Cell ├── AddressHelper.php ├── AddressRange.php ├── AdvancedValueBinder.php ├── Cell.php ├── CellAddress.php ├── CellRange.php ├── ColumnRange.php ├── Coordinate.php ├── DataType.php ├── DataValidation.php ├── DataValidator.php ├── DefaultValueBinder.php ├── Hyperlink.php ├── IValueBinder.php ├── IgnoredErrors.php ├── RowRange.php └── StringValueBinder.php ├── CellReferenceHelper.php ├── Chart ├── Axis.php ├── AxisText.php ├── Chart.php ├── ChartColor.php ├── DataSeries.php ├── DataSeriesValues.php ├── Exception.php ├── GridLines.php ├── Layout.php ├── Legend.php ├── PlotArea.php ├── Properties.php ├── Renderer │ ├── IRenderer.php │ ├── JpGraph.php │ ├── JpGraphRendererBase.php │ ├── MtJpGraphRenderer.php │ └── PHP Charting Libraries.txt ├── Title.php └── TrendLine.php ├── Collection ├── Cells.php ├── CellsFactory.php └── Memory │ ├── SimpleCache1.php │ └── SimpleCache3.php ├── Comment.php ├── DefinedName.php ├── Document ├── Properties.php └── Security.php ├── Exception.php ├── HashTable.php ├── Helper ├── Dimension.php ├── Downloader.php ├── Handler.php ├── Html.php ├── Sample.php ├── Size.php └── TextGrid.php ├── IComparable.php ├── IOFactory.php ├── NamedFormula.php ├── NamedRange.php ├── Reader ├── BaseReader.php ├── Csv.php ├── Csv │ └── Delimiter.php ├── DefaultReadFilter.php ├── Exception.php ├── Gnumeric.php ├── Gnumeric │ ├── PageSetup.php │ ├── Properties.php │ └── Styles.php ├── Html.php ├── IReadFilter.php ├── IReader.php ├── Ods.php ├── Ods │ ├── AutoFilter.php │ ├── BaseLoader.php │ ├── DefinedNames.php │ ├── FormulaTranslator.php │ ├── PageSettings.php │ └── Properties.php ├── Security │ └── XmlScanner.php ├── Slk.php ├── Xls.php ├── Xls │ ├── Biff5.php │ ├── Biff8.php │ ├── Color.php │ ├── Color │ │ ├── BIFF5.php │ │ ├── BIFF8.php │ │ └── BuiltIn.php │ ├── ConditionalFormatting.php │ ├── DataValidationHelper.php │ ├── ErrorCode.php │ ├── Escher.php │ ├── ListFunctions.php │ ├── LoadSpreadsheet.php │ ├── MD5.php │ ├── Mappings.php │ ├── RC4.php │ └── Style │ │ ├── Border.php │ │ ├── CellAlignment.php │ │ ├── CellFont.php │ │ └── FillPattern.php ├── XlsBase.php ├── Xlsx.php ├── Xlsx │ ├── AutoFilter.php │ ├── BaseParserClass.php │ ├── Chart.php │ ├── ColumnAndRowAttributes.php │ ├── ConditionalStyles.php │ ├── DataValidations.php │ ├── Hyperlinks.php │ ├── Namespaces.php │ ├── PageSetup.php │ ├── Properties.php │ ├── SharedFormula.php │ ├── SheetViewOptions.php │ ├── SheetViews.php │ ├── Styles.php │ ├── TableReader.php │ ├── Theme.php │ └── WorkbookView.php ├── Xml.php └── Xml │ ├── DataValidations.php │ ├── PageSettings.php │ ├── Properties.php │ ├── Style.php │ └── Style │ ├── Alignment.php │ ├── Border.php │ ├── Fill.php │ ├── Font.php │ ├── NumberFormat.php │ └── StyleBase.php ├── ReferenceHelper.php ├── RichText ├── ITextElement.php ├── RichText.php ├── Run.php └── TextElement.php ├── Settings.php ├── Shared ├── CodePage.php ├── Date.php ├── Drawing.php ├── Escher.php ├── Escher │ ├── DgContainer.php │ ├── DgContainer │ │ ├── SpgrContainer.php │ │ └── SpgrContainer │ │ │ └── SpContainer.php │ ├── DggContainer.php │ └── DggContainer │ │ ├── BstoreContainer.php │ │ └── BstoreContainer │ │ ├── BSE.php │ │ └── BSE │ │ └── Blip.php ├── File.php ├── Font.php ├── IntOrFloat.php ├── OLE.php ├── OLE │ ├── ChainedBlockStream.php │ ├── PPS.php │ └── PPS │ │ ├── File.php │ │ └── Root.php ├── OLERead.php ├── PasswordHasher.php ├── StringHelper.php ├── TimeZone.php ├── Trend │ ├── BestFit.php │ ├── ExponentialBestFit.php │ ├── LinearBestFit.php │ ├── LogarithmicBestFit.php │ ├── PolynomialBestFit.php │ ├── PowerBestFit.php │ └── Trend.php ├── XMLWriter.php └── Xls.php ├── Spreadsheet.php ├── Style ├── Alignment.php ├── Border.php ├── Borders.php ├── Color.php ├── Conditional.php ├── ConditionalFormatting │ ├── CellMatcher.php │ ├── CellStyleAssessor.php │ ├── ConditionalColorScale.php │ ├── ConditionalDataBar.php │ ├── ConditionalDataBarExtension.php │ ├── ConditionalFormatValueObject.php │ ├── ConditionalFormattingRuleExtension.php │ ├── StyleMerger.php │ ├── Wizard.php │ └── Wizard │ │ ├── Blanks.php │ │ ├── CellValue.php │ │ ├── DateValue.php │ │ ├── Duplicates.php │ │ ├── Errors.php │ │ ├── Expression.php │ │ ├── TextValue.php │ │ ├── WizardAbstract.php │ │ └── WizardInterface.php ├── Fill.php ├── Font.php ├── NumberFormat.php ├── NumberFormat │ ├── BaseFormatter.php │ ├── DateFormatter.php │ ├── Formatter.php │ ├── FractionFormatter.php │ ├── NumberFormatter.php │ ├── PercentageFormatter.php │ └── Wizard │ │ ├── Accounting.php │ │ ├── Currency.php │ │ ├── CurrencyBase.php │ │ ├── CurrencyNegative.php │ │ ├── Date.php │ │ ├── DateTime.php │ │ ├── DateTimeWizard.php │ │ ├── Duration.php │ │ ├── Locale.php │ │ ├── Number.php │ │ ├── NumberBase.php │ │ ├── Percentage.php │ │ ├── Scientific.php │ │ ├── Time.php │ │ └── Wizard.php ├── Protection.php ├── RgbTint.php ├── Style.php └── Supervisor.php ├── Theme.php ├── Worksheet ├── AutoFilter.php ├── AutoFilter │ ├── Column.php │ └── Column │ │ └── Rule.php ├── AutoFit.php ├── BaseDrawing.php ├── CellIterator.php ├── Column.php ├── ColumnCellIterator.php ├── ColumnDimension.php ├── ColumnIterator.php ├── Dimension.php ├── Drawing.php ├── Drawing │ └── Shadow.php ├── HeaderFooter.php ├── HeaderFooterDrawing.php ├── Iterator.php ├── MemoryDrawing.php ├── PageBreak.php ├── PageMargins.php ├── PageSetup.php ├── Pane.php ├── ProtectedRange.php ├── Protection.php ├── Row.php ├── RowCellIterator.php ├── RowDimension.php ├── RowIterator.php ├── SheetView.php ├── Table.php ├── Table │ ├── Column.php │ ├── TableDxfsStyle.php │ └── TableStyle.php ├── Validations.php └── Worksheet.php └── Writer ├── BaseWriter.php ├── Csv.php ├── Exception.php ├── Html.php ├── IWriter.php ├── Ods.php ├── Ods ├── AutoFilters.php ├── Cell │ ├── Comment.php │ └── Style.php ├── Content.php ├── Formula.php ├── Meta.php ├── MetaInf.php ├── Mimetype.php ├── NamedExpressions.php ├── Settings.php ├── Styles.php ├── Thumbnails.php └── WriterPart.php ├── Pdf.php ├── Pdf ├── Dompdf.php ├── Mpdf.php └── Tcpdf.php ├── Xls.php ├── Xls ├── BIFFwriter.php ├── CellDataValidation.php ├── ConditionalHelper.php ├── ErrorCode.php ├── Escher.php ├── Font.php ├── Parser.php ├── Style │ ├── CellAlignment.php │ ├── CellBorder.php │ └── CellFill.php ├── Workbook.php ├── Worksheet.php └── Xf.php ├── Xlsx.php ├── Xlsx ├── AutoFilter.php ├── Chart.php ├── Comments.php ├── ContentTypes.php ├── DefinedNames.php ├── DocProps.php ├── Drawing.php ├── FunctionPrefix.php ├── Metadata.php ├── Rels.php ├── RelsRibbon.php ├── RelsVBA.php ├── StringTable.php ├── Style.php ├── Table.php ├── Theme.php ├── Workbook.php ├── Worksheet.php └── WriterPart.php ├── ZipStream0.php ├── ZipStream2.php └── ZipStream3.php /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019-2025 PhpSpreadsheet Authors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Calculation/CalculationBase.php: -------------------------------------------------------------------------------- 1 | 11 | */ 12 | public static function getFunctions(): array 13 | { 14 | return FunctionArray::$phpSpreadsheetFunctions; 15 | } 16 | 17 | /** 18 | * Get address of list of all implemented functions as an array of function objects. 19 | * 20 | * @return array> 21 | */ 22 | protected static function &getFunctionsAddress(): array 23 | { 24 | return FunctionArray::$phpSpreadsheetFunctions; 25 | } 26 | 27 | /** 28 | * @param array{category: string, functionCall: string|string[], argumentCount: string, passCellReference?: bool, passByReference?: bool[], custom?: bool} $value 29 | */ 30 | public static function addFunction(string $key, array $value): bool 31 | { 32 | $key = strtoupper($key); 33 | if (array_key_exists($key, FunctionArray::$phpSpreadsheetFunctions)) { 34 | return false; 35 | } 36 | $value['custom'] = true; 37 | FunctionArray::$phpSpreadsheetFunctions[$key] = $value; 38 | 39 | return true; 40 | } 41 | 42 | public static function removeFunction(string $key): bool 43 | { 44 | $key = strtoupper($key); 45 | if (array_key_exists($key, FunctionArray::$phpSpreadsheetFunctions)) { 46 | if (FunctionArray::$phpSpreadsheetFunctions[$key]['custom'] ?? false) { 47 | unset(FunctionArray::$phpSpreadsheetFunctions[$key]); 48 | 49 | return true; 50 | } 51 | } 52 | 53 | return false; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Calculation/Category.php: -------------------------------------------------------------------------------- 1 | |int|string $field Indicates which column is used in the function. Enter the 23 | * column label enclosed between double quotation marks, such as 24 | * "Age" or "Yield," or a number (without quotation marks) that 25 | * represents the position of the column within the list: 1 for 26 | * the first column, 2 for the second column, and so on. 27 | * @param mixed[][] $criteria The range of cells that contains the conditions you specify. 28 | * You can use any range for the criteria argument, as long as it 29 | * includes at least one column label and at least one cell below 30 | * the column label in which you specify a condition for the 31 | * column. 32 | */ 33 | public static function evaluate(array $database, array|null|int|string $field, array $criteria): string|int|float 34 | { 35 | $field = self::fieldExtract($database, $field); 36 | if ($field === null) { 37 | return ExcelError::VALUE(); 38 | } 39 | 40 | return Averages::average( 41 | self::getFilteredColumn($database, $field, $criteria) 42 | ); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Calculation/Database/DCountA.php: -------------------------------------------------------------------------------- 1 | |int|string $field Indicates which column is used in the function. Enter the 23 | * column label enclosed between double quotation marks, such as 24 | * "Age" or "Yield," or a number (without quotation marks) that 25 | * represents the position of the column within the list: 1 for 26 | * the first column, 2 for the second column, and so on. 27 | * @param mixed[][] $criteria The range of cells that contains the conditions you specify. 28 | * You can use any range for the criteria argument, as long as it 29 | * includes at least one column label and at least one cell below 30 | * the column label in which you specify a condition for the 31 | * column. 32 | */ 33 | public static function evaluate(array $database, array|null|int|string $field, array $criteria): string|int 34 | { 35 | $field = self::fieldExtract($database, $field); 36 | if ($field === null) { 37 | return ExcelError::VALUE(); 38 | } 39 | 40 | return Counts::COUNTA( 41 | self::getFilteredColumn($database, $field, $criteria) 42 | ); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Calculation/Database/DMax.php: -------------------------------------------------------------------------------- 1 | |int|string $field Indicates which column is used in the function. Enter the 24 | * column label enclosed between double quotation marks, such as 25 | * "Age" or "Yield," or a number (without quotation marks) that 26 | * represents the position of the column within the list: 1 for 27 | * the first column, 2 for the second column, and so on. 28 | * @param mixed[][] $criteria The range of cells that contains the conditions you specify. 29 | * You can use any range for the criteria argument, as long as it 30 | * includes at least one column label and at least one cell below 31 | * the column label in which you specify a condition for the 32 | * column. 33 | */ 34 | public static function evaluate(array $database, array|null|int|string $field, array $criteria, bool $returnError = true): null|float|string 35 | { 36 | $field = self::fieldExtract($database, $field); 37 | if ($field === null) { 38 | return $returnError ? ExcelError::VALUE() : null; 39 | } 40 | 41 | return Maximum::max( 42 | self::getFilteredColumn($database, $field, $criteria) 43 | ); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Calculation/Database/DProduct.php: -------------------------------------------------------------------------------- 1 | |int|string $field Indicates which column is used in the function. Enter the 23 | * column label enclosed between double quotation marks, such as 24 | * "Age" or "Yield," or a number (without quotation marks) that 25 | * represents the position of the column within the list: 1 for 26 | * the first column, 2 for the second column, and so on. 27 | * @param mixed[][] $criteria The range of cells that contains the conditions you specify. 28 | * You can use any range for the criteria argument, as long as it 29 | * includes at least one column label and at least one cell below 30 | * the column label in which you specify a condition for the 31 | * column. 32 | */ 33 | public static function evaluate(array $database, array|null|int|string $field, array $criteria): string|float 34 | { 35 | $field = self::fieldExtract($database, $field); 36 | if ($field === null) { 37 | return ExcelError::VALUE(); 38 | } 39 | 40 | return MathTrig\Operations::product( 41 | self::getFilteredColumn($database, $field, $criteria) 42 | ); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Calculation/Database/DSum.php: -------------------------------------------------------------------------------- 1 | |int|string $field Indicates which column is used in the function. Enter the 23 | * column label enclosed between double quotation marks, such as 24 | * "Age" or "Yield," or a number (without quotation marks) that 25 | * represents the position of the column within the list: 1 for 26 | * the first column, 2 for the second column, and so on. 27 | * @param mixed[][] $criteria The range of cells that contains the conditions you specify. 28 | * You can use any range for the criteria argument, as long as it 29 | * includes at least one column label and at least one cell below 30 | * the column label in which you specify a condition for the 31 | * column. 32 | */ 33 | public static function evaluate(array $database, array|null|int|string $field, array $criteria, bool $returnNull = false): null|float|string 34 | { 35 | $field = self::fieldExtract($database, $field); 36 | if ($field === null) { 37 | return $returnNull ? null : ExcelError::VALUE(); 38 | } 39 | 40 | return MathTrig\Sum::sumIgnoringStrings( 41 | self::getFilteredColumn($database, $field, $criteria) 42 | ); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Calculation/DateTimeExcel/Constants.php: -------------------------------------------------------------------------------- 1 | self::DOW_SUNDAY, 28 | self::DOW_MONDAY, 29 | self::STARTWEEK_MONDAY_ALT => self::DOW_MONDAY, 30 | self::DOW_TUESDAY, 31 | self::DOW_WEDNESDAY, 32 | self::DOW_THURSDAY, 33 | self::DOW_FRIDAY, 34 | self::DOW_SATURDAY, 35 | self::DOW_SUNDAY, 36 | self::STARTWEEK_MONDAY_ISO => self::STARTWEEK_MONDAY_ISO, 37 | ]; 38 | } 39 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Calculation/Engine/CyclicReferenceStack.php: -------------------------------------------------------------------------------- 1 | stack); 20 | } 21 | 22 | /** 23 | * Push a new entry onto the stack. 24 | */ 25 | public function push(mixed $value): void 26 | { 27 | $this->stack[$value] = $value; 28 | } 29 | 30 | /** 31 | * Pop the last entry from the stack. 32 | */ 33 | public function pop(): mixed 34 | { 35 | return array_pop($this->stack); 36 | } 37 | 38 | /** 39 | * Test to see if a specified entry exists on the stack. 40 | * 41 | * @param mixed $value The value to test 42 | */ 43 | public function onStack(mixed $value): bool 44 | { 45 | return isset($this->stack[$value]); 46 | } 47 | 48 | /** 49 | * Clear the stack. 50 | */ 51 | public function clear(): void 52 | { 53 | $this->stack = []; 54 | } 55 | 56 | /** 57 | * Return an array of all entries on the stack. 58 | * 59 | * @return mixed[] 60 | */ 61 | public function showStack(): array 62 | { 63 | return $this->stack; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Calculation/Engine/Operands/Operand.php: -------------------------------------------------------------------------------- 1 | 10) { 41 | throw new Exception(ExcelError::NAN()); 42 | } 43 | 44 | return (int) $places; 45 | } 46 | 47 | throw new Exception(ExcelError::VALUE()); 48 | } 49 | 50 | /** 51 | * Formats a number base string value with leading zeroes. 52 | * 53 | * @param string $value The "number" to pad 54 | * @param ?int $places The length that we want to pad this value 55 | * 56 | * @return string The padded "number" 57 | */ 58 | protected static function nbrConversionFormat(string $value, ?int $places): string 59 | { 60 | if ($places !== null) { 61 | if (strlen($value) <= $places) { 62 | return substr(str_pad($value, $places, '0', STR_PAD_LEFT), -10); 63 | } 64 | 65 | return ExcelError::NAN(); 66 | } 67 | 68 | return substr($value, -10); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Calculation/Engineering/EngineeringValidations.php: -------------------------------------------------------------------------------- 1 | line = $line; 18 | $e->file = $file; 19 | 20 | throw $e; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Calculation/ExceptionHandler.php: -------------------------------------------------------------------------------- 1 | interest = $interest; 32 | $this->principal = $principal; 33 | } 34 | 35 | public function interest(): float 36 | { 37 | return $this->interest; 38 | } 39 | 40 | public function principal(): float 41 | { 42 | return $this->principal; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Calculation/Financial/Constants.php: -------------------------------------------------------------------------------- 1 | format('d') === $date->format('t'); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Calculation/Financial/Securities/SecurityValidations.php: -------------------------------------------------------------------------------- 1 | = $maturity) { 19 | throw new Exception(ExcelError::NAN()); 20 | } 21 | } 22 | 23 | public static function validateRedemption(mixed $redemption): float 24 | { 25 | $redemption = self::validateFloat($redemption); 26 | if ($redemption <= 0.0) { 27 | throw new Exception(ExcelError::NAN()); 28 | } 29 | 30 | return $redemption; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Calculation/Internal/MakeMatrix.php: -------------------------------------------------------------------------------- 1 | getWorksheet()->getParentOrThrow()->getSheetByName($worksheetName) 31 | : $cell->getWorksheet(); 32 | } 33 | 34 | if ( 35 | $worksheet === null 36 | || !$worksheet->cellExists($cellReference) 37 | || !$worksheet->getCell($cellReference)->isFormula() 38 | ) { 39 | return ExcelError::NA(); 40 | } 41 | 42 | return $worksheet->getCell($cellReference)->getValueString(); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Calculation/LookupRef/Hstack.php: -------------------------------------------------------------------------------- 1 | $rows) { 35 | $matrix[] = array_pad([], $columns, ExcelError::NA()); 36 | ++$rows; 37 | } 38 | } 39 | 40 | $transpose = array_map(null, ...$inputData); //* @phpstan-ignore-line 41 | $returnMatrix = []; 42 | foreach ($transpose as $array) { 43 | $returnMatrix[] = Functions::flattenArray($array); 44 | } 45 | 46 | return $returnMatrix; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Calculation/LookupRef/Hyperlink.php: -------------------------------------------------------------------------------- 1 | getHyperlink() 42 | ->setUrl($linkURL); 43 | $cell->getHyperlink()->setTooltip($displayName); 44 | 45 | return $displayName; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Calculation/LookupRef/LookupRefValidations.php: -------------------------------------------------------------------------------- 1 | $entryCount)) { 42 | return ExcelError::VALUE(); 43 | } 44 | 45 | if (is_array($chooseArgs[$chosenEntry])) { 46 | return Functions::flattenArray($chooseArgs[$chosenEntry]); 47 | } 48 | 49 | return $chooseArgs[$chosenEntry]; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Calculation/LookupRef/Vstack.php: -------------------------------------------------------------------------------- 1 | |float|int|string rounded number 20 | * If an array of numbers is passed as the argument, then the returned result will also be an array 21 | * with the same dimensions 22 | */ 23 | public static function evaluate(mixed $number): array|string|int|float 24 | { 25 | if (is_array($number)) { 26 | return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $number); 27 | } 28 | 29 | try { 30 | $number = Helpers::validateNumericNullBool($number); 31 | } catch (Exception $e) { 32 | return $e->getMessage(); 33 | } 34 | 35 | return abs($number); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Calculation/MathTrig/Angle.php: -------------------------------------------------------------------------------- 1 | |float|string Rounded number 20 | * If an array of numbers is passed as the argument, then the returned result will also be an array 21 | * with the same dimensions 22 | */ 23 | public static function toDegrees(mixed $number): array|string|float 24 | { 25 | if (is_array($number)) { 26 | return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $number); 27 | } 28 | 29 | try { 30 | $number = Helpers::validateNumericNullBool($number); 31 | } catch (Exception $e) { 32 | return $e->getMessage(); 33 | } 34 | 35 | return rad2deg($number); 36 | } 37 | 38 | /** 39 | * RADIANS. 40 | * 41 | * Returns the result of builtin function deg2rad after validating args. 42 | * 43 | * @param mixed $number Should be numeric, or can be an array of numbers 44 | * 45 | * @return array|float|string Rounded number 46 | * If an array of numbers is passed as the argument, then the returned result will also be an array 47 | * with the same dimensions 48 | */ 49 | public static function toRadians(mixed $number): array|string|float 50 | { 51 | if (is_array($number)) { 52 | return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $number); 53 | } 54 | 55 | try { 56 | $number = Helpers::validateNumericNullBool($number); 57 | } catch (Exception $e) { 58 | return $e->getMessage(); 59 | } 60 | 61 | return deg2rad($number); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Calculation/MathTrig/Exp.php: -------------------------------------------------------------------------------- 1 | |float|string Rounded number 20 | * If an array of numbers is passed as the argument, then the returned result will also be an array 21 | * with the same dimensions 22 | */ 23 | public static function evaluate(mixed $number): array|string|float 24 | { 25 | if (is_array($number)) { 26 | return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $number); 27 | } 28 | 29 | try { 30 | $number = Helpers::validateNumericNullBool($number); 31 | } catch (Exception $e) { 32 | return $e->getMessage(); 33 | } 34 | 35 | return exp($number); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Calculation/MathTrig/Gcd.php: -------------------------------------------------------------------------------- 1 | getMessage(); 53 | } 54 | 55 | if (count($arrayArgs) <= 0) { 56 | return ExcelError::VALUE(); 57 | } 58 | $gcd = (int) array_pop($arrayArgs); 59 | do { 60 | $gcd = self::evaluateGCD($gcd, (int) array_pop($arrayArgs)); 61 | } while (!empty($arrayArgs)); 62 | 63 | return $gcd; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Calculation/MathTrig/IntClass.php: -------------------------------------------------------------------------------- 1 | |float $number Number to cast to an integer, or can be an array of numbers 21 | * 22 | * @return array|int|string Integer value, or a string containing an error 23 | * If an array of numbers is passed as the argument, then the returned result will also be an array 24 | * with the same dimensions 25 | */ 26 | public static function evaluate($number): array|string|int 27 | { 28 | if (is_array($number)) { 29 | return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $number); 30 | } 31 | 32 | try { 33 | $number = Helpers::validateNumericNullBool($number); 34 | } catch (Exception $e) { 35 | return $e->getMessage(); 36 | } 37 | 38 | return (int) floor($number); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Calculation/MathTrig/SeriesSum.php: -------------------------------------------------------------------------------- 1 | |float|int|string The result, or a string containing an error 24 | */ 25 | public static function evaluate(mixed $x, mixed $n, mixed $m, ...$args): array|string|float|int 26 | { 27 | if (is_array($x) || is_array($n) || is_array($m)) { 28 | return self::evaluateArrayArgumentsSubset([self::class, __FUNCTION__], 3, $x, $n, $m, ...$args); 29 | } 30 | 31 | try { 32 | $x = Helpers::validateNumericNullSubstitution($x, 0); 33 | $n = Helpers::validateNumericNullSubstitution($n, 0); 34 | $m = Helpers::validateNumericNullSubstitution($m, 0); 35 | 36 | // Loop through arguments 37 | $aArgs = Functions::flattenArray($args); 38 | $returnValue = 0; 39 | $i = 0; 40 | foreach ($aArgs as $argx) { 41 | if ($argx !== null) { 42 | $arg = Helpers::validateNumericNullSubstitution($argx, 0); 43 | $returnValue += $arg * $x ** ($n + ($m * $i)); 44 | ++$i; 45 | } 46 | } 47 | } catch (Exception $e) { 48 | return $e->getMessage(); 49 | } 50 | 51 | return $returnValue; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Calculation/MathTrig/Sign.php: -------------------------------------------------------------------------------- 1 | |float $number Number to round, or can be an array of numbers 19 | * 20 | * @return array|int|string sign value, or a string containing an error 21 | * If an array of numbers is passed as the argument, then the returned result will also be an array 22 | * with the same dimensions 23 | */ 24 | public static function evaluate($number): array|string|int 25 | { 26 | if (is_array($number)) { 27 | return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $number); 28 | } 29 | 30 | try { 31 | $number = Helpers::validateNumericNullBool($number); 32 | } catch (Exception $e) { 33 | return $e->getMessage(); 34 | } 35 | 36 | return Helpers::returnSign($number); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Calculation/MathTrig/Sqrt.php: -------------------------------------------------------------------------------- 1 | |float|string square root 20 | * If an array of numbers is passed as the argument, then the returned result will also be an array 21 | * with the same dimensions 22 | */ 23 | public static function sqrt(mixed $number) 24 | { 25 | if (is_array($number)) { 26 | return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $number); 27 | } 28 | 29 | try { 30 | $number = Helpers::validateNumericNullBool($number); 31 | } catch (Exception $e) { 32 | return $e->getMessage(); 33 | } 34 | 35 | return Helpers::numberOrNan(sqrt($number)); 36 | } 37 | 38 | /** 39 | * SQRTPI. 40 | * 41 | * Returns the square root of (number * pi). 42 | * 43 | * @param array|float $number Number, or can be an array of numbers 44 | * 45 | * @return array|float|string Square Root of Number * Pi, or a string containing an error 46 | * If an array of numbers is passed as the argument, then the returned result will also be an array 47 | * with the same dimensions 48 | */ 49 | public static function pi($number): array|string|float 50 | { 51 | if (is_array($number)) { 52 | return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $number); 53 | } 54 | 55 | try { 56 | $number = Helpers::validateNumericNullSubstitution($number, 0); 57 | Helpers::validateNotNegative($number); 58 | } catch (Exception $e) { 59 | return $e->getMessage(); 60 | } 61 | 62 | return sqrt($number * M_PI); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Calculation/MathTrig/Trig/Cosecant.php: -------------------------------------------------------------------------------- 1 | |float $angle Number, or can be an array of numbers 19 | * 20 | * @return array|float|string The cosecant of the angle 21 | * If an array of numbers is passed as the argument, then the returned result will also be an array 22 | * with the same dimensions 23 | */ 24 | public static function csc($angle) 25 | { 26 | if (is_array($angle)) { 27 | return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $angle); 28 | } 29 | 30 | try { 31 | $angle = Helpers::validateNumericNullBool($angle); 32 | } catch (Exception $e) { 33 | return $e->getMessage(); 34 | } 35 | 36 | return Helpers::verySmallDenominator(1.0, sin($angle)); 37 | } 38 | 39 | /** 40 | * CSCH. 41 | * 42 | * Returns the hyperbolic cosecant of an angle. 43 | * 44 | * @param array|float $angle Number, or can be an array of numbers 45 | * 46 | * @return array|float|string The hyperbolic cosecant of the angle 47 | * If an array of numbers is passed as the argument, then the returned result will also be an array 48 | * with the same dimensions 49 | */ 50 | public static function csch($angle) 51 | { 52 | if (is_array($angle)) { 53 | return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $angle); 54 | } 55 | 56 | try { 57 | $angle = Helpers::validateNumericNullBool($angle); 58 | } catch (Exception $e) { 59 | return $e->getMessage(); 60 | } 61 | 62 | return Helpers::verySmallDenominator(1.0, sinh($angle)); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Calculation/MathTrig/Trig/Secant.php: -------------------------------------------------------------------------------- 1 | |float $angle Number, or can be an array of numbers 19 | * 20 | * @return array|float|string The secant of the angle 21 | * If an array of numbers is passed as the argument, then the returned result will also be an array 22 | * with the same dimensions 23 | */ 24 | public static function sec($angle) 25 | { 26 | if (is_array($angle)) { 27 | return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $angle); 28 | } 29 | 30 | try { 31 | $angle = Helpers::validateNumericNullBool($angle); 32 | } catch (Exception $e) { 33 | return $e->getMessage(); 34 | } 35 | 36 | return Helpers::verySmallDenominator(1.0, cos($angle)); 37 | } 38 | 39 | /** 40 | * SECH. 41 | * 42 | * Returns the hyperbolic secant of an angle. 43 | * 44 | * @param array|float $angle Number, or can be an array of numbers 45 | * 46 | * @return array|float|string The hyperbolic secant of the angle 47 | * If an array of numbers is passed as the argument, then the returned result will also be an array 48 | * with the same dimensions 49 | */ 50 | public static function sech($angle) 51 | { 52 | if (is_array($angle)) { 53 | return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $angle); 54 | } 55 | 56 | try { 57 | $angle = Helpers::validateNumericNullBool($angle); 58 | } catch (Exception $e) { 59 | return $e->getMessage(); 60 | } 61 | 62 | return Helpers::verySmallDenominator(1.0, cosh($angle)); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Calculation/MathTrig/Trunc.php: -------------------------------------------------------------------------------- 1 | |float|string $value Or can be an array of values 22 | * @param array|float|int|string $digits Or can be an array of values 23 | * 24 | * @return array|float|string Truncated value, or a string containing an error 25 | * If an array of numbers is passed as an argument, then the returned result will also be an array 26 | * with the same dimensions 27 | */ 28 | public static function evaluate(array|float|string|null $value = 0, array|float|int|string $digits = 0): array|float|string 29 | { 30 | if (is_array($value) || is_array($digits)) { 31 | return self::evaluateArrayArguments([self::class, __FUNCTION__], $value, $digits); 32 | } 33 | 34 | return Round::down($value, $digits); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Calculation/Statistical/AggregateBase.php: -------------------------------------------------------------------------------- 1 | |float|string If an array of numbers is passed as an argument, then the returned result will also be an array 27 | * with the same dimensions 28 | */ 29 | public static function CONFIDENCE(mixed $alpha, mixed $stdDev, mixed $size) 30 | { 31 | if (is_array($alpha) || is_array($stdDev) || is_array($size)) { 32 | return self::evaluateArrayArguments([self::class, __FUNCTION__], $alpha, $stdDev, $size); 33 | } 34 | 35 | try { 36 | $alpha = StatisticalValidations::validateFloat($alpha); 37 | $stdDev = StatisticalValidations::validateFloat($stdDev); 38 | $size = StatisticalValidations::validateInt($size); 39 | } catch (Exception $e) { 40 | return $e->getMessage(); 41 | } 42 | 43 | if (($alpha <= 0) || ($alpha >= 1) || ($stdDev <= 0) || ($size < 1)) { 44 | return ExcelError::NAN(); 45 | } 46 | /** @var float $temp */ 47 | $temp = Distributions\StandardNormal::inverse(1 - $alpha / 2); 48 | 49 | /** @var float */ 50 | $result = Functions::scalar($temp * $stdDev / sqrt($size)); 51 | 52 | return $result; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Calculation/Statistical/Distributions/DistributionValidations.php: -------------------------------------------------------------------------------- 1 | 1.0) { 16 | throw new Exception(ExcelError::NAN()); 17 | } 18 | 19 | return $probability; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Calculation/Statistical/Distributions/Exponential.php: -------------------------------------------------------------------------------- 1 | |float|string If an array of numbers is passed as an argument, then the returned result will also be an array 28 | * with the same dimensions 29 | */ 30 | public static function distribution(mixed $value, mixed $lambda, mixed $cumulative): array|string|float 31 | { 32 | if (is_array($value) || is_array($lambda) || is_array($cumulative)) { 33 | return self::evaluateArrayArguments([self::class, __FUNCTION__], $value, $lambda, $cumulative); 34 | } 35 | 36 | try { 37 | $value = DistributionValidations::validateFloat($value); 38 | $lambda = DistributionValidations::validateFloat($lambda); 39 | $cumulative = DistributionValidations::validateBool($cumulative); 40 | } catch (Exception $e) { 41 | return $e->getMessage(); 42 | } 43 | 44 | if (($value < 0) || ($lambda < 0)) { 45 | return ExcelError::NAN(); 46 | } 47 | 48 | if ($cumulative === true) { 49 | return 1 - exp(0 - $value * $lambda); 50 | } 51 | 52 | return $lambda * exp(0 - $value * $lambda); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Calculation/Statistical/Distributions/NewtonRaphson.php: -------------------------------------------------------------------------------- 1 | callback = $callback; 19 | } 20 | 21 | public function execute(float $probability): string|int|float 22 | { 23 | $xLo = 100; 24 | $xHi = 0; 25 | 26 | $dx = 1; 27 | $x = $xNew = 1; 28 | $i = 0; 29 | 30 | while ((abs($dx) > Functions::PRECISION) && ($i++ < self::MAX_ITERATIONS)) { 31 | // Apply Newton-Raphson step 32 | $result = call_user_func($this->callback, $x); 33 | if (!is_float($result)) { 34 | return ExcelError::VALUE(); 35 | } 36 | $error = $result - $probability; 37 | 38 | if ($error == 0.0) { 39 | $dx = 0; 40 | } elseif ($error < 0.0) { 41 | $xLo = $x; 42 | } else { 43 | $xHi = $x; 44 | } 45 | 46 | // Avoid division by zero 47 | if ($result != 0.0) { 48 | $dx = $error / $result; 49 | $xNew = $x - $dx; 50 | } 51 | 52 | // If the NR fails to converge (which for example may be the 53 | // case if the initial guess is too rough) we apply a bisection 54 | // step to determine a more narrow interval around the root. 55 | if (($xNew < $xLo) || ($xNew > $xHi) || ($result == 0.0)) { 56 | $xNew = ($xLo + $xHi) / 2; 57 | $dx = $xNew - $x; 58 | } 59 | $x = $xNew; 60 | } 61 | 62 | if ($i == self::MAX_ITERATIONS) { 63 | return ExcelError::NA(); 64 | } 65 | 66 | return $x; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Calculation/Statistical/MaxMinBase.php: -------------------------------------------------------------------------------- 1 | |float $value Value to normalize 19 | * Or can be an array of values 20 | * @param array|float $mean Mean Value 21 | * Or can be an array of values 22 | * @param array|float $stdDev Standard Deviation 23 | * Or can be an array of values 24 | * 25 | * @return array|float|string Standardized value, or a string containing an error 26 | * If an array of numbers is passed as an argument, then the returned result will also be an array 27 | * with the same dimensions 28 | */ 29 | public static function execute($value, $mean, $stdDev): array|string|float 30 | { 31 | if (is_array($value) || is_array($mean) || is_array($stdDev)) { 32 | return self::evaluateArrayArguments([self::class, __FUNCTION__], $value, $mean, $stdDev); 33 | } 34 | 35 | try { 36 | $value = self::validateFloat($value); 37 | $mean = self::validateFloat($mean); 38 | $stdDev = self::validateFloat($stdDev); 39 | } catch (Exception $e) { 40 | return $e->getMessage(); 41 | } 42 | 43 | if ($stdDev <= 0) { 44 | return ExcelError::NAN(); 45 | } 46 | 47 | return ($value - $mean) / $stdDev; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Calculation/Statistical/StatisticalValidations.php: -------------------------------------------------------------------------------- 1 | |string If an array of values is passed as the argument, then the returned result will also be an array 18 | * with the same dimensions 19 | */ 20 | public static function nonPrintable(mixed $stringValue = '') 21 | { 22 | if (is_array($stringValue)) { 23 | return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $stringValue); 24 | } 25 | 26 | $stringValue = Helpers::extractString($stringValue); 27 | 28 | return (string) preg_replace('/[\x00-\x1f]/', '', "$stringValue"); 29 | } 30 | 31 | /** 32 | * TRIM. 33 | * 34 | * @param mixed $stringValue String Value to check 35 | * Or can be an array of values 36 | * 37 | * @return array|string If an array of values is passed as the argument, then the returned result will also be an array 38 | * with the same dimensions 39 | */ 40 | public static function spaces(mixed $stringValue = ''): array|string 41 | { 42 | if (is_array($stringValue)) { 43 | return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $stringValue); 44 | } 45 | 46 | $stringValue = Helpers::extractString($stringValue); 47 | 48 | return trim(preg_replace('/ +/', ' ', trim("$stringValue", ' ')) ?? '', ' '); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Calculation/Web/Service.php: -------------------------------------------------------------------------------- 1 | 2048) { 25 | return ExcelError::VALUE(); // Invalid URL length 26 | } 27 | 28 | if (!preg_match('/^http[s]?:\/\//', $url)) { 29 | return ExcelError::VALUE(); // Invalid protocol 30 | } 31 | 32 | // Get results from the webservice 33 | $client = Settings::getHttpClient(); 34 | $requestFactory = Settings::getRequestFactory(); 35 | $request = $requestFactory->createRequest('GET', $url); 36 | 37 | try { 38 | $response = $client->sendRequest($request); 39 | } catch (ClientExceptionInterface) { 40 | return ExcelError::VALUE(); // cURL error 41 | } 42 | 43 | if ($response->getStatusCode() != 200) { 44 | return ExcelError::VALUE(); // cURL error 45 | } 46 | 47 | $output = $response->getBody()->getContents(); 48 | if (strlen($output) > 32767) { 49 | return ExcelError::VALUE(); // Output not a string or too long 50 | } 51 | 52 | return $output; 53 | } 54 | 55 | /** 56 | * URLENCODE. 57 | * 58 | * Returns data from a web service on the Internet or Intranet. 59 | * 60 | * Excel Function: 61 | * urlEncode(text) 62 | * 63 | * @return string the url encoded output 64 | */ 65 | public static function urlEncode(mixed $text): string 66 | { 67 | if (!is_string($text)) { 68 | return ExcelError::VALUE(); 69 | } 70 | 71 | return str_replace('+', '%20', urlencode($text)); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Calculation/locale/Translations.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PHPOffice/PhpSpreadsheet/44c3bd564b9913fac38bb1b565654d6bf7b5419a/src/PhpSpreadsheet/Calculation/locale/Translations.xlsx -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Calculation/locale/bg/config: -------------------------------------------------------------------------------- 1 | ############################################################ 2 | ## 3 | ## PhpSpreadsheet - locale settings 4 | ## 5 | ## български (Bulgarian) 6 | ## 7 | ############################################################ 8 | 9 | ArgumentSeparator = ; 10 | ## 11 | ## (For future use) 12 | ## 13 | currencySymbol = лв 14 | 15 | ## 16 | ## Error Codes 17 | ## 18 | NULL = #ПРАЗНО! 19 | DIV0 = #ДЕЛ/0! 20 | VALUE = #СТОЙНОСТ! 21 | REF = #РЕФ! 22 | NAME = #ИМЕ? 23 | NUM = #ЧИСЛО! 24 | NA = #Н/Д 25 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Calculation/locale/cs/config: -------------------------------------------------------------------------------- 1 | ############################################################ 2 | ## 3 | ## PhpSpreadsheet - locale settings 4 | ## 5 | ## Ceština (Czech) 6 | ## 7 | ############################################################ 8 | 9 | ArgumentSeparator = ; 10 | 11 | ## 12 | ## Error Codes 13 | ## 14 | NULL 15 | DIV0 = #DĚLENÍ_NULOU! 16 | VALUE = #HODNOTA! 17 | REF = #ODKAZ! 18 | NAME = #NÁZEV? 19 | NUM = #ČÍSLO! 20 | NA = #NENÍ_K_DISPOZICI 21 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Calculation/locale/da/config: -------------------------------------------------------------------------------- 1 | ############################################################ 2 | ## 3 | ## PhpSpreadsheet - locale settings 4 | ## 5 | ## Dansk (Danish) 6 | ## 7 | ############################################################ 8 | 9 | ArgumentSeparator = ; 10 | 11 | ## 12 | ## Error Codes 13 | ## 14 | NULL = #NUL! 15 | DIV0 16 | VALUE = #VÆRDI! 17 | REF = #REFERENCE! 18 | NAME = #NAVN? 19 | NUM 20 | NA = #I/T 21 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Calculation/locale/de/config: -------------------------------------------------------------------------------- 1 | ############################################################ 2 | ## 3 | ## PhpSpreadsheet - locale settings 4 | ## 5 | ## Deutsch (German) 6 | ## 7 | ############################################################ 8 | 9 | ArgumentSeparator = ; 10 | 11 | ## 12 | ## Error Codes 13 | ## 14 | NULL 15 | DIV0 16 | VALUE = #WERT! 17 | REF = #BEZUG! 18 | NAME 19 | NUM = #ZAHL! 20 | NA = #NV 21 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Calculation/locale/en/uk/config: -------------------------------------------------------------------------------- 1 | ############################################################ 2 | ## 3 | ## PhpSpreadsheet - locale settings 4 | ## 5 | ## English-UK (English-UK) 6 | ## 7 | ############################################################ 8 | 9 | ArgumentSeparator = , 10 | ## 11 | ## (For future use) 12 | ## 13 | currencySymbol = £ 14 | 15 | ## 16 | ## Error Codes 17 | ## 18 | NULL 19 | DIV0 20 | VALUE 21 | REF 22 | NAME 23 | NUM 24 | NA 25 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Calculation/locale/es/config: -------------------------------------------------------------------------------- 1 | ############################################################ 2 | ## 3 | ## PhpSpreadsheet - locale settings 4 | ## 5 | ## Español (Spanish) 6 | ## 7 | ############################################################ 8 | 9 | ArgumentSeparator = ; 10 | 11 | ## 12 | ## Error Codes 13 | ## 14 | NULL = #¡NULO! 15 | DIV0 = #¡DIV/0! 16 | VALUE = #¡VALOR! 17 | REF = #¡REF! 18 | NAME = #¿NOMBRE? 19 | NUM = #¡NUM! 20 | NA 21 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Calculation/locale/fi/config: -------------------------------------------------------------------------------- 1 | ############################################################ 2 | ## 3 | ## PhpSpreadsheet - locale settings 4 | ## 5 | ## Suomi (Finnish) 6 | ## 7 | ############################################################ 8 | 9 | ArgumentSeparator = ; 10 | 11 | ## 12 | ## Error Codes 13 | ## 14 | NULL = #TYHJÄ! 15 | DIV0 = #JAKO/0! 16 | VALUE = #ARVO! 17 | REF = #VIITTAUS! 18 | NAME = #NIMI? 19 | NUM = #LUKU! 20 | NA = #PUUTTUU! 21 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Calculation/locale/fr/config: -------------------------------------------------------------------------------- 1 | ############################################################ 2 | ## 3 | ## PhpSpreadsheet - locale settings 4 | ## 5 | ## Français (French) 6 | ## 7 | ############################################################ 8 | 9 | ArgumentSeparator = ; 10 | 11 | ## 12 | ## Error Codes 13 | ## 14 | NULL = #NUL! 15 | DIV0 16 | VALUE = #VALEUR! 17 | REF 18 | NAME = #NOM? 19 | NUM = #NOMBRE! 20 | NA 21 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Calculation/locale/hu/config: -------------------------------------------------------------------------------- 1 | ############################################################ 2 | ## 3 | ## PhpSpreadsheet - locale settings 4 | ## 5 | ## Magyar (Hungarian) 6 | ## 7 | ############################################################ 8 | 9 | ArgumentSeparator = ; 10 | 11 | ## 12 | ## Error Codes 13 | ## 14 | NULL = #NULLA! 15 | DIV0 = #ZÉRÓOSZTÓ! 16 | VALUE = #ÉRTÉK! 17 | REF = #HIV! 18 | NAME = #NÉV? 19 | NUM = #SZÁM! 20 | NA = #HIÁNYZIK 21 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Calculation/locale/it/config: -------------------------------------------------------------------------------- 1 | ############################################################ 2 | ## 3 | ## PhpSpreadsheet - locale settings 4 | ## 5 | ## Italiano (Italian) 6 | ## 7 | ############################################################ 8 | 9 | ArgumentSeparator = ; 10 | 11 | ## 12 | ## Error Codes 13 | ## 14 | NULL 15 | DIV0 16 | VALUE = #VALORE! 17 | REF = #RIF! 18 | NAME = #NOME? 19 | NUM 20 | NA = #N/D 21 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Calculation/locale/nb/config: -------------------------------------------------------------------------------- 1 | ############################################################ 2 | ## 3 | ## PhpSpreadsheet - locale settings 4 | ## 5 | ## Norsk Bokmål (Norwegian Bokmål) 6 | ## 7 | ############################################################ 8 | 9 | ArgumentSeparator = ; 10 | 11 | ## 12 | ## Error Codes 13 | ## 14 | NULL 15 | DIV0 16 | VALUE = #VERDI! 17 | REF 18 | NAME = #NAVN? 19 | NUM 20 | NA = #N/D 21 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Calculation/locale/nl/config: -------------------------------------------------------------------------------- 1 | ############################################################ 2 | ## 3 | ## PhpSpreadsheet - locale settings 4 | ## 5 | ## Nederlands (Dutch) 6 | ## 7 | ############################################################ 8 | 9 | ArgumentSeparator = ; 10 | 11 | ## 12 | ## Error Codes 13 | ## 14 | NULL = #LEEG! 15 | DIV0 = #DEEL/0! 16 | VALUE = #WAARDE! 17 | REF = #VERW! 18 | NAME = #NAAM? 19 | NUM = #GETAL! 20 | NA = #N/B 21 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Calculation/locale/pl/config: -------------------------------------------------------------------------------- 1 | ############################################################ 2 | ## 3 | ## PhpSpreadsheet - locale settings 4 | ## 5 | ## Jezyk polski (Polish) 6 | ## 7 | ############################################################ 8 | 9 | ArgumentSeparator = ; 10 | 11 | ## 12 | ## Error Codes 13 | ## 14 | NULL = #ZERO! 15 | DIV0 = #DZIEL/0! 16 | VALUE = #ARG! 17 | REF = #ADR! 18 | NAME = #NAZWA? 19 | NUM = #LICZBA! 20 | NA = #N/D! 21 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Calculation/locale/pt/br/config: -------------------------------------------------------------------------------- 1 | ############################################################ 2 | ## 3 | ## PhpSpreadsheet - locale settings 4 | ## 5 | ## Português Brasileiro (Brazilian Portuguese) 6 | ## 7 | ############################################################ 8 | 9 | ArgumentSeparator = ; 10 | 11 | ## 12 | ## Error Codes 13 | ## 14 | NULL = #NULO! 15 | DIV0 16 | VALUE = #VALOR! 17 | REF 18 | NAME = #NOME? 19 | NUM = #NÚM! 20 | NA = #N/D 21 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Calculation/locale/pt/config: -------------------------------------------------------------------------------- 1 | ############################################################ 2 | ## 3 | ## PhpSpreadsheet - locale settings 4 | ## 5 | ## Português (Portuguese) 6 | ## 7 | ############################################################ 8 | 9 | ArgumentSeparator = ; 10 | 11 | ## 12 | ## Error Codes 13 | ## 14 | NULL = #NULO! 15 | DIV0 16 | VALUE = #VALOR! 17 | REF 18 | NAME = #NOME? 19 | NUM = #NÚM! 20 | NA = #N/D 21 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Calculation/locale/ru/config: -------------------------------------------------------------------------------- 1 | ############################################################ 2 | ## 3 | ## PhpSpreadsheet - locale settings 4 | ## 5 | ## русский язык (Russian) 6 | ## 7 | ############################################################ 8 | 9 | ArgumentSeparator = ; 10 | 11 | ## 12 | ## Error Codes 13 | ## 14 | NULL = #ПУСТО! 15 | DIV0 = #ДЕЛ/0! 16 | VALUE = #ЗНАЧ! 17 | REF = #ССЫЛКА! 18 | NAME = #ИМЯ? 19 | NUM = #ЧИСЛО! 20 | NA = #Н/Д 21 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Calculation/locale/sv/config: -------------------------------------------------------------------------------- 1 | ############################################################ 2 | ## 3 | ## PhpSpreadsheet - locale settings 4 | ## 5 | ## Svenska (Swedish) 6 | ## 7 | ############################################################ 8 | 9 | ArgumentSeparator = ; 10 | 11 | ## 12 | ## Error Codes 13 | ## 14 | NULL = #SKÄRNING! 15 | DIV0 = #DIVISION/0! 16 | VALUE = #VÄRDEFEL! 17 | REF = #REFERENS! 18 | NAME = #NAMN? 19 | NUM = #OGILTIGT! 20 | NA = #SAKNAS! 21 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Calculation/locale/tr/config: -------------------------------------------------------------------------------- 1 | ############################################################ 2 | ## 3 | ## PhpSpreadsheet - locale settings 4 | ## 5 | ## Türkçe (Turkish) 6 | ## 7 | ############################################################ 8 | 9 | ArgumentSeparator = ; 10 | 11 | ## 12 | ## Error Codes 13 | ## 14 | NULL = #BOŞ! 15 | DIV0 = #SAYI/0! 16 | VALUE = #DEĞER! 17 | REF = #BAŞV! 18 | NAME = #AD? 19 | NUM = #SAYI! 20 | NA = #YOK 21 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Cell/AddressRange.php: -------------------------------------------------------------------------------- 1 | url = $url; 27 | $this->tooltip = $tooltip; 28 | } 29 | 30 | /** 31 | * Get URL. 32 | */ 33 | public function getUrl(): string 34 | { 35 | return $this->url; 36 | } 37 | 38 | /** 39 | * Set URL. 40 | * 41 | * @return $this 42 | */ 43 | public function setUrl(string $url): static 44 | { 45 | $this->url = $url; 46 | 47 | return $this; 48 | } 49 | 50 | /** 51 | * Get tooltip. 52 | */ 53 | public function getTooltip(): string 54 | { 55 | return $this->tooltip; 56 | } 57 | 58 | /** 59 | * Set tooltip. 60 | * 61 | * @return $this 62 | */ 63 | public function setTooltip(string $tooltip): static 64 | { 65 | $this->tooltip = $tooltip; 66 | 67 | return $this; 68 | } 69 | 70 | /** 71 | * Is this hyperlink internal? (to another worksheet or a cell in this worksheet). 72 | */ 73 | public function isInternal(): bool 74 | { 75 | return str_starts_with($this->url, 'sheet://') || str_starts_with($this->url, '#'); 76 | } 77 | 78 | public function getTypeHyperlink(): string 79 | { 80 | return $this->isInternal() ? '' : 'External'; 81 | } 82 | 83 | /** 84 | * Get hash code. 85 | * 86 | * @return string Hash code 87 | */ 88 | public function getHashCode(): string 89 | { 90 | return md5( 91 | $this->url 92 | . $this->tooltip 93 | . __CLASS__ 94 | ); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Cell/IValueBinder.php: -------------------------------------------------------------------------------- 1 | numberStoredAsText = $value; 20 | 21 | return $this; 22 | } 23 | 24 | public function getNumberStoredAsText(): bool 25 | { 26 | return $this->numberStoredAsText; 27 | } 28 | 29 | public function setFormula(bool $value): self 30 | { 31 | $this->formula = $value; 32 | 33 | return $this; 34 | } 35 | 36 | public function getFormula(): bool 37 | { 38 | return $this->formula; 39 | } 40 | 41 | public function setFormulaRange(bool $value): self 42 | { 43 | $this->formulaRange = $value; 44 | 45 | return $this; 46 | } 47 | 48 | public function getFormulaRange(): bool 49 | { 50 | return $this->formulaRange; 51 | } 52 | 53 | public function setTwoDigitTextYear(bool $value): self 54 | { 55 | $this->twoDigitTextYear = $value; 56 | 57 | return $this; 58 | } 59 | 60 | public function getTwoDigitTextYear(): bool 61 | { 62 | return $this->twoDigitTextYear; 63 | } 64 | 65 | public function setEvalError(bool $value): self 66 | { 67 | $this->evalError = $value; 68 | 69 | return $this; 70 | } 71 | 72 | public function getEvalError(): bool 73 | { 74 | return $this->evalError; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Chart/AxisText.php: -------------------------------------------------------------------------------- 1 | font = new Font(); 17 | $this->font->setSize(null, true); 18 | } 19 | 20 | public function setRotation(?int $rotation): self 21 | { 22 | $this->rotation = $rotation; 23 | 24 | return $this; 25 | } 26 | 27 | public function getRotation(): ?int 28 | { 29 | return $this->rotation; 30 | } 31 | 32 | public function getFillColorObject(): ChartColor 33 | { 34 | $fillColor = $this->font->getChartColor(); 35 | if ($fillColor === null) { 36 | $fillColor = new ChartColor(); 37 | $this->font->setChartColorFromObject($fillColor); 38 | } 39 | 40 | return $fillColor; 41 | } 42 | 43 | public function getFont(): Font 44 | { 45 | return $this->font; 46 | } 47 | 48 | public function setFont(Font $font): self 49 | { 50 | $this->font = $font; 51 | 52 | return $this; 53 | } 54 | 55 | /** 56 | * Implement PHP __clone to create a deep clone, not just a shallow copy. 57 | */ 58 | public function __clone() 59 | { 60 | parent::__clone(); 61 | $this->font = clone $this->font; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Chart/Exception.php: -------------------------------------------------------------------------------- 1 | cache = []; 28 | 29 | return true; 30 | } 31 | 32 | public function delete($key): bool 33 | { 34 | unset($this->cache[$key]); 35 | 36 | return true; 37 | } 38 | 39 | public function deleteMultiple($keys): bool 40 | { 41 | foreach ($keys as $key) { 42 | $this->delete($key); 43 | } 44 | 45 | return true; 46 | } 47 | 48 | public function get($key, $default = null): mixed 49 | { 50 | if ($this->has($key)) { 51 | return $this->cache[$key]; 52 | } 53 | 54 | return $default; 55 | } 56 | 57 | public function getMultiple($keys, $default = null): iterable 58 | { 59 | $results = []; 60 | foreach ($keys as $key) { 61 | $results[$key] = $this->get($key, $default); 62 | } 63 | 64 | return $results; 65 | } 66 | 67 | public function has($key): bool 68 | { 69 | return array_key_exists($key, $this->cache); 70 | } 71 | 72 | public function set($key, $value, $ttl = null): bool 73 | { 74 | $this->cache[$key] = $value; 75 | 76 | return true; 77 | } 78 | 79 | public function setMultiple($values, $ttl = null): bool 80 | { 81 | foreach ($values as $key => $value) { 82 | $this->set($key, $value); 83 | } 84 | 85 | return true; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Collection/Memory/SimpleCache3.php: -------------------------------------------------------------------------------- 1 | cache = []; 21 | 22 | return true; 23 | } 24 | 25 | public function delete(string $key): bool 26 | { 27 | unset($this->cache[$key]); 28 | 29 | return true; 30 | } 31 | 32 | public function deleteMultiple(iterable $keys): bool 33 | { 34 | foreach ($keys as $key) { 35 | $this->delete($key); 36 | } 37 | 38 | return true; 39 | } 40 | 41 | public function get(string $key, mixed $default = null): mixed 42 | { 43 | if ($this->has($key)) { 44 | return $this->cache[$key]; 45 | } 46 | 47 | return $default; 48 | } 49 | 50 | public function getMultiple(iterable $keys, mixed $default = null): iterable 51 | { 52 | $results = []; 53 | foreach ($keys as $key) { 54 | $results[$key] = $this->get($key, $default); 55 | } 56 | 57 | return $results; 58 | } 59 | 60 | public function has(string $key): bool 61 | { 62 | return array_key_exists($key, $this->cache); 63 | } 64 | 65 | public function set(string $key, mixed $value, null|int|DateInterval $ttl = null): bool 66 | { 67 | $this->cache[$key] = $value; 68 | 69 | return true; 70 | } 71 | 72 | public function setMultiple(iterable $values, null|int|DateInterval $ttl = null): bool 73 | { 74 | foreach ($values as $key => $value) { 75 | $this->set($key, $value); 76 | } 77 | 78 | return true; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Exception.php: -------------------------------------------------------------------------------- 1 | \d*\.?\d+)(?Ppt|px|em)?$/i'; 10 | 11 | protected bool $valid = false; 12 | 13 | protected string $size = ''; 14 | 15 | protected string $unit = ''; 16 | 17 | public function __construct(string $size) 18 | { 19 | if (1 === preg_match(self::REGEXP_SIZE_VALIDATION, $size, $matches)) { 20 | $this->valid = true; 21 | $this->size = $matches['size']; 22 | $this->unit = $matches['unit'] ?? 'pt'; 23 | } 24 | } 25 | 26 | public function valid(): bool 27 | { 28 | return $this->valid; 29 | } 30 | 31 | public function size(): string 32 | { 33 | return $this->size; 34 | } 35 | 36 | public function unit(): string 37 | { 38 | return $this->unit; 39 | } 40 | 41 | public function __toString(): string 42 | { 43 | return $this->size . $this->unit; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/IComparable.php: -------------------------------------------------------------------------------- 1 | value; 32 | } 33 | 34 | /** 35 | * Set the formula value. 36 | */ 37 | public function setFormula(string $formula): self 38 | { 39 | if (!empty($formula)) { 40 | $this->value = $formula; 41 | } 42 | 43 | return $this; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/NamedRange.php: -------------------------------------------------------------------------------- 1 | value; 32 | } 33 | 34 | /** 35 | * Set the range value. 36 | */ 37 | public function setRange(string $range): self 38 | { 39 | if (!empty($range)) { 40 | $this->value = $range; 41 | } 42 | 43 | return $this; 44 | } 45 | 46 | /** @return string[] */ 47 | public function getCellsInRange(): array 48 | { 49 | $range = $this->value; 50 | if (str_starts_with($range, '=')) { 51 | $range = substr($range, 1); 52 | } 53 | 54 | return Coordinate::extractAllCellReferencesInRange($range); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Reader/DefaultReadFilter.php: -------------------------------------------------------------------------------- 1 | readAutoFilters($workbookData); 13 | } 14 | 15 | protected function readAutoFilters(DOMElement $workbookData): void 16 | { 17 | $databases = $workbookData->getElementsByTagNameNS($this->tableNs, 'database-ranges'); 18 | 19 | foreach ($databases as $autofilters) { 20 | foreach ($autofilters->childNodes as $autofilter) { 21 | $autofilterRange = $this->getAttributeValue($autofilter, 'target-range-address'); 22 | if ($autofilterRange !== null) { 23 | $baseAddress = FormulaTranslator::convertToExcelAddressValue($autofilterRange); 24 | $this->spreadsheet->getActiveSheet()->setAutoFilter($baseAddress); 25 | } 26 | } 27 | } 28 | } 29 | 30 | protected function getAttributeValue(?DOMNode $node, string $attributeName): ?string 31 | { 32 | if ($node !== null && $node->attributes !== null) { 33 | $attribute = $node->attributes->getNamedItemNS( 34 | $this->tableNs, 35 | $attributeName 36 | ); 37 | 38 | if ($attribute !== null) { 39 | return $attribute->nodeValue; 40 | } 41 | } 42 | 43 | return null; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Reader/Ods/BaseLoader.php: -------------------------------------------------------------------------------- 1 | spreadsheet = $spreadsheet; 17 | $this->tableNs = $tableNs; 18 | } 19 | 20 | abstract public function read(DOMElement $workbookData): void; 21 | } 22 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Reader/Xls/Biff5.php: -------------------------------------------------------------------------------- 1 | $lr || $fc > $lc) { 32 | throw new ReaderException('Not a cell range address'); 33 | } 34 | 35 | // column index to letter 36 | $fc = Coordinate::stringFromColumnIndex($fc + 1); 37 | $lc = Coordinate::stringFromColumnIndex($lc + 1); 38 | 39 | if ($fr == $lr && $fc == $lc) { 40 | return "$fc$fr"; 41 | } 42 | 43 | return "$fc$fr:$lc$lr"; 44 | } 45 | 46 | /** 47 | * Read BIFF5 cell range address list 48 | * section 2.5.15. 49 | * 50 | * @return array{size: int, cellRangeAddresses: string[]} 51 | */ 52 | public static function readBIFF5CellRangeAddressList(string $subData): array 53 | { 54 | $cellRangeAddresses = []; 55 | 56 | // offset: 0; size: 2; number of the following cell range addresses 57 | $nm = self::getUInt2d($subData, 0); 58 | 59 | $offset = 2; 60 | // offset: 2; size: 6 * $nm; list of $nm (fixed) cell range addresses 61 | for ($i = 0; $i < $nm; ++$i) { 62 | $cellRangeAddresses[] = self::readBIFF5CellRangeAddressFixed(substr($subData, $offset, 6)); 63 | $offset += 6; 64 | } 65 | 66 | return [ 67 | 'size' => 2 + 6 * $nm, 68 | 'cellRangeAddresses' => $cellRangeAddresses, 69 | ]; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Reader/Xls/Color.php: -------------------------------------------------------------------------------- 1 | 'FF0000'] 16 | */ 17 | public static function map(int $color, array $palette, int $version): array 18 | { 19 | if ($color <= 0x07 || $color >= 0x40) { 20 | // special built-in color 21 | return Color\BuiltIn::lookup($color); 22 | } elseif (isset($palette[$color - 8])) { 23 | // palette color, color index 0x08 maps to pallete index 0 24 | return $palette[$color - 8]; 25 | } 26 | 27 | return ($version === Xls::XLS_BIFF8) ? Color\BIFF8::lookup($color) : Color\BIFF5::lookup($color); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Reader/Xls/Color/BIFF5.php: -------------------------------------------------------------------------------- 1 | '000000', 9 | 0x09 => 'FFFFFF', 10 | 0x0A => 'FF0000', 11 | 0x0B => '00FF00', 12 | 0x0C => '0000FF', 13 | 0x0D => 'FFFF00', 14 | 0x0E => 'FF00FF', 15 | 0x0F => '00FFFF', 16 | 0x10 => '800000', 17 | 0x11 => '008000', 18 | 0x12 => '000080', 19 | 0x13 => '808000', 20 | 0x14 => '800080', 21 | 0x15 => '008080', 22 | 0x16 => 'C0C0C0', 23 | 0x17 => '808080', 24 | 0x18 => '8080FF', 25 | 0x19 => '802060', 26 | 0x1A => 'FFFFC0', 27 | 0x1B => 'A0E0F0', 28 | 0x1C => '600080', 29 | 0x1D => 'FF8080', 30 | 0x1E => '0080C0', 31 | 0x1F => 'C0C0FF', 32 | 0x20 => '000080', 33 | 0x21 => 'FF00FF', 34 | 0x22 => 'FFFF00', 35 | 0x23 => '00FFFF', 36 | 0x24 => '800080', 37 | 0x25 => '800000', 38 | 0x26 => '008080', 39 | 0x27 => '0000FF', 40 | 0x28 => '00CFFF', 41 | 0x29 => '69FFFF', 42 | 0x2A => 'E0FFE0', 43 | 0x2B => 'FFFF80', 44 | 0x2C => 'A6CAF0', 45 | 0x2D => 'DD9CB3', 46 | 0x2E => 'B38FEE', 47 | 0x2F => 'E3E3E3', 48 | 0x30 => '2A6FF9', 49 | 0x31 => '3FB8CD', 50 | 0x32 => '488436', 51 | 0x33 => '958C41', 52 | 0x34 => '8E5E42', 53 | 0x35 => 'A0627A', 54 | 0x36 => '624FAC', 55 | 0x37 => '969696', 56 | 0x38 => '1D2FBE', 57 | 0x39 => '286676', 58 | 0x3A => '004500', 59 | 0x3B => '453E01', 60 | 0x3C => '6A2813', 61 | 0x3D => '85396A', 62 | 0x3E => '4A3285', 63 | 0x3F => '424242', 64 | ]; 65 | 66 | /** 67 | * Map color array from BIFF5 built-in color index. 68 | * 69 | * @return array{rgb: string} 70 | */ 71 | public static function lookup(int $color): array 72 | { 73 | return ['rgb' => self::BIFF5_COLOR_MAP[$color] ?? '000000']; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Reader/Xls/Color/BIFF8.php: -------------------------------------------------------------------------------- 1 | '000000', 9 | 0x09 => 'FFFFFF', 10 | 0x0A => 'FF0000', 11 | 0x0B => '00FF00', 12 | 0x0C => '0000FF', 13 | 0x0D => 'FFFF00', 14 | 0x0E => 'FF00FF', 15 | 0x0F => '00FFFF', 16 | 0x10 => '800000', 17 | 0x11 => '008000', 18 | 0x12 => '000080', 19 | 0x13 => '808000', 20 | 0x14 => '800080', 21 | 0x15 => '008080', 22 | 0x16 => 'C0C0C0', 23 | 0x17 => '808080', 24 | 0x18 => '9999FF', 25 | 0x19 => '993366', 26 | 0x1A => 'FFFFCC', 27 | 0x1B => 'CCFFFF', 28 | 0x1C => '660066', 29 | 0x1D => 'FF8080', 30 | 0x1E => '0066CC', 31 | 0x1F => 'CCCCFF', 32 | 0x20 => '000080', 33 | 0x21 => 'FF00FF', 34 | 0x22 => 'FFFF00', 35 | 0x23 => '00FFFF', 36 | 0x24 => '800080', 37 | 0x25 => '800000', 38 | 0x26 => '008080', 39 | 0x27 => '0000FF', 40 | 0x28 => '00CCFF', 41 | 0x29 => 'CCFFFF', 42 | 0x2A => 'CCFFCC', 43 | 0x2B => 'FFFF99', 44 | 0x2C => '99CCFF', 45 | 0x2D => 'FF99CC', 46 | 0x2E => 'CC99FF', 47 | 0x2F => 'FFCC99', 48 | 0x30 => '3366FF', 49 | 0x31 => '33CCCC', 50 | 0x32 => '99CC00', 51 | 0x33 => 'FFCC00', 52 | 0x34 => 'FF9900', 53 | 0x35 => 'FF6600', 54 | 0x36 => '666699', 55 | 0x37 => '969696', 56 | 0x38 => '003366', 57 | 0x39 => '339966', 58 | 0x3A => '003300', 59 | 0x3B => '333300', 60 | 0x3C => '993300', 61 | 0x3D => '993366', 62 | 0x3E => '333399', 63 | 0x3F => '333333', 64 | ]; 65 | 66 | /** 67 | * Map color array from BIFF8 built-in color index. 68 | * 69 | * @return array{rgb: string} 70 | */ 71 | public static function lookup(int $color): array 72 | { 73 | return ['rgb' => self::BIFF8_COLOR_MAP[$color] ?? '000000']; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Reader/Xls/Color/BuiltIn.php: -------------------------------------------------------------------------------- 1 | '000000', 9 | 0x01 => 'FFFFFF', 10 | 0x02 => 'FF0000', 11 | 0x03 => '00FF00', 12 | 0x04 => '0000FF', 13 | 0x05 => 'FFFF00', 14 | 0x06 => 'FF00FF', 15 | 0x07 => '00FFFF', 16 | 0x40 => '000000', // system window text color 17 | 0x41 => 'FFFFFF', // system window background color 18 | ]; 19 | 20 | /** 21 | * Map built-in color to RGB value. 22 | * 23 | * @param int $color Indexed color 24 | * 25 | * @return array{rgb: string} 26 | */ 27 | public static function lookup(int $color): array 28 | { 29 | return ['rgb' => self::BUILTIN_COLOR_MAP[$color] ?? '000000']; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Reader/Xls/ErrorCode.php: -------------------------------------------------------------------------------- 1 | '#NULL!', 9 | 0x07 => '#DIV/0!', 10 | 0x0F => '#VALUE!', 11 | 0x17 => '#REF!', 12 | 0x1D => '#NAME?', 13 | 0x24 => '#NUM!', 14 | 0x2A => '#N/A', 15 | ]; 16 | 17 | /** 18 | * Map error code, e.g. '#N/A'. 19 | */ 20 | public static function lookup(int $code): string|bool 21 | { 22 | return self::ERROR_CODE_MAP[$code] ?? false; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Reader/Xls/RC4.php: -------------------------------------------------------------------------------- 1 | i = 0; $this->i < 256; ++$this->i) { 24 | $this->s[$this->i] = $this->i; 25 | } 26 | 27 | $this->j = 0; 28 | for ($this->i = 0; $this->i < 256; ++$this->i) { 29 | $this->j = ($this->j + $this->s[$this->i] + ord($key[$this->i % $len])) % 256; 30 | $t = $this->s[$this->i]; 31 | $this->s[$this->i] = $this->s[$this->j]; 32 | $this->s[$this->j] = $t; 33 | } 34 | $this->i = $this->j = 0; 35 | } 36 | 37 | /** 38 | * Symmetric decryption/encryption function. 39 | * 40 | * @param string $data Data to encrypt/decrypt 41 | */ 42 | public function RC4(string $data): string 43 | { 44 | $len = strlen($data); 45 | for ($c = 0; $c < $len; ++$c) { 46 | $this->i = ($this->i + 1) % 256; 47 | $this->j = ($this->j + $this->s[$this->i]) % 256; 48 | $t = $this->s[$this->i]; 49 | $this->s[$this->i] = $this->s[$this->j]; 50 | $this->s[$this->j] = $t; 51 | 52 | $t = ($this->s[$this->i] + $this->s[$this->j]) % 256; 53 | 54 | $data[$c] = chr(ord($data[$c]) ^ $this->s[$t]); 55 | } 56 | 57 | return $data; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Reader/Xls/Style/Border.php: -------------------------------------------------------------------------------- 1 | 11 | */ 12 | protected static array $borderStyleMap = [ 13 | 0x00 => StyleBorder::BORDER_NONE, 14 | 0x01 => StyleBorder::BORDER_THIN, 15 | 0x02 => StyleBorder::BORDER_MEDIUM, 16 | 0x03 => StyleBorder::BORDER_DASHED, 17 | 0x04 => StyleBorder::BORDER_DOTTED, 18 | 0x05 => StyleBorder::BORDER_THICK, 19 | 0x06 => StyleBorder::BORDER_DOUBLE, 20 | 0x07 => StyleBorder::BORDER_HAIR, 21 | 0x08 => StyleBorder::BORDER_MEDIUMDASHED, 22 | 0x09 => StyleBorder::BORDER_DASHDOT, 23 | 0x0A => StyleBorder::BORDER_MEDIUMDASHDOT, 24 | 0x0B => StyleBorder::BORDER_DASHDOTDOT, 25 | 0x0C => StyleBorder::BORDER_MEDIUMDASHDOTDOT, 26 | 0x0D => StyleBorder::BORDER_SLANTDASHDOT, 27 | ]; 28 | 29 | public static function lookup(int $index): string 30 | { 31 | return self::$borderStyleMap[$index] ?? StyleBorder::BORDER_NONE; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Reader/Xls/Style/CellAlignment.php: -------------------------------------------------------------------------------- 1 | 11 | */ 12 | protected static array $horizontalAlignmentMap = [ 13 | 0 => Alignment::HORIZONTAL_GENERAL, 14 | 1 => Alignment::HORIZONTAL_LEFT, 15 | 2 => Alignment::HORIZONTAL_CENTER, 16 | 3 => Alignment::HORIZONTAL_RIGHT, 17 | 4 => Alignment::HORIZONTAL_FILL, 18 | 5 => Alignment::HORIZONTAL_JUSTIFY, 19 | 6 => Alignment::HORIZONTAL_CENTER_CONTINUOUS, 20 | ]; 21 | 22 | /** 23 | * @var array 24 | */ 25 | protected static array $verticalAlignmentMap = [ 26 | 0 => Alignment::VERTICAL_TOP, 27 | 1 => Alignment::VERTICAL_CENTER, 28 | 2 => Alignment::VERTICAL_BOTTOM, 29 | 3 => Alignment::VERTICAL_JUSTIFY, 30 | ]; 31 | 32 | public static function horizontal(Alignment $alignment, int $horizontal): void 33 | { 34 | if (array_key_exists($horizontal, self::$horizontalAlignmentMap)) { 35 | $alignment->setHorizontal(self::$horizontalAlignmentMap[$horizontal]); 36 | } 37 | } 38 | 39 | public static function vertical(Alignment $alignment, int $vertical): void 40 | { 41 | if (array_key_exists($vertical, self::$verticalAlignmentMap)) { 42 | $alignment->setVertical(self::$verticalAlignmentMap[$vertical]); 43 | } 44 | } 45 | 46 | public static function wrap(Alignment $alignment, int $wrap): void 47 | { 48 | $alignment->setWrapText((bool) $wrap); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Reader/Xls/Style/CellFont.php: -------------------------------------------------------------------------------- 1 | setSuperscript(true); 14 | 15 | break; 16 | case 0x0002: 17 | $font->setSubscript(true); 18 | 19 | break; 20 | } 21 | } 22 | 23 | /** 24 | * @var array 25 | */ 26 | protected static array $underlineMap = [ 27 | 0x01 => Font::UNDERLINE_SINGLE, 28 | 0x02 => Font::UNDERLINE_DOUBLE, 29 | 0x21 => Font::UNDERLINE_SINGLEACCOUNTING, 30 | 0x22 => Font::UNDERLINE_DOUBLEACCOUNTING, 31 | ]; 32 | 33 | public static function underline(Font $font, int $underline): void 34 | { 35 | if (array_key_exists($underline, self::$underlineMap)) { 36 | $font->setUnderline(self::$underlineMap[$underline]); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Reader/Xls/Style/FillPattern.php: -------------------------------------------------------------------------------- 1 | 11 | */ 12 | protected static array $fillPatternMap = [ 13 | 0x00 => Fill::FILL_NONE, 14 | 0x01 => Fill::FILL_SOLID, 15 | 0x02 => Fill::FILL_PATTERN_MEDIUMGRAY, 16 | 0x03 => Fill::FILL_PATTERN_DARKGRAY, 17 | 0x04 => Fill::FILL_PATTERN_LIGHTGRAY, 18 | 0x05 => Fill::FILL_PATTERN_DARKHORIZONTAL, 19 | 0x06 => Fill::FILL_PATTERN_DARKVERTICAL, 20 | 0x07 => Fill::FILL_PATTERN_DARKDOWN, 21 | 0x08 => Fill::FILL_PATTERN_DARKUP, 22 | 0x09 => Fill::FILL_PATTERN_DARKGRID, 23 | 0x0A => Fill::FILL_PATTERN_DARKTRELLIS, 24 | 0x0B => Fill::FILL_PATTERN_LIGHTHORIZONTAL, 25 | 0x0C => Fill::FILL_PATTERN_LIGHTVERTICAL, 26 | 0x0D => Fill::FILL_PATTERN_LIGHTDOWN, 27 | 0x0E => Fill::FILL_PATTERN_LIGHTUP, 28 | 0x0F => Fill::FILL_PATTERN_LIGHTGRID, 29 | 0x10 => Fill::FILL_PATTERN_LIGHTTRELLIS, 30 | 0x11 => Fill::FILL_PATTERN_GRAY125, 31 | 0x12 => Fill::FILL_PATTERN_GRAY0625, 32 | ]; 33 | 34 | /** 35 | * Get fill pattern from index 36 | * OpenOffice documentation: 2.5.12. 37 | */ 38 | public static function lookup(int $index): string 39 | { 40 | return self::$fillPatternMap[$index] ?? Fill::FILL_NONE; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Reader/Xlsx/BaseParserClass.php: -------------------------------------------------------------------------------- 1 | worksheet = $workSheet; 20 | } 21 | 22 | public function readHyperlinks(SimpleXMLElement $relsWorksheet): void 23 | { 24 | foreach ($relsWorksheet->children(Namespaces::RELATIONSHIPS)->Relationship as $elementx) { 25 | $element = Xlsx::getAttributes($elementx); 26 | if ($element->Type == Namespaces::HYPERLINK) { 27 | $this->hyperlinks[(string) $element->Id] = (string) $element->Target; 28 | } 29 | } 30 | } 31 | 32 | public function setHyperlinks(SimpleXMLElement $worksheetXml): void 33 | { 34 | foreach ($worksheetXml->children(Namespaces::MAIN)->hyperlink as $hyperlink) { 35 | $this->setHyperlink($hyperlink, $this->worksheet); 36 | } 37 | } 38 | 39 | private function setHyperlink(SimpleXMLElement $hyperlink, Worksheet $worksheet): void 40 | { 41 | // Link url 42 | $linkRel = Xlsx::getAttributes($hyperlink, Namespaces::SCHEMA_OFFICE_DOCUMENT); 43 | 44 | $attributes = Xlsx::getAttributes($hyperlink); 45 | foreach (Coordinate::extractAllCellReferencesInRange($attributes->ref) as $cellReference) { 46 | $cell = $worksheet->getCell($cellReference); 47 | if (isset($linkRel['id'])) { 48 | $hyperlinkUrl = $this->hyperlinks[(string) $linkRel['id']] ?? ''; 49 | if (isset($attributes['location'])) { 50 | $hyperlinkUrl .= '#' . (string) $attributes['location']; 51 | } 52 | $cell->getHyperlink()->setUrl($hyperlinkUrl); 53 | } elseif (isset($attributes['location'])) { 54 | $cell->getHyperlink()->setUrl('sheet://' . (string) $attributes['location']); 55 | } 56 | 57 | // Tooltip 58 | if (isset($attributes['tooltip'])) { 59 | $cell->getHyperlink()->setTooltip((string) $attributes['tooltip']); 60 | } 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Reader/Xlsx/SharedFormula.php: -------------------------------------------------------------------------------- 1 | master = $master; 14 | $this->formula = $formula; 15 | } 16 | 17 | public function master(): string 18 | { 19 | return $this->master; 20 | } 21 | 22 | public function formula(): string 23 | { 24 | return $this->formula; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Reader/Xlsx/Theme.php: -------------------------------------------------------------------------------- 1 | themeName = $themeName; 33 | $this->colourSchemeName = $colourSchemeName; 34 | $this->colourMap = $colourMap; 35 | } 36 | 37 | /** 38 | * Not called by Reader, never accessible any other time. 39 | * 40 | * @codeCoverageIgnore 41 | */ 42 | public function getThemeName(): string 43 | { 44 | return $this->themeName; 45 | } 46 | 47 | /** 48 | * Not called by Reader, never accessible any other time. 49 | * 50 | * @codeCoverageIgnore 51 | */ 52 | public function getColourSchemeName(): string 53 | { 54 | return $this->colourSchemeName; 55 | } 56 | 57 | /** 58 | * Get colour Map Value by Position. 59 | */ 60 | public function getColourByIndex(int $index): ?string 61 | { 62 | return $this->colourMap[$index] ?? null; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Reader/Xml/Style/Alignment.php: -------------------------------------------------------------------------------- 1 | $styleAttributeValue) { 32 | $styleAttributeValue = (string) $styleAttributeValue; 33 | switch ($styleAttributeKey) { 34 | case 'Vertical': 35 | if (self::identifyFixedStyleValue(self::VERTICAL_ALIGNMENT_STYLES, $styleAttributeValue)) { 36 | $style['alignment']['vertical'] = $styleAttributeValue; 37 | } 38 | 39 | break; 40 | case 'Horizontal': 41 | if (self::identifyFixedStyleValue(self::HORIZONTAL_ALIGNMENT_STYLES, $styleAttributeValue)) { 42 | $style['alignment']['horizontal'] = $styleAttributeValue; 43 | } 44 | 45 | break; 46 | case 'WrapText': 47 | $style['alignment']['wrapText'] = true; 48 | 49 | break; 50 | case 'Rotate': 51 | $style['alignment']['textRotation'] = $styleAttributeValue; 52 | 53 | break; 54 | case 'Indent': 55 | $style['alignment']['indent'] = $styleAttributeValue; 56 | 57 | break; 58 | } 59 | } 60 | 61 | return $style; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Reader/Xml/Style/NumberFormat.php: -------------------------------------------------------------------------------- 1 | $styleAttributeValue) { 18 | $styleAttributeValue = str_replace($fromFormats, $toFormats, $styleAttributeValue); 19 | 20 | switch ($styleAttributeValue) { 21 | case 'Short Date': 22 | $styleAttributeValue = 'dd/mm/yyyy'; 23 | 24 | break; 25 | } 26 | 27 | if ($styleAttributeValue > '') { 28 | $style['numberFormat']['formatCode'] = $styleAttributeValue; 29 | } 30 | } 31 | 32 | return $style; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Reader/Xml/Style/StyleBase.php: -------------------------------------------------------------------------------- 1 | ') : ($simple->attributes($node) ?? new SimpleXMLElement('')); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/RichText/ITextElement.php: -------------------------------------------------------------------------------- 1 | font = new Font(); 25 | } 26 | 27 | /** 28 | * Get font. 29 | */ 30 | public function getFont(): ?Font 31 | { 32 | return $this->font; 33 | } 34 | 35 | public function getFontOrThrow(): Font 36 | { 37 | if ($this->font === null) { 38 | throw new SpreadsheetException('unexpected null font'); 39 | } 40 | 41 | return $this->font; 42 | } 43 | 44 | /** 45 | * Set font. 46 | * 47 | * @param ?Font $font Font 48 | * 49 | * @return $this 50 | */ 51 | public function setFont(?Font $font = null): static 52 | { 53 | $this->font = $font; 54 | 55 | return $this; 56 | } 57 | 58 | /** 59 | * Get hash code. 60 | * 61 | * @return string Hash code 62 | */ 63 | public function getHashCode(): string 64 | { 65 | return md5( 66 | $this->getText() 67 | . (($this->font === null) ? '' : $this->font->getHashCode()) 68 | . __CLASS__ 69 | ); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/RichText/TextElement.php: -------------------------------------------------------------------------------- 1 | text = $text; 23 | } 24 | 25 | /** 26 | * Get text. 27 | * 28 | * @return string Text 29 | */ 30 | public function getText(): string 31 | { 32 | return $this->text; 33 | } 34 | 35 | /** 36 | * Set text. 37 | * 38 | * @param string $text Text 39 | * 40 | * @return $this 41 | */ 42 | public function setText(string $text): self 43 | { 44 | $this->text = $text; 45 | 46 | return $this; 47 | } 48 | 49 | /** 50 | * Get font. For this class, the return value is always null. 51 | */ 52 | public function getFont(): ?Font 53 | { 54 | return null; 55 | } 56 | 57 | /** 58 | * Get hash code. 59 | * 60 | * @return string Hash code 61 | */ 62 | public function getHashCode(): string 63 | { 64 | return md5( 65 | $this->text 66 | . __CLASS__ 67 | ); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Shared/Escher.php: -------------------------------------------------------------------------------- 1 | dggContainer; 23 | } 24 | 25 | /** 26 | * Set Drawing Group Container. 27 | */ 28 | public function setDggContainer(Escher\DggContainer $dggContainer): Escher\DggContainer 29 | { 30 | return $this->dggContainer = $dggContainer; 31 | } 32 | 33 | /** 34 | * Get Drawing Container. 35 | */ 36 | public function getDgContainer(): ?Escher\DgContainer 37 | { 38 | return $this->dgContainer; 39 | } 40 | 41 | /** 42 | * Set Drawing Container. 43 | */ 44 | public function setDgContainer(Escher\DgContainer $dgContainer): Escher\DgContainer 45 | { 46 | return $this->dgContainer = $dgContainer; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Shared/Escher/DgContainer.php: -------------------------------------------------------------------------------- 1 | dgId; 25 | } 26 | 27 | public function setDgId(int $value): void 28 | { 29 | $this->dgId = $value; 30 | } 31 | 32 | public function getLastSpId(): ?int 33 | { 34 | return $this->lastSpId; 35 | } 36 | 37 | public function setLastSpId(int $value): void 38 | { 39 | $this->lastSpId = $value; 40 | } 41 | 42 | public function getSpgrContainer(): ?SpgrContainer 43 | { 44 | return $this->spgrContainer; 45 | } 46 | 47 | public function getSpgrContainerOrThrow(): SpgrContainer 48 | { 49 | if ($this->spgrContainer !== null) { 50 | return $this->spgrContainer; 51 | } 52 | 53 | throw new SpreadsheetException('spgrContainer is unexpectedly null'); 54 | } 55 | 56 | public function setSpgrContainer(SpgrContainer $spgrContainer): SpgrContainer 57 | { 58 | return $this->spgrContainer = $spgrContainer; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Shared/Escher/DgContainer/SpgrContainer.php: -------------------------------------------------------------------------------- 1 | parent = $parent; 25 | } 26 | 27 | /** 28 | * Get the parent Shape Group Container if any. 29 | */ 30 | public function getParent(): ?self 31 | { 32 | return $this->parent; 33 | } 34 | 35 | /** 36 | * Add a child. This will be either spgrContainer or spContainer. 37 | * 38 | * @param SpgrContainer|SpgrContainer\SpContainer $child child to be added 39 | */ 40 | public function addChild(mixed $child): void 41 | { 42 | $this->children[] = $child; 43 | $child->setParent($this); 44 | } 45 | 46 | /** 47 | * Get collection of Shape Containers. 48 | * 49 | * @return mixed[] 50 | */ 51 | public function getChildren(): array 52 | { 53 | return $this->children; 54 | } 55 | 56 | /** 57 | * Recursively get all spContainers within this spgrContainer. 58 | * 59 | * @return SpgrContainer\SpContainer[] 60 | */ 61 | public function getAllSpContainers(): array 62 | { 63 | $allSpContainers = []; 64 | 65 | foreach ($this->children as $child) { 66 | if ($child instanceof self) { 67 | $allSpContainers = array_merge($allSpContainers, $child->getAllSpContainers()); 68 | } else { 69 | $allSpContainers[] = $child; 70 | } 71 | } 72 | /** @var SpgrContainer\SpContainer[] $allSpContainers */ 73 | 74 | return $allSpContainers; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Shared/Escher/DggContainer/BstoreContainer.php: -------------------------------------------------------------------------------- 1 | BSECollection[] = $BSE; 20 | $BSE->setParent($this); 21 | } 22 | 23 | /** 24 | * Get the collection of BLIP Store Entries. 25 | * 26 | * @return BstoreContainer\BSE[] 27 | */ 28 | public function getBSECollection(): array 29 | { 30 | return $this->BSECollection; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Shared/Escher/DggContainer/BstoreContainer/BSE.php: -------------------------------------------------------------------------------- 1 | parent = $parent; 42 | } 43 | 44 | public function getParent(): BstoreContainer 45 | { 46 | return $this->parent; 47 | } 48 | 49 | /** 50 | * Get the BLIP. 51 | */ 52 | public function getBlip(): ?BSE\Blip 53 | { 54 | return $this->blip; 55 | } 56 | 57 | /** 58 | * Set the BLIP. 59 | */ 60 | public function setBlip(BSE\Blip $blip): void 61 | { 62 | $this->blip = $blip; 63 | $blip->setParent($this); 64 | } 65 | 66 | /** 67 | * Get the BLIP type. 68 | */ 69 | public function getBlipType(): int 70 | { 71 | return $this->blipType; 72 | } 73 | 74 | /** 75 | * Set the BLIP type. 76 | */ 77 | public function setBlipType(int $blipType): void 78 | { 79 | $this->blipType = $blipType; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Shared/Escher/DggContainer/BstoreContainer/BSE/Blip.php: -------------------------------------------------------------------------------- 1 | data; 25 | } 26 | 27 | /** 28 | * Set the raw image data. 29 | */ 30 | public function setData(string $data): void 31 | { 32 | $this->data = $data; 33 | } 34 | 35 | /** 36 | * Set parent BSE. 37 | */ 38 | public function setParent(BSE $parent): void 39 | { 40 | $this->parent = $parent; 41 | } 42 | 43 | /** 44 | * Get parent BSE. 45 | */ 46 | public function getParent(): BSE 47 | { 48 | return $this->parent; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Shared/IntOrFloat.php: -------------------------------------------------------------------------------- 1 | | 20 | // | Based on OLE::Storage_Lite by Kawai, Takanori | 21 | // +----------------------------------------------------------------------+ 22 | // 23 | use PhpOffice\PhpSpreadsheet\Shared\OLE; 24 | use PhpOffice\PhpSpreadsheet\Shared\OLE\PPS; 25 | 26 | /** 27 | * Class for creating File PPS's for OLE containers. 28 | * 29 | * @author Xavier Noguer 30 | */ 31 | class File extends PPS 32 | { 33 | /** 34 | * The constructor. 35 | * 36 | * @param string $name The name of the file (in Unicode) 37 | * 38 | * @see OLE::ascToUcs() 39 | */ 40 | public function __construct(string $name) 41 | { 42 | parent::__construct(null, $name, OLE::OLE_PPS_TYPE_FILE, null, null, null, null, null, '', []); 43 | } 44 | 45 | /** 46 | * Initialization method. Has to be called right after OLE_PPS_File(). 47 | */ 48 | public function init(): bool 49 | { 50 | return true; 51 | } 52 | 53 | /** 54 | * Append data to PPS. 55 | * 56 | * @param string $data The data to append 57 | */ 58 | public function append(string $data): void 59 | { 60 | $this->_data .= $data; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Shared/Trend/LinearBestFit.php: -------------------------------------------------------------------------------- 1 | getIntersect() + $this->getSlope() * $xValue; 23 | } 24 | 25 | /** 26 | * Return the X-Value for a specified value of Y. 27 | * 28 | * @param float $yValue Y-Value 29 | * 30 | * @return float X-Value 31 | */ 32 | public function getValueOfXForY(float $yValue): float 33 | { 34 | return ($yValue - $this->getIntersect()) / $this->getSlope(); 35 | } 36 | 37 | /** 38 | * Return the Equation of the best-fit line. 39 | * 40 | * @param int $dp Number of places of decimal precision to display 41 | */ 42 | public function getEquation(int $dp = 0): string 43 | { 44 | $slope = $this->getSlope($dp); 45 | $intersect = $this->getIntersect($dp); 46 | 47 | return 'Y = ' . $intersect . ' + ' . $slope . ' * X'; 48 | } 49 | 50 | /** 51 | * Execute the regression and calculate the goodness of fit for a set of X and Y data values. 52 | * 53 | * @param float[] $yValues The set of Y-values for this regression 54 | * @param float[] $xValues The set of X-values for this regression 55 | */ 56 | private function linearRegression(array $yValues, array $xValues, bool $const): void 57 | { 58 | $this->leastSquareFit($yValues, $xValues, $const); 59 | } 60 | 61 | /** 62 | * Define the regression and calculate the goodness of fit for a set of X and Y data values. 63 | * 64 | * @param float[] $yValues The set of Y-values for this regression 65 | * @param float[] $xValues The set of X-values for this regression 66 | */ 67 | public function __construct(array $yValues, array $xValues = [], bool $const = true) 68 | { 69 | parent::__construct($yValues, $xValues); 70 | 71 | if (!$this->error) { 72 | $this->linearRegression($yValues, $xValues, (bool) $const); 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Style/ConditionalFormatting/CellStyleAssessor.php: -------------------------------------------------------------------------------- 1 | cell = $cell; 20 | $this->cellMatcher = new CellMatcher($cell, $conditionalRange); 21 | $this->styleMerger = new StyleMerger($cell->getStyle()); 22 | } 23 | 24 | /** 25 | * @param Conditional[] $conditionalStyles 26 | */ 27 | public function matchConditions(array $conditionalStyles = []): Style 28 | { 29 | foreach ($conditionalStyles as $conditional) { 30 | if ($this->cellMatcher->evaluateConditional($conditional) === true) { 31 | // Merging the conditional style into the base style goes in here 32 | $this->styleMerger->mergeStyle($conditional->getStyle($this->cell->getValue())); 33 | if ($conditional->getStopIfTrue() === true) { 34 | break; 35 | } 36 | } 37 | } 38 | 39 | return $this->styleMerger->getStyle(); 40 | } 41 | 42 | /** 43 | * @param Conditional[] $conditionalStyles 44 | */ 45 | public function matchConditionsReturnNullIfNoneMatched(array $conditionalStyles, string $cellData, bool $stopAtFirstMatch = false): ?Style 46 | { 47 | $matched = false; 48 | $value = (float) $cellData; 49 | foreach ($conditionalStyles as $conditional) { 50 | if ($this->cellMatcher->evaluateConditional($conditional) === true) { 51 | $matched = true; 52 | // Merging the conditional style into the base style goes in here 53 | $this->styleMerger->mergeStyle($conditional->getStyle($value)); 54 | if ($conditional->getStopIfTrue() === true || $stopAtFirstMatch) { 55 | break; 56 | } 57 | } 58 | } 59 | if ($matched) { 60 | return $this->styleMerger->getStyle(); 61 | } 62 | 63 | return null; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalDataBar.php: -------------------------------------------------------------------------------- 1 | showValue; 20 | } 21 | 22 | public function setShowValue(bool $showValue): self 23 | { 24 | $this->showValue = $showValue; 25 | 26 | return $this; 27 | } 28 | 29 | public function getMinimumConditionalFormatValueObject(): ?ConditionalFormatValueObject 30 | { 31 | return $this->minimumConditionalFormatValueObject; 32 | } 33 | 34 | public function setMinimumConditionalFormatValueObject(ConditionalFormatValueObject $minimumConditionalFormatValueObject): self 35 | { 36 | $this->minimumConditionalFormatValueObject = $minimumConditionalFormatValueObject; 37 | 38 | return $this; 39 | } 40 | 41 | public function getMaximumConditionalFormatValueObject(): ?ConditionalFormatValueObject 42 | { 43 | return $this->maximumConditionalFormatValueObject; 44 | } 45 | 46 | public function setMaximumConditionalFormatValueObject(ConditionalFormatValueObject $maximumConditionalFormatValueObject): self 47 | { 48 | $this->maximumConditionalFormatValueObject = $maximumConditionalFormatValueObject; 49 | 50 | return $this; 51 | } 52 | 53 | public function getColor(): string 54 | { 55 | return $this->color; 56 | } 57 | 58 | public function setColor(string $color): self 59 | { 60 | $this->color = $color; 61 | 62 | return $this; 63 | } 64 | 65 | public function getConditionalFormattingRuleExt(): ?ConditionalFormattingRuleExtension 66 | { 67 | return $this->conditionalFormattingRuleExt; 68 | } 69 | 70 | public function setConditionalFormattingRuleExt(ConditionalFormattingRuleExtension $conditionalFormattingRuleExt): self 71 | { 72 | $this->conditionalFormattingRuleExt = $conditionalFormattingRuleExt; 73 | 74 | return $this; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalFormatValueObject.php: -------------------------------------------------------------------------------- 1 | type = $type; 16 | $this->value = $value; 17 | $this->cellFormula = $cellFormula; 18 | } 19 | 20 | public function getType(): string 21 | { 22 | return $this->type; 23 | } 24 | 25 | public function setType(string $type): self 26 | { 27 | $this->type = $type; 28 | 29 | return $this; 30 | } 31 | 32 | public function getValue(): null|float|int|string 33 | { 34 | return $this->value; 35 | } 36 | 37 | public function setValue(null|float|int|string $value): self 38 | { 39 | $this->value = $value; 40 | 41 | return $this; 42 | } 43 | 44 | public function getCellFormula(): ?string 45 | { 46 | return $this->cellFormula; 47 | } 48 | 49 | public function setCellFormula(?string $cellFormula): self 50 | { 51 | $this->cellFormula = $cellFormula; 52 | 53 | return $this; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Style/ConditionalFormatting/Wizard/WizardInterface.php: -------------------------------------------------------------------------------- 1 | 0); 40 | $replacement = "0{$wholePartSize}.{$decimalPartSize}"; 41 | $mask = (string) preg_replace('/[#0,]+\.?[?#0,]*/ui', "%{$replacement}F{$placeHolders}", $format); 42 | 43 | /** @var float $valueFloat */ 44 | $valueFloat = $value; 45 | 46 | return self::adjustSeparators(sprintf($mask, round($valueFloat, $decimalPartSize))); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Style/NumberFormat/Wizard/Accounting.php: -------------------------------------------------------------------------------- 1 | fullLocale, NumberFormatter::CURRENCY_ACCOUNTING); 27 | $mask = $formatter->format($this->stripLeadingRLM); 28 | if ($this->decimals === 0) { 29 | $mask = (string) preg_replace('/\.0+/miu', '', $mask); 30 | } 31 | 32 | return str_replace('¤', $this->formatCurrencyCode(), $mask); 33 | } 34 | 35 | public static function icuVersion(): float 36 | { 37 | [$major, $minor] = explode('.', INTL_ICU_VERSION); 38 | 39 | return (float) "{$major}.{$minor}"; 40 | } 41 | 42 | private function formatCurrencyCode(): string 43 | { 44 | if ($this->locale === null) { 45 | return $this->currencyCode . '*'; 46 | } 47 | 48 | return "[\${$this->currencyCode}-{$this->locale}]"; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Style/NumberFormat/Wizard/Currency.php: -------------------------------------------------------------------------------- 1 | '-', 16 | self::parentheses, self::redParentheses => '\(', 17 | }; 18 | } 19 | 20 | public function end(): string 21 | { 22 | return match ($this) { 23 | self::minus, self::redMinus => '', 24 | self::parentheses, self::redParentheses => '\)', 25 | }; 26 | } 27 | 28 | public function color(): string 29 | { 30 | return match ($this) { 31 | self::redParentheses, self::redMinus => '[Red]', 32 | self::parentheses, self::minus => '', 33 | }; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Style/NumberFormat/Wizard/DateTime.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | protected array $formatBlocks; 16 | 17 | /** 18 | * @param null|string|string[] $separators 19 | * If you want to use only a single format block, then pass a null as the separator argument 20 | * @param DateTimeWizard|string ...$formatBlocks 21 | */ 22 | public function __construct($separators, ...$formatBlocks) 23 | { 24 | $this->separators = $this->padSeparatorArray( 25 | is_array($separators) ? $separators : [$separators], //* @phpstan-ignore-line 26 | count($formatBlocks) - 1 27 | ); 28 | $this->formatBlocks = array_map([$this, 'mapFormatBlocks'], $formatBlocks); 29 | } 30 | 31 | private function mapFormatBlocks(DateTimeWizard|string $value): string 32 | { 33 | // Any date masking codes are returned as lower case values 34 | if ($value instanceof DateTimeWizard) { 35 | return $value->__toString(); 36 | } 37 | 38 | // Wrap any string literals in quotes, so that they're clearly defined as string literals 39 | return $this->wrapLiteral($value); 40 | } 41 | 42 | public function format(): string 43 | { 44 | return implode('', array_map([$this, 'intersperse'], $this->formatBlocks, $this->separators)); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Style/NumberFormat/Wizard/DateTimeWizard.php: -------------------------------------------------------------------------------- 1 | = "; 10 | 11 | /** 12 | * @param string[] $separators 13 | * 14 | * @return string[] 15 | */ 16 | protected function padSeparatorArray(array $separators, int $count): array 17 | { 18 | $lastSeparator = (string) array_pop($separators); 19 | 20 | return $separators + array_fill(0, $count, $lastSeparator); 21 | } 22 | 23 | protected function escapeSingleCharacter(string $value): string 24 | { 25 | if (str_contains(self::NO_ESCAPING_NEEDED, $value)) { 26 | return $value; 27 | } 28 | 29 | return "\\{$value}"; 30 | } 31 | 32 | protected function wrapLiteral(string $value): string 33 | { 34 | if (mb_strlen($value, 'UTF-8') === 1) { 35 | return $this->escapeSingleCharacter($value); 36 | } 37 | 38 | // Wrap any other string literals in quotes, so that they're clearly defined as string literals 39 | return '"' . str_replace('"', '""', $value) . '"'; 40 | } 41 | 42 | protected function intersperse(string $formatBlock, ?string $separator): string 43 | { 44 | return "{$formatBlock}{$separator}"; 45 | } 46 | 47 | public function __toString(): string 48 | { 49 | return $this->format(); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/PhpSpreadsheet/Style/NumberFormat/Wizard/Locale.php: -------------------------------------------------------------------------------- 1 | [a-z]{2})([-_](?P