feat: Version 3.5.2 - Configuration Stripe et gestion des immeubles

- Configuration complète Stripe pour les 3 environnements (DEV/REC/PROD)
  * DEV: Clés TEST Pierre (mode test)
  * REC: Clés TEST Client (mode test)
  * PROD: Clés LIVE Client (mode live)
- Ajout de la gestion des bases de données immeubles/bâtiments
  * Configuration buildings_database pour DEV/REC/PROD
  * Service BuildingService pour enrichissement des adresses
- Optimisations pages et améliorations ergonomie
- Mises à jour des dépendances Composer
- Nettoyage des fichiers obsolètes

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
pierre
2025-11-09 18:26:27 +01:00
parent 21657a3820
commit 2f5946a184
812 changed files with 142105 additions and 25992 deletions

View File

@@ -13,14 +13,19 @@ return array(
'App\\Controllers\\ChatController' => $baseDir . '/src/Controllers/ChatController.php',
'App\\Controllers\\EntiteController' => $baseDir . '/src/Controllers/EntiteController.php',
'App\\Controllers\\FileController' => $baseDir . '/src/Controllers/FileController.php',
'App\\Controllers\\HealthController' => $baseDir . '/src/Controllers/HealthController.php',
'App\\Controllers\\LoginController' => $baseDir . '/src/Controllers/LoginController.php',
'App\\Controllers\\MigrationController' => $baseDir . '/src/Controllers/MigrationController.php',
'App\\Controllers\\OperationController' => $baseDir . '/src/Controllers/OperationController.php',
'App\\Controllers\\PassageController' => $baseDir . '/src/Controllers/PassageController.php',
'App\\Controllers\\PasswordController' => $baseDir . '/src/Controllers/PasswordController.php',
'App\\Controllers\\SectorController' => $baseDir . '/src/Controllers/SectorController.php',
'App\\Controllers\\SecurityController' => $baseDir . '/src/Controllers/SecurityController.php',
'App\\Controllers\\StripeController' => $baseDir . '/src/Controllers/StripeController.php',
'App\\Controllers\\StripeWebhookController' => $baseDir . '/src/Controllers/StripeWebhookController.php',
'App\\Controllers\\UserController' => $baseDir . '/src/Controllers/UserController.php',
'App\\Controllers\\VilleController' => $baseDir . '/src/Controllers/VilleController.php',
'App\\Core\\Controller' => $baseDir . '/src/Core/Controller.php',
'App\\Services\\PDFGenerator' => $baseDir . '/src/Services/PDFGenerator.php',
'App\\Services\\PasswordSecurityService' => $baseDir . '/src/Services/PasswordSecurityService.php',
'App\\Services\\ReceiptPDFGenerator' => $baseDir . '/src/Services/ReceiptPDFGenerator.php',
@@ -31,6 +36,7 @@ return array(
'App\\Services\\Security\\PerformanceMonitor' => $baseDir . '/src/Services/Security/PerformanceMonitor.php',
'App\\Services\\Security\\SecurityMonitor' => $baseDir . '/src/Services/Security/SecurityMonitor.php',
'App\\Services\\SimplePDF' => $baseDir . '/src/Services/SimplePDF.php',
'App\\Services\\StripeService' => $baseDir . '/src/Services/StripeService.php',
'BackupEncryptionService' => $baseDir . '/src/Services/BackupEncryptionService.php',
'ClientDetector' => $baseDir . '/src/Utils/ClientDetector.php',
'Complex\\Complex' => $vendorDir . '/markbaker/complex/classes/src/Complex.php',
@@ -58,6 +64,7 @@ return array(
'Database' => $baseDir . '/src/Core/Database.php',
'DepartmentBoundaryService' => $baseDir . '/src/Services/DepartmentBoundaryService.php',
'EmailTemplates' => $baseDir . '/src/Services/EmailTemplates.php',
'EventLogService' => $baseDir . '/src/Services/EventLogService.php',
'ExportService' => $baseDir . '/src/Services/ExportService.php',
'FPDF' => $vendorDir . '/setasign/fpdf/fpdf.php',
'FileService' => $baseDir . '/src/Services/FileService.php',
@@ -78,6 +85,7 @@ return array(
'Matrix\\Operators\\Multiplication' => $vendorDir . '/markbaker/matrix/classes/src/Operators/Multiplication.php',
'Matrix\\Operators\\Operator' => $vendorDir . '/markbaker/matrix/classes/src/Operators/Operator.php',
'Matrix\\Operators\\Subtraction' => $vendorDir . '/markbaker/matrix/classes/src/Operators/Subtraction.php',
'MigrationService' => $baseDir . '/src/Services/MigrationService.php',
'MonitoredDatabase' => $baseDir . '/src/Core/MonitoredDatabase.php',
'MonitoredStatement' => $baseDir . '/src/Core/MonitoredDatabase.php',
'OperationDataService' => $baseDir . '/src/Services/OperationDataService.php',
@@ -91,6 +99,8 @@ return array(
'PhpOffice\\PhpSpreadsheet\\Calculation\\ArrayEnabled' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/ArrayEnabled.php',
'PhpOffice\\PhpSpreadsheet\\Calculation\\BinaryComparison' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/BinaryComparison.php',
'PhpOffice\\PhpSpreadsheet\\Calculation\\Calculation' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/Calculation.php',
'PhpOffice\\PhpSpreadsheet\\Calculation\\CalculationBase' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/CalculationBase.php',
'PhpOffice\\PhpSpreadsheet\\Calculation\\CalculationLocale' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/CalculationLocale.php',
'PhpOffice\\PhpSpreadsheet\\Calculation\\Category' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/Category.php',
'PhpOffice\\PhpSpreadsheet\\Calculation\\Database\\DAverage' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/Database/DAverage.php',
'PhpOffice\\PhpSpreadsheet\\Calculation\\Database\\DCount' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/Database/DCount.php',
@@ -176,21 +186,25 @@ return array(
'PhpOffice\\PhpSpreadsheet\\Calculation\\Financial\\TreasuryBill' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/Financial/TreasuryBill.php',
'PhpOffice\\PhpSpreadsheet\\Calculation\\FormulaParser' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/FormulaParser.php',
'PhpOffice\\PhpSpreadsheet\\Calculation\\FormulaToken' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/FormulaToken.php',
'PhpOffice\\PhpSpreadsheet\\Calculation\\FunctionArray' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/FunctionArray.php',
'PhpOffice\\PhpSpreadsheet\\Calculation\\Functions' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/Functions.php',
'PhpOffice\\PhpSpreadsheet\\Calculation\\Information\\ErrorValue' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/Information/ErrorValue.php',
'PhpOffice\\PhpSpreadsheet\\Calculation\\Information\\ExcelError' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/Information/ExcelError.php',
'PhpOffice\\PhpSpreadsheet\\Calculation\\Information\\Value' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/Information/Value.php',
'PhpOffice\\PhpSpreadsheet\\Calculation\\Internal\\ExcelArrayPseudoFunctions' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/Internal/ExcelArrayPseudoFunctions.php',
'PhpOffice\\PhpSpreadsheet\\Calculation\\Internal\\MakeMatrix' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/Internal/MakeMatrix.php',
'PhpOffice\\PhpSpreadsheet\\Calculation\\Internal\\WildcardMatch' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/Internal/WildcardMatch.php',
'PhpOffice\\PhpSpreadsheet\\Calculation\\Logical\\Boolean' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/Logical/Boolean.php',
'PhpOffice\\PhpSpreadsheet\\Calculation\\Logical\\Conditional' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/Logical/Conditional.php',
'PhpOffice\\PhpSpreadsheet\\Calculation\\Logical\\Operations' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/Logical/Operations.php',
'PhpOffice\\PhpSpreadsheet\\Calculation\\LookupRef\\Address' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/LookupRef/Address.php',
'PhpOffice\\PhpSpreadsheet\\Calculation\\LookupRef\\ChooseRowsEtc' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/LookupRef/ChooseRowsEtc.php',
'PhpOffice\\PhpSpreadsheet\\Calculation\\LookupRef\\ExcelMatch' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/LookupRef/ExcelMatch.php',
'PhpOffice\\PhpSpreadsheet\\Calculation\\LookupRef\\Filter' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/LookupRef/Filter.php',
'PhpOffice\\PhpSpreadsheet\\Calculation\\LookupRef\\Formula' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/LookupRef/Formula.php',
'PhpOffice\\PhpSpreadsheet\\Calculation\\LookupRef\\HLookup' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/LookupRef/HLookup.php',
'PhpOffice\\PhpSpreadsheet\\Calculation\\LookupRef\\Helpers' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/LookupRef/Helpers.php',
'PhpOffice\\PhpSpreadsheet\\Calculation\\LookupRef\\Hstack' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/LookupRef/Hstack.php',
'PhpOffice\\PhpSpreadsheet\\Calculation\\LookupRef\\Hyperlink' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/LookupRef/Hyperlink.php',
'PhpOffice\\PhpSpreadsheet\\Calculation\\LookupRef\\Indirect' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/LookupRef/Indirect.php',
'PhpOffice\\PhpSpreadsheet\\Calculation\\LookupRef\\Lookup' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/LookupRef/Lookup.php',
@@ -201,8 +215,10 @@ return array(
'PhpOffice\\PhpSpreadsheet\\Calculation\\LookupRef\\RowColumnInformation' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/LookupRef/RowColumnInformation.php',
'PhpOffice\\PhpSpreadsheet\\Calculation\\LookupRef\\Selection' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/LookupRef/Selection.php',
'PhpOffice\\PhpSpreadsheet\\Calculation\\LookupRef\\Sort' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/LookupRef/Sort.php',
'PhpOffice\\PhpSpreadsheet\\Calculation\\LookupRef\\TorowTocol' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/LookupRef/TorowTocol.php',
'PhpOffice\\PhpSpreadsheet\\Calculation\\LookupRef\\Unique' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/LookupRef/Unique.php',
'PhpOffice\\PhpSpreadsheet\\Calculation\\LookupRef\\VLookup' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/LookupRef/VLookup.php',
'PhpOffice\\PhpSpreadsheet\\Calculation\\LookupRef\\Vstack' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/LookupRef/Vstack.php',
'PhpOffice\\PhpSpreadsheet\\Calculation\\MathTrig\\Absolute' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/MathTrig/Absolute.php',
'PhpOffice\\PhpSpreadsheet\\Calculation\\MathTrig\\Angle' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/MathTrig/Angle.php',
'PhpOffice\\PhpSpreadsheet\\Calculation\\MathTrig\\Arabic' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/MathTrig/Arabic.php',
@@ -362,6 +378,9 @@ return array(
'PhpOffice\\PhpSpreadsheet\\Reader\\Security\\XmlScanner' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Security/XmlScanner.php',
'PhpOffice\\PhpSpreadsheet\\Reader\\Slk' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Slk.php',
'PhpOffice\\PhpSpreadsheet\\Reader\\Xls' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xls.php',
'PhpOffice\\PhpSpreadsheet\\Reader\\XlsBase' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/XlsBase.php',
'PhpOffice\\PhpSpreadsheet\\Reader\\Xls\\Biff5' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xls/Biff5.php',
'PhpOffice\\PhpSpreadsheet\\Reader\\Xls\\Biff8' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xls/Biff8.php',
'PhpOffice\\PhpSpreadsheet\\Reader\\Xls\\Color' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xls/Color.php',
'PhpOffice\\PhpSpreadsheet\\Reader\\Xls\\Color\\BIFF5' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xls/Color/BIFF5.php',
'PhpOffice\\PhpSpreadsheet\\Reader\\Xls\\Color\\BIFF8' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xls/Color/BIFF8.php',
@@ -370,7 +389,10 @@ return array(
'PhpOffice\\PhpSpreadsheet\\Reader\\Xls\\DataValidationHelper' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xls/DataValidationHelper.php',
'PhpOffice\\PhpSpreadsheet\\Reader\\Xls\\ErrorCode' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xls/ErrorCode.php',
'PhpOffice\\PhpSpreadsheet\\Reader\\Xls\\Escher' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xls/Escher.php',
'PhpOffice\\PhpSpreadsheet\\Reader\\Xls\\ListFunctions' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xls/ListFunctions.php',
'PhpOffice\\PhpSpreadsheet\\Reader\\Xls\\LoadSpreadsheet' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xls/LoadSpreadsheet.php',
'PhpOffice\\PhpSpreadsheet\\Reader\\Xls\\MD5' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xls/MD5.php',
'PhpOffice\\PhpSpreadsheet\\Reader\\Xls\\Mappings' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xls/Mappings.php',
'PhpOffice\\PhpSpreadsheet\\Reader\\Xls\\RC4' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xls/RC4.php',
'PhpOffice\\PhpSpreadsheet\\Reader\\Xls\\Style\\Border' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xls/Style/Border.php',
'PhpOffice\\PhpSpreadsheet\\Reader\\Xls\\Style\\CellAlignment' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xls/Style/CellAlignment.php',
@@ -456,6 +478,8 @@ return array(
'PhpOffice\\PhpSpreadsheet\\Style\\ConditionalFormatting\\ConditionalDataBarExtension' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalDataBarExtension.php',
'PhpOffice\\PhpSpreadsheet\\Style\\ConditionalFormatting\\ConditionalFormatValueObject' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalFormatValueObject.php',
'PhpOffice\\PhpSpreadsheet\\Style\\ConditionalFormatting\\ConditionalFormattingRuleExtension' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalFormattingRuleExtension.php',
'PhpOffice\\PhpSpreadsheet\\Style\\ConditionalFormatting\\ConditionalIconSet' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalIconSet.php',
'PhpOffice\\PhpSpreadsheet\\Style\\ConditionalFormatting\\IconSetValues' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/ConditionalFormatting/IconSetValues.php',
'PhpOffice\\PhpSpreadsheet\\Style\\ConditionalFormatting\\StyleMerger' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/ConditionalFormatting/StyleMerger.php',
'PhpOffice\\PhpSpreadsheet\\Style\\ConditionalFormatting\\Wizard' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/ConditionalFormatting/Wizard.php',
'PhpOffice\\PhpSpreadsheet\\Style\\ConditionalFormatting\\Wizard\\Blanks' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/ConditionalFormatting/Wizard/Blanks.php',
@@ -478,6 +502,8 @@ return array(
'PhpOffice\\PhpSpreadsheet\\Style\\NumberFormat\\PercentageFormatter' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/NumberFormat/PercentageFormatter.php',
'PhpOffice\\PhpSpreadsheet\\Style\\NumberFormat\\Wizard\\Accounting' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/NumberFormat/Wizard/Accounting.php',
'PhpOffice\\PhpSpreadsheet\\Style\\NumberFormat\\Wizard\\Currency' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/NumberFormat/Wizard/Currency.php',
'PhpOffice\\PhpSpreadsheet\\Style\\NumberFormat\\Wizard\\CurrencyBase' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/NumberFormat/Wizard/CurrencyBase.php',
'PhpOffice\\PhpSpreadsheet\\Style\\NumberFormat\\Wizard\\CurrencyNegative' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/NumberFormat/Wizard/CurrencyNegative.php',
'PhpOffice\\PhpSpreadsheet\\Style\\NumberFormat\\Wizard\\Date' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/NumberFormat/Wizard/Date.php',
'PhpOffice\\PhpSpreadsheet\\Style\\NumberFormat\\Wizard\\DateTime' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/NumberFormat/Wizard/DateTime.php',
'PhpOffice\\PhpSpreadsheet\\Style\\NumberFormat\\Wizard\\DateTimeWizard' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/NumberFormat/Wizard/DateTimeWizard.php',
@@ -524,6 +550,7 @@ return array(
'PhpOffice\\PhpSpreadsheet\\Worksheet\\SheetView' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Worksheet/SheetView.php',
'PhpOffice\\PhpSpreadsheet\\Worksheet\\Table' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Worksheet/Table.php',
'PhpOffice\\PhpSpreadsheet\\Worksheet\\Table\\Column' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Worksheet/Table/Column.php',
'PhpOffice\\PhpSpreadsheet\\Worksheet\\Table\\TableDxfsStyle' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Worksheet/Table/TableDxfsStyle.php',
'PhpOffice\\PhpSpreadsheet\\Worksheet\\Table\\TableStyle' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Worksheet/Table/TableStyle.php',
'PhpOffice\\PhpSpreadsheet\\Worksheet\\Validations' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Worksheet/Validations.php',
'PhpOffice\\PhpSpreadsheet\\Worksheet\\Worksheet' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Worksheet/Worksheet.php',
@@ -561,7 +588,6 @@ return array(
'PhpOffice\\PhpSpreadsheet\\Writer\\Xls\\Style\\CellAlignment' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Xls/Style/CellAlignment.php',
'PhpOffice\\PhpSpreadsheet\\Writer\\Xls\\Style\\CellBorder' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Xls/Style/CellBorder.php',
'PhpOffice\\PhpSpreadsheet\\Writer\\Xls\\Style\\CellFill' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Xls/Style/CellFill.php',
'PhpOffice\\PhpSpreadsheet\\Writer\\Xls\\Style\\ColorMap' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Xls/Style/ColorMap.php',
'PhpOffice\\PhpSpreadsheet\\Writer\\Xls\\Workbook' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Xls/Workbook.php',
'PhpOffice\\PhpSpreadsheet\\Writer\\Xls\\Worksheet' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Xls/Worksheet.php',
'PhpOffice\\PhpSpreadsheet\\Writer\\Xls\\Xf' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Xls/Xf.php',
@@ -574,6 +600,7 @@ return array(
'PhpOffice\\PhpSpreadsheet\\Writer\\Xlsx\\DocProps' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Xlsx/DocProps.php',
'PhpOffice\\PhpSpreadsheet\\Writer\\Xlsx\\Drawing' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Xlsx/Drawing.php',
'PhpOffice\\PhpSpreadsheet\\Writer\\Xlsx\\FunctionPrefix' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Xlsx/FunctionPrefix.php',
'PhpOffice\\PhpSpreadsheet\\Writer\\Xlsx\\Metadata' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Xlsx/Metadata.php',
'PhpOffice\\PhpSpreadsheet\\Writer\\Xlsx\\Rels' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Xlsx/Rels.php',
'PhpOffice\\PhpSpreadsheet\\Writer\\Xlsx\\RelsRibbon' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Xlsx/RelsRibbon.php',
'PhpOffice\\PhpSpreadsheet\\Writer\\Xlsx\\RelsVBA' => $vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Xlsx/RelsVBA.php',
@@ -1001,6 +1028,7 @@ return array(
'ZipStream\\LocalFileHeader' => $vendorDir . '/maennchen/zipstream-php/src/LocalFileHeader.php',
'ZipStream\\OperationMode' => $vendorDir . '/maennchen/zipstream-php/src/OperationMode.php',
'ZipStream\\PackField' => $vendorDir . '/maennchen/zipstream-php/src/PackField.php',
'ZipStream\\Stream\\CallbackStreamWrapper' => $vendorDir . '/maennchen/zipstream-php/src/Stream/CallbackStreamWrapper.php',
'ZipStream\\Time' => $vendorDir . '/maennchen/zipstream-php/src/Time.php',
'ZipStream\\Version' => $vendorDir . '/maennchen/zipstream-php/src/Version.php',
'ZipStream\\Zip64\\DataDescriptor' => $vendorDir . '/maennchen/zipstream-php/src/Zip64/DataDescriptor.php',
@@ -1009,4 +1037,55 @@ return array(
'ZipStream\\Zip64\\ExtendedInformationExtraField' => $vendorDir . '/maennchen/zipstream-php/src/Zip64/ExtendedInformationExtraField.php',
'ZipStream\\ZipStream' => $vendorDir . '/maennchen/zipstream-php/src/ZipStream.php',
'ZipStream\\Zs\\ExtendedInformationExtraField' => $vendorDir . '/maennchen/zipstream-php/src/Zs/ExtendedInformationExtraField.php',
'setasign\\Fpdi\\FpdfTpl' => $vendorDir . '/setasign/fpdi/src/FpdfTpl.php',
'setasign\\Fpdi\\FpdfTplTrait' => $vendorDir . '/setasign/fpdi/src/FpdfTplTrait.php',
'setasign\\Fpdi\\FpdfTrait' => $vendorDir . '/setasign/fpdi/src/FpdfTrait.php',
'setasign\\Fpdi\\Fpdi' => $vendorDir . '/setasign/fpdi/src/Fpdi.php',
'setasign\\Fpdi\\FpdiException' => $vendorDir . '/setasign/fpdi/src/FpdiException.php',
'setasign\\Fpdi\\FpdiTrait' => $vendorDir . '/setasign/fpdi/src/FpdiTrait.php',
'setasign\\Fpdi\\GraphicsState' => $vendorDir . '/setasign/fpdi/src/GraphicsState.php',
'setasign\\Fpdi\\Math\\Matrix' => $vendorDir . '/setasign/fpdi/src/Math/Matrix.php',
'setasign\\Fpdi\\Math\\Vector' => $vendorDir . '/setasign/fpdi/src/Math/Vector.php',
'setasign\\Fpdi\\PdfParser\\CrossReference\\AbstractReader' => $vendorDir . '/setasign/fpdi/src/PdfParser/CrossReference/AbstractReader.php',
'setasign\\Fpdi\\PdfParser\\CrossReference\\CrossReference' => $vendorDir . '/setasign/fpdi/src/PdfParser/CrossReference/CrossReference.php',
'setasign\\Fpdi\\PdfParser\\CrossReference\\CrossReferenceException' => $vendorDir . '/setasign/fpdi/src/PdfParser/CrossReference/CrossReferenceException.php',
'setasign\\Fpdi\\PdfParser\\CrossReference\\FixedReader' => $vendorDir . '/setasign/fpdi/src/PdfParser/CrossReference/FixedReader.php',
'setasign\\Fpdi\\PdfParser\\CrossReference\\LineReader' => $vendorDir . '/setasign/fpdi/src/PdfParser/CrossReference/LineReader.php',
'setasign\\Fpdi\\PdfParser\\CrossReference\\ReaderInterface' => $vendorDir . '/setasign/fpdi/src/PdfParser/CrossReference/ReaderInterface.php',
'setasign\\Fpdi\\PdfParser\\Filter\\Ascii85' => $vendorDir . '/setasign/fpdi/src/PdfParser/Filter/Ascii85.php',
'setasign\\Fpdi\\PdfParser\\Filter\\Ascii85Exception' => $vendorDir . '/setasign/fpdi/src/PdfParser/Filter/Ascii85Exception.php',
'setasign\\Fpdi\\PdfParser\\Filter\\AsciiHex' => $vendorDir . '/setasign/fpdi/src/PdfParser/Filter/AsciiHex.php',
'setasign\\Fpdi\\PdfParser\\Filter\\FilterException' => $vendorDir . '/setasign/fpdi/src/PdfParser/Filter/FilterException.php',
'setasign\\Fpdi\\PdfParser\\Filter\\FilterInterface' => $vendorDir . '/setasign/fpdi/src/PdfParser/Filter/FilterInterface.php',
'setasign\\Fpdi\\PdfParser\\Filter\\Flate' => $vendorDir . '/setasign/fpdi/src/PdfParser/Filter/Flate.php',
'setasign\\Fpdi\\PdfParser\\Filter\\FlateException' => $vendorDir . '/setasign/fpdi/src/PdfParser/Filter/FlateException.php',
'setasign\\Fpdi\\PdfParser\\Filter\\Lzw' => $vendorDir . '/setasign/fpdi/src/PdfParser/Filter/Lzw.php',
'setasign\\Fpdi\\PdfParser\\Filter\\LzwException' => $vendorDir . '/setasign/fpdi/src/PdfParser/Filter/LzwException.php',
'setasign\\Fpdi\\PdfParser\\PdfParser' => $vendorDir . '/setasign/fpdi/src/PdfParser/PdfParser.php',
'setasign\\Fpdi\\PdfParser\\PdfParserException' => $vendorDir . '/setasign/fpdi/src/PdfParser/PdfParserException.php',
'setasign\\Fpdi\\PdfParser\\StreamReader' => $vendorDir . '/setasign/fpdi/src/PdfParser/StreamReader.php',
'setasign\\Fpdi\\PdfParser\\Tokenizer' => $vendorDir . '/setasign/fpdi/src/PdfParser/Tokenizer.php',
'setasign\\Fpdi\\PdfParser\\Type\\PdfArray' => $vendorDir . '/setasign/fpdi/src/PdfParser/Type/PdfArray.php',
'setasign\\Fpdi\\PdfParser\\Type\\PdfBoolean' => $vendorDir . '/setasign/fpdi/src/PdfParser/Type/PdfBoolean.php',
'setasign\\Fpdi\\PdfParser\\Type\\PdfDictionary' => $vendorDir . '/setasign/fpdi/src/PdfParser/Type/PdfDictionary.php',
'setasign\\Fpdi\\PdfParser\\Type\\PdfHexString' => $vendorDir . '/setasign/fpdi/src/PdfParser/Type/PdfHexString.php',
'setasign\\Fpdi\\PdfParser\\Type\\PdfIndirectObject' => $vendorDir . '/setasign/fpdi/src/PdfParser/Type/PdfIndirectObject.php',
'setasign\\Fpdi\\PdfParser\\Type\\PdfIndirectObjectReference' => $vendorDir . '/setasign/fpdi/src/PdfParser/Type/PdfIndirectObjectReference.php',
'setasign\\Fpdi\\PdfParser\\Type\\PdfName' => $vendorDir . '/setasign/fpdi/src/PdfParser/Type/PdfName.php',
'setasign\\Fpdi\\PdfParser\\Type\\PdfNull' => $vendorDir . '/setasign/fpdi/src/PdfParser/Type/PdfNull.php',
'setasign\\Fpdi\\PdfParser\\Type\\PdfNumeric' => $vendorDir . '/setasign/fpdi/src/PdfParser/Type/PdfNumeric.php',
'setasign\\Fpdi\\PdfParser\\Type\\PdfStream' => $vendorDir . '/setasign/fpdi/src/PdfParser/Type/PdfStream.php',
'setasign\\Fpdi\\PdfParser\\Type\\PdfString' => $vendorDir . '/setasign/fpdi/src/PdfParser/Type/PdfString.php',
'setasign\\Fpdi\\PdfParser\\Type\\PdfToken' => $vendorDir . '/setasign/fpdi/src/PdfParser/Type/PdfToken.php',
'setasign\\Fpdi\\PdfParser\\Type\\PdfType' => $vendorDir . '/setasign/fpdi/src/PdfParser/Type/PdfType.php',
'setasign\\Fpdi\\PdfParser\\Type\\PdfTypeException' => $vendorDir . '/setasign/fpdi/src/PdfParser/Type/PdfTypeException.php',
'setasign\\Fpdi\\PdfReader\\DataStructure\\Rectangle' => $vendorDir . '/setasign/fpdi/src/PdfReader/DataStructure/Rectangle.php',
'setasign\\Fpdi\\PdfReader\\Page' => $vendorDir . '/setasign/fpdi/src/PdfReader/Page.php',
'setasign\\Fpdi\\PdfReader\\PageBoundaries' => $vendorDir . '/setasign/fpdi/src/PdfReader/PageBoundaries.php',
'setasign\\Fpdi\\PdfReader\\PdfReader' => $vendorDir . '/setasign/fpdi/src/PdfReader/PdfReader.php',
'setasign\\Fpdi\\PdfReader\\PdfReaderException' => $vendorDir . '/setasign/fpdi/src/PdfReader/PdfReaderException.php',
'setasign\\Fpdi\\TcpdfFpdi' => $vendorDir . '/setasign/fpdi/src/TcpdfFpdi.php',
'setasign\\Fpdi\\Tcpdf\\Fpdi' => $vendorDir . '/setasign/fpdi/src/Tcpdf/Fpdi.php',
'setasign\\Fpdi\\Tfpdf\\FpdfTpl' => $vendorDir . '/setasign/fpdi/src/Tfpdf/FpdfTpl.php',
'setasign\\Fpdi\\Tfpdf\\Fpdi' => $vendorDir . '/setasign/fpdi/src/Tfpdf/Fpdi.php',
);

View File

@@ -6,6 +6,7 @@ $vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);
return array(
'setasign\\Fpdi\\' => array($vendorDir . '/setasign/fpdi/src'),
'ZipStream\\' => array($vendorDir . '/maennchen/zipstream-php/src'),
'Stripe\\' => array($vendorDir . '/stripe/stripe-php/lib'),
'Psr\\SimpleCache\\' => array($vendorDir . '/psr/simple-cache/src'),

View File

@@ -7,6 +7,10 @@ namespace Composer\Autoload;
class ComposerStaticInit03e608fa83a14a82b3f9223977e9674e
{
public static $prefixLengthsPsr4 = array (
's' =>
array (
'setasign\\Fpdi\\' => 14,
),
'Z' =>
array (
'ZipStream\\' => 10,
@@ -35,6 +39,10 @@ class ComposerStaticInit03e608fa83a14a82b3f9223977e9674e
);
public static $prefixDirsPsr4 = array (
'setasign\\Fpdi\\' =>
array (
0 => __DIR__ . '/..' . '/setasign/fpdi/src',
),
'ZipStream\\' =>
array (
0 => __DIR__ . '/..' . '/maennchen/zipstream-php/src',
@@ -86,14 +94,19 @@ class ComposerStaticInit03e608fa83a14a82b3f9223977e9674e
'App\\Controllers\\ChatController' => __DIR__ . '/../..' . '/src/Controllers/ChatController.php',
'App\\Controllers\\EntiteController' => __DIR__ . '/../..' . '/src/Controllers/EntiteController.php',
'App\\Controllers\\FileController' => __DIR__ . '/../..' . '/src/Controllers/FileController.php',
'App\\Controllers\\HealthController' => __DIR__ . '/../..' . '/src/Controllers/HealthController.php',
'App\\Controllers\\LoginController' => __DIR__ . '/../..' . '/src/Controllers/LoginController.php',
'App\\Controllers\\MigrationController' => __DIR__ . '/../..' . '/src/Controllers/MigrationController.php',
'App\\Controllers\\OperationController' => __DIR__ . '/../..' . '/src/Controllers/OperationController.php',
'App\\Controllers\\PassageController' => __DIR__ . '/../..' . '/src/Controllers/PassageController.php',
'App\\Controllers\\PasswordController' => __DIR__ . '/../..' . '/src/Controllers/PasswordController.php',
'App\\Controllers\\SectorController' => __DIR__ . '/../..' . '/src/Controllers/SectorController.php',
'App\\Controllers\\SecurityController' => __DIR__ . '/../..' . '/src/Controllers/SecurityController.php',
'App\\Controllers\\StripeController' => __DIR__ . '/../..' . '/src/Controllers/StripeController.php',
'App\\Controllers\\StripeWebhookController' => __DIR__ . '/../..' . '/src/Controllers/StripeWebhookController.php',
'App\\Controllers\\UserController' => __DIR__ . '/../..' . '/src/Controllers/UserController.php',
'App\\Controllers\\VilleController' => __DIR__ . '/../..' . '/src/Controllers/VilleController.php',
'App\\Core\\Controller' => __DIR__ . '/../..' . '/src/Core/Controller.php',
'App\\Services\\PDFGenerator' => __DIR__ . '/../..' . '/src/Services/PDFGenerator.php',
'App\\Services\\PasswordSecurityService' => __DIR__ . '/../..' . '/src/Services/PasswordSecurityService.php',
'App\\Services\\ReceiptPDFGenerator' => __DIR__ . '/../..' . '/src/Services/ReceiptPDFGenerator.php',
@@ -104,6 +117,7 @@ class ComposerStaticInit03e608fa83a14a82b3f9223977e9674e
'App\\Services\\Security\\PerformanceMonitor' => __DIR__ . '/../..' . '/src/Services/Security/PerformanceMonitor.php',
'App\\Services\\Security\\SecurityMonitor' => __DIR__ . '/../..' . '/src/Services/Security/SecurityMonitor.php',
'App\\Services\\SimplePDF' => __DIR__ . '/../..' . '/src/Services/SimplePDF.php',
'App\\Services\\StripeService' => __DIR__ . '/../..' . '/src/Services/StripeService.php',
'BackupEncryptionService' => __DIR__ . '/../..' . '/src/Services/BackupEncryptionService.php',
'ClientDetector' => __DIR__ . '/../..' . '/src/Utils/ClientDetector.php',
'Complex\\Complex' => __DIR__ . '/..' . '/markbaker/complex/classes/src/Complex.php',
@@ -131,6 +145,7 @@ class ComposerStaticInit03e608fa83a14a82b3f9223977e9674e
'Database' => __DIR__ . '/../..' . '/src/Core/Database.php',
'DepartmentBoundaryService' => __DIR__ . '/../..' . '/src/Services/DepartmentBoundaryService.php',
'EmailTemplates' => __DIR__ . '/../..' . '/src/Services/EmailTemplates.php',
'EventLogService' => __DIR__ . '/../..' . '/src/Services/EventLogService.php',
'ExportService' => __DIR__ . '/../..' . '/src/Services/ExportService.php',
'FPDF' => __DIR__ . '/..' . '/setasign/fpdf/fpdf.php',
'FileService' => __DIR__ . '/../..' . '/src/Services/FileService.php',
@@ -151,6 +166,7 @@ class ComposerStaticInit03e608fa83a14a82b3f9223977e9674e
'Matrix\\Operators\\Multiplication' => __DIR__ . '/..' . '/markbaker/matrix/classes/src/Operators/Multiplication.php',
'Matrix\\Operators\\Operator' => __DIR__ . '/..' . '/markbaker/matrix/classes/src/Operators/Operator.php',
'Matrix\\Operators\\Subtraction' => __DIR__ . '/..' . '/markbaker/matrix/classes/src/Operators/Subtraction.php',
'MigrationService' => __DIR__ . '/../..' . '/src/Services/MigrationService.php',
'MonitoredDatabase' => __DIR__ . '/../..' . '/src/Core/MonitoredDatabase.php',
'MonitoredStatement' => __DIR__ . '/../..' . '/src/Core/MonitoredDatabase.php',
'OperationDataService' => __DIR__ . '/../..' . '/src/Services/OperationDataService.php',
@@ -164,6 +180,8 @@ class ComposerStaticInit03e608fa83a14a82b3f9223977e9674e
'PhpOffice\\PhpSpreadsheet\\Calculation\\ArrayEnabled' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/ArrayEnabled.php',
'PhpOffice\\PhpSpreadsheet\\Calculation\\BinaryComparison' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/BinaryComparison.php',
'PhpOffice\\PhpSpreadsheet\\Calculation\\Calculation' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/Calculation.php',
'PhpOffice\\PhpSpreadsheet\\Calculation\\CalculationBase' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/CalculationBase.php',
'PhpOffice\\PhpSpreadsheet\\Calculation\\CalculationLocale' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/CalculationLocale.php',
'PhpOffice\\PhpSpreadsheet\\Calculation\\Category' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/Category.php',
'PhpOffice\\PhpSpreadsheet\\Calculation\\Database\\DAverage' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/Database/DAverage.php',
'PhpOffice\\PhpSpreadsheet\\Calculation\\Database\\DCount' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/Database/DCount.php',
@@ -249,21 +267,25 @@ class ComposerStaticInit03e608fa83a14a82b3f9223977e9674e
'PhpOffice\\PhpSpreadsheet\\Calculation\\Financial\\TreasuryBill' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/Financial/TreasuryBill.php',
'PhpOffice\\PhpSpreadsheet\\Calculation\\FormulaParser' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/FormulaParser.php',
'PhpOffice\\PhpSpreadsheet\\Calculation\\FormulaToken' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/FormulaToken.php',
'PhpOffice\\PhpSpreadsheet\\Calculation\\FunctionArray' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/FunctionArray.php',
'PhpOffice\\PhpSpreadsheet\\Calculation\\Functions' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/Functions.php',
'PhpOffice\\PhpSpreadsheet\\Calculation\\Information\\ErrorValue' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/Information/ErrorValue.php',
'PhpOffice\\PhpSpreadsheet\\Calculation\\Information\\ExcelError' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/Information/ExcelError.php',
'PhpOffice\\PhpSpreadsheet\\Calculation\\Information\\Value' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/Information/Value.php',
'PhpOffice\\PhpSpreadsheet\\Calculation\\Internal\\ExcelArrayPseudoFunctions' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/Internal/ExcelArrayPseudoFunctions.php',
'PhpOffice\\PhpSpreadsheet\\Calculation\\Internal\\MakeMatrix' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/Internal/MakeMatrix.php',
'PhpOffice\\PhpSpreadsheet\\Calculation\\Internal\\WildcardMatch' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/Internal/WildcardMatch.php',
'PhpOffice\\PhpSpreadsheet\\Calculation\\Logical\\Boolean' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/Logical/Boolean.php',
'PhpOffice\\PhpSpreadsheet\\Calculation\\Logical\\Conditional' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/Logical/Conditional.php',
'PhpOffice\\PhpSpreadsheet\\Calculation\\Logical\\Operations' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/Logical/Operations.php',
'PhpOffice\\PhpSpreadsheet\\Calculation\\LookupRef\\Address' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/LookupRef/Address.php',
'PhpOffice\\PhpSpreadsheet\\Calculation\\LookupRef\\ChooseRowsEtc' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/LookupRef/ChooseRowsEtc.php',
'PhpOffice\\PhpSpreadsheet\\Calculation\\LookupRef\\ExcelMatch' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/LookupRef/ExcelMatch.php',
'PhpOffice\\PhpSpreadsheet\\Calculation\\LookupRef\\Filter' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/LookupRef/Filter.php',
'PhpOffice\\PhpSpreadsheet\\Calculation\\LookupRef\\Formula' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/LookupRef/Formula.php',
'PhpOffice\\PhpSpreadsheet\\Calculation\\LookupRef\\HLookup' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/LookupRef/HLookup.php',
'PhpOffice\\PhpSpreadsheet\\Calculation\\LookupRef\\Helpers' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/LookupRef/Helpers.php',
'PhpOffice\\PhpSpreadsheet\\Calculation\\LookupRef\\Hstack' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/LookupRef/Hstack.php',
'PhpOffice\\PhpSpreadsheet\\Calculation\\LookupRef\\Hyperlink' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/LookupRef/Hyperlink.php',
'PhpOffice\\PhpSpreadsheet\\Calculation\\LookupRef\\Indirect' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/LookupRef/Indirect.php',
'PhpOffice\\PhpSpreadsheet\\Calculation\\LookupRef\\Lookup' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/LookupRef/Lookup.php',
@@ -274,8 +296,10 @@ class ComposerStaticInit03e608fa83a14a82b3f9223977e9674e
'PhpOffice\\PhpSpreadsheet\\Calculation\\LookupRef\\RowColumnInformation' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/LookupRef/RowColumnInformation.php',
'PhpOffice\\PhpSpreadsheet\\Calculation\\LookupRef\\Selection' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/LookupRef/Selection.php',
'PhpOffice\\PhpSpreadsheet\\Calculation\\LookupRef\\Sort' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/LookupRef/Sort.php',
'PhpOffice\\PhpSpreadsheet\\Calculation\\LookupRef\\TorowTocol' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/LookupRef/TorowTocol.php',
'PhpOffice\\PhpSpreadsheet\\Calculation\\LookupRef\\Unique' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/LookupRef/Unique.php',
'PhpOffice\\PhpSpreadsheet\\Calculation\\LookupRef\\VLookup' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/LookupRef/VLookup.php',
'PhpOffice\\PhpSpreadsheet\\Calculation\\LookupRef\\Vstack' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/LookupRef/Vstack.php',
'PhpOffice\\PhpSpreadsheet\\Calculation\\MathTrig\\Absolute' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/MathTrig/Absolute.php',
'PhpOffice\\PhpSpreadsheet\\Calculation\\MathTrig\\Angle' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/MathTrig/Angle.php',
'PhpOffice\\PhpSpreadsheet\\Calculation\\MathTrig\\Arabic' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/MathTrig/Arabic.php',
@@ -435,6 +459,9 @@ class ComposerStaticInit03e608fa83a14a82b3f9223977e9674e
'PhpOffice\\PhpSpreadsheet\\Reader\\Security\\XmlScanner' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Security/XmlScanner.php',
'PhpOffice\\PhpSpreadsheet\\Reader\\Slk' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Slk.php',
'PhpOffice\\PhpSpreadsheet\\Reader\\Xls' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xls.php',
'PhpOffice\\PhpSpreadsheet\\Reader\\XlsBase' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/XlsBase.php',
'PhpOffice\\PhpSpreadsheet\\Reader\\Xls\\Biff5' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xls/Biff5.php',
'PhpOffice\\PhpSpreadsheet\\Reader\\Xls\\Biff8' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xls/Biff8.php',
'PhpOffice\\PhpSpreadsheet\\Reader\\Xls\\Color' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xls/Color.php',
'PhpOffice\\PhpSpreadsheet\\Reader\\Xls\\Color\\BIFF5' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xls/Color/BIFF5.php',
'PhpOffice\\PhpSpreadsheet\\Reader\\Xls\\Color\\BIFF8' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xls/Color/BIFF8.php',
@@ -443,7 +470,10 @@ class ComposerStaticInit03e608fa83a14a82b3f9223977e9674e
'PhpOffice\\PhpSpreadsheet\\Reader\\Xls\\DataValidationHelper' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xls/DataValidationHelper.php',
'PhpOffice\\PhpSpreadsheet\\Reader\\Xls\\ErrorCode' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xls/ErrorCode.php',
'PhpOffice\\PhpSpreadsheet\\Reader\\Xls\\Escher' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xls/Escher.php',
'PhpOffice\\PhpSpreadsheet\\Reader\\Xls\\ListFunctions' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xls/ListFunctions.php',
'PhpOffice\\PhpSpreadsheet\\Reader\\Xls\\LoadSpreadsheet' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xls/LoadSpreadsheet.php',
'PhpOffice\\PhpSpreadsheet\\Reader\\Xls\\MD5' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xls/MD5.php',
'PhpOffice\\PhpSpreadsheet\\Reader\\Xls\\Mappings' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xls/Mappings.php',
'PhpOffice\\PhpSpreadsheet\\Reader\\Xls\\RC4' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xls/RC4.php',
'PhpOffice\\PhpSpreadsheet\\Reader\\Xls\\Style\\Border' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xls/Style/Border.php',
'PhpOffice\\PhpSpreadsheet\\Reader\\Xls\\Style\\CellAlignment' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xls/Style/CellAlignment.php',
@@ -529,6 +559,8 @@ class ComposerStaticInit03e608fa83a14a82b3f9223977e9674e
'PhpOffice\\PhpSpreadsheet\\Style\\ConditionalFormatting\\ConditionalDataBarExtension' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalDataBarExtension.php',
'PhpOffice\\PhpSpreadsheet\\Style\\ConditionalFormatting\\ConditionalFormatValueObject' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalFormatValueObject.php',
'PhpOffice\\PhpSpreadsheet\\Style\\ConditionalFormatting\\ConditionalFormattingRuleExtension' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalFormattingRuleExtension.php',
'PhpOffice\\PhpSpreadsheet\\Style\\ConditionalFormatting\\ConditionalIconSet' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalIconSet.php',
'PhpOffice\\PhpSpreadsheet\\Style\\ConditionalFormatting\\IconSetValues' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/ConditionalFormatting/IconSetValues.php',
'PhpOffice\\PhpSpreadsheet\\Style\\ConditionalFormatting\\StyleMerger' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/ConditionalFormatting/StyleMerger.php',
'PhpOffice\\PhpSpreadsheet\\Style\\ConditionalFormatting\\Wizard' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/ConditionalFormatting/Wizard.php',
'PhpOffice\\PhpSpreadsheet\\Style\\ConditionalFormatting\\Wizard\\Blanks' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/ConditionalFormatting/Wizard/Blanks.php',
@@ -551,6 +583,8 @@ class ComposerStaticInit03e608fa83a14a82b3f9223977e9674e
'PhpOffice\\PhpSpreadsheet\\Style\\NumberFormat\\PercentageFormatter' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/NumberFormat/PercentageFormatter.php',
'PhpOffice\\PhpSpreadsheet\\Style\\NumberFormat\\Wizard\\Accounting' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/NumberFormat/Wizard/Accounting.php',
'PhpOffice\\PhpSpreadsheet\\Style\\NumberFormat\\Wizard\\Currency' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/NumberFormat/Wizard/Currency.php',
'PhpOffice\\PhpSpreadsheet\\Style\\NumberFormat\\Wizard\\CurrencyBase' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/NumberFormat/Wizard/CurrencyBase.php',
'PhpOffice\\PhpSpreadsheet\\Style\\NumberFormat\\Wizard\\CurrencyNegative' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/NumberFormat/Wizard/CurrencyNegative.php',
'PhpOffice\\PhpSpreadsheet\\Style\\NumberFormat\\Wizard\\Date' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/NumberFormat/Wizard/Date.php',
'PhpOffice\\PhpSpreadsheet\\Style\\NumberFormat\\Wizard\\DateTime' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/NumberFormat/Wizard/DateTime.php',
'PhpOffice\\PhpSpreadsheet\\Style\\NumberFormat\\Wizard\\DateTimeWizard' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/NumberFormat/Wizard/DateTimeWizard.php',
@@ -597,6 +631,7 @@ class ComposerStaticInit03e608fa83a14a82b3f9223977e9674e
'PhpOffice\\PhpSpreadsheet\\Worksheet\\SheetView' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Worksheet/SheetView.php',
'PhpOffice\\PhpSpreadsheet\\Worksheet\\Table' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Worksheet/Table.php',
'PhpOffice\\PhpSpreadsheet\\Worksheet\\Table\\Column' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Worksheet/Table/Column.php',
'PhpOffice\\PhpSpreadsheet\\Worksheet\\Table\\TableDxfsStyle' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Worksheet/Table/TableDxfsStyle.php',
'PhpOffice\\PhpSpreadsheet\\Worksheet\\Table\\TableStyle' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Worksheet/Table/TableStyle.php',
'PhpOffice\\PhpSpreadsheet\\Worksheet\\Validations' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Worksheet/Validations.php',
'PhpOffice\\PhpSpreadsheet\\Worksheet\\Worksheet' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Worksheet/Worksheet.php',
@@ -634,7 +669,6 @@ class ComposerStaticInit03e608fa83a14a82b3f9223977e9674e
'PhpOffice\\PhpSpreadsheet\\Writer\\Xls\\Style\\CellAlignment' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Xls/Style/CellAlignment.php',
'PhpOffice\\PhpSpreadsheet\\Writer\\Xls\\Style\\CellBorder' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Xls/Style/CellBorder.php',
'PhpOffice\\PhpSpreadsheet\\Writer\\Xls\\Style\\CellFill' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Xls/Style/CellFill.php',
'PhpOffice\\PhpSpreadsheet\\Writer\\Xls\\Style\\ColorMap' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Xls/Style/ColorMap.php',
'PhpOffice\\PhpSpreadsheet\\Writer\\Xls\\Workbook' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Xls/Workbook.php',
'PhpOffice\\PhpSpreadsheet\\Writer\\Xls\\Worksheet' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Xls/Worksheet.php',
'PhpOffice\\PhpSpreadsheet\\Writer\\Xls\\Xf' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Xls/Xf.php',
@@ -647,6 +681,7 @@ class ComposerStaticInit03e608fa83a14a82b3f9223977e9674e
'PhpOffice\\PhpSpreadsheet\\Writer\\Xlsx\\DocProps' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Xlsx/DocProps.php',
'PhpOffice\\PhpSpreadsheet\\Writer\\Xlsx\\Drawing' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Xlsx/Drawing.php',
'PhpOffice\\PhpSpreadsheet\\Writer\\Xlsx\\FunctionPrefix' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Xlsx/FunctionPrefix.php',
'PhpOffice\\PhpSpreadsheet\\Writer\\Xlsx\\Metadata' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Xlsx/Metadata.php',
'PhpOffice\\PhpSpreadsheet\\Writer\\Xlsx\\Rels' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Xlsx/Rels.php',
'PhpOffice\\PhpSpreadsheet\\Writer\\Xlsx\\RelsRibbon' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Xlsx/RelsRibbon.php',
'PhpOffice\\PhpSpreadsheet\\Writer\\Xlsx\\RelsVBA' => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Xlsx/RelsVBA.php',
@@ -1074,6 +1109,7 @@ class ComposerStaticInit03e608fa83a14a82b3f9223977e9674e
'ZipStream\\LocalFileHeader' => __DIR__ . '/..' . '/maennchen/zipstream-php/src/LocalFileHeader.php',
'ZipStream\\OperationMode' => __DIR__ . '/..' . '/maennchen/zipstream-php/src/OperationMode.php',
'ZipStream\\PackField' => __DIR__ . '/..' . '/maennchen/zipstream-php/src/PackField.php',
'ZipStream\\Stream\\CallbackStreamWrapper' => __DIR__ . '/..' . '/maennchen/zipstream-php/src/Stream/CallbackStreamWrapper.php',
'ZipStream\\Time' => __DIR__ . '/..' . '/maennchen/zipstream-php/src/Time.php',
'ZipStream\\Version' => __DIR__ . '/..' . '/maennchen/zipstream-php/src/Version.php',
'ZipStream\\Zip64\\DataDescriptor' => __DIR__ . '/..' . '/maennchen/zipstream-php/src/Zip64/DataDescriptor.php',
@@ -1082,6 +1118,57 @@ class ComposerStaticInit03e608fa83a14a82b3f9223977e9674e
'ZipStream\\Zip64\\ExtendedInformationExtraField' => __DIR__ . '/..' . '/maennchen/zipstream-php/src/Zip64/ExtendedInformationExtraField.php',
'ZipStream\\ZipStream' => __DIR__ . '/..' . '/maennchen/zipstream-php/src/ZipStream.php',
'ZipStream\\Zs\\ExtendedInformationExtraField' => __DIR__ . '/..' . '/maennchen/zipstream-php/src/Zs/ExtendedInformationExtraField.php',
'setasign\\Fpdi\\FpdfTpl' => __DIR__ . '/..' . '/setasign/fpdi/src/FpdfTpl.php',
'setasign\\Fpdi\\FpdfTplTrait' => __DIR__ . '/..' . '/setasign/fpdi/src/FpdfTplTrait.php',
'setasign\\Fpdi\\FpdfTrait' => __DIR__ . '/..' . '/setasign/fpdi/src/FpdfTrait.php',
'setasign\\Fpdi\\Fpdi' => __DIR__ . '/..' . '/setasign/fpdi/src/Fpdi.php',
'setasign\\Fpdi\\FpdiException' => __DIR__ . '/..' . '/setasign/fpdi/src/FpdiException.php',
'setasign\\Fpdi\\FpdiTrait' => __DIR__ . '/..' . '/setasign/fpdi/src/FpdiTrait.php',
'setasign\\Fpdi\\GraphicsState' => __DIR__ . '/..' . '/setasign/fpdi/src/GraphicsState.php',
'setasign\\Fpdi\\Math\\Matrix' => __DIR__ . '/..' . '/setasign/fpdi/src/Math/Matrix.php',
'setasign\\Fpdi\\Math\\Vector' => __DIR__ . '/..' . '/setasign/fpdi/src/Math/Vector.php',
'setasign\\Fpdi\\PdfParser\\CrossReference\\AbstractReader' => __DIR__ . '/..' . '/setasign/fpdi/src/PdfParser/CrossReference/AbstractReader.php',
'setasign\\Fpdi\\PdfParser\\CrossReference\\CrossReference' => __DIR__ . '/..' . '/setasign/fpdi/src/PdfParser/CrossReference/CrossReference.php',
'setasign\\Fpdi\\PdfParser\\CrossReference\\CrossReferenceException' => __DIR__ . '/..' . '/setasign/fpdi/src/PdfParser/CrossReference/CrossReferenceException.php',
'setasign\\Fpdi\\PdfParser\\CrossReference\\FixedReader' => __DIR__ . '/..' . '/setasign/fpdi/src/PdfParser/CrossReference/FixedReader.php',
'setasign\\Fpdi\\PdfParser\\CrossReference\\LineReader' => __DIR__ . '/..' . '/setasign/fpdi/src/PdfParser/CrossReference/LineReader.php',
'setasign\\Fpdi\\PdfParser\\CrossReference\\ReaderInterface' => __DIR__ . '/..' . '/setasign/fpdi/src/PdfParser/CrossReference/ReaderInterface.php',
'setasign\\Fpdi\\PdfParser\\Filter\\Ascii85' => __DIR__ . '/..' . '/setasign/fpdi/src/PdfParser/Filter/Ascii85.php',
'setasign\\Fpdi\\PdfParser\\Filter\\Ascii85Exception' => __DIR__ . '/..' . '/setasign/fpdi/src/PdfParser/Filter/Ascii85Exception.php',
'setasign\\Fpdi\\PdfParser\\Filter\\AsciiHex' => __DIR__ . '/..' . '/setasign/fpdi/src/PdfParser/Filter/AsciiHex.php',
'setasign\\Fpdi\\PdfParser\\Filter\\FilterException' => __DIR__ . '/..' . '/setasign/fpdi/src/PdfParser/Filter/FilterException.php',
'setasign\\Fpdi\\PdfParser\\Filter\\FilterInterface' => __DIR__ . '/..' . '/setasign/fpdi/src/PdfParser/Filter/FilterInterface.php',
'setasign\\Fpdi\\PdfParser\\Filter\\Flate' => __DIR__ . '/..' . '/setasign/fpdi/src/PdfParser/Filter/Flate.php',
'setasign\\Fpdi\\PdfParser\\Filter\\FlateException' => __DIR__ . '/..' . '/setasign/fpdi/src/PdfParser/Filter/FlateException.php',
'setasign\\Fpdi\\PdfParser\\Filter\\Lzw' => __DIR__ . '/..' . '/setasign/fpdi/src/PdfParser/Filter/Lzw.php',
'setasign\\Fpdi\\PdfParser\\Filter\\LzwException' => __DIR__ . '/..' . '/setasign/fpdi/src/PdfParser/Filter/LzwException.php',
'setasign\\Fpdi\\PdfParser\\PdfParser' => __DIR__ . '/..' . '/setasign/fpdi/src/PdfParser/PdfParser.php',
'setasign\\Fpdi\\PdfParser\\PdfParserException' => __DIR__ . '/..' . '/setasign/fpdi/src/PdfParser/PdfParserException.php',
'setasign\\Fpdi\\PdfParser\\StreamReader' => __DIR__ . '/..' . '/setasign/fpdi/src/PdfParser/StreamReader.php',
'setasign\\Fpdi\\PdfParser\\Tokenizer' => __DIR__ . '/..' . '/setasign/fpdi/src/PdfParser/Tokenizer.php',
'setasign\\Fpdi\\PdfParser\\Type\\PdfArray' => __DIR__ . '/..' . '/setasign/fpdi/src/PdfParser/Type/PdfArray.php',
'setasign\\Fpdi\\PdfParser\\Type\\PdfBoolean' => __DIR__ . '/..' . '/setasign/fpdi/src/PdfParser/Type/PdfBoolean.php',
'setasign\\Fpdi\\PdfParser\\Type\\PdfDictionary' => __DIR__ . '/..' . '/setasign/fpdi/src/PdfParser/Type/PdfDictionary.php',
'setasign\\Fpdi\\PdfParser\\Type\\PdfHexString' => __DIR__ . '/..' . '/setasign/fpdi/src/PdfParser/Type/PdfHexString.php',
'setasign\\Fpdi\\PdfParser\\Type\\PdfIndirectObject' => __DIR__ . '/..' . '/setasign/fpdi/src/PdfParser/Type/PdfIndirectObject.php',
'setasign\\Fpdi\\PdfParser\\Type\\PdfIndirectObjectReference' => __DIR__ . '/..' . '/setasign/fpdi/src/PdfParser/Type/PdfIndirectObjectReference.php',
'setasign\\Fpdi\\PdfParser\\Type\\PdfName' => __DIR__ . '/..' . '/setasign/fpdi/src/PdfParser/Type/PdfName.php',
'setasign\\Fpdi\\PdfParser\\Type\\PdfNull' => __DIR__ . '/..' . '/setasign/fpdi/src/PdfParser/Type/PdfNull.php',
'setasign\\Fpdi\\PdfParser\\Type\\PdfNumeric' => __DIR__ . '/..' . '/setasign/fpdi/src/PdfParser/Type/PdfNumeric.php',
'setasign\\Fpdi\\PdfParser\\Type\\PdfStream' => __DIR__ . '/..' . '/setasign/fpdi/src/PdfParser/Type/PdfStream.php',
'setasign\\Fpdi\\PdfParser\\Type\\PdfString' => __DIR__ . '/..' . '/setasign/fpdi/src/PdfParser/Type/PdfString.php',
'setasign\\Fpdi\\PdfParser\\Type\\PdfToken' => __DIR__ . '/..' . '/setasign/fpdi/src/PdfParser/Type/PdfToken.php',
'setasign\\Fpdi\\PdfParser\\Type\\PdfType' => __DIR__ . '/..' . '/setasign/fpdi/src/PdfParser/Type/PdfType.php',
'setasign\\Fpdi\\PdfParser\\Type\\PdfTypeException' => __DIR__ . '/..' . '/setasign/fpdi/src/PdfParser/Type/PdfTypeException.php',
'setasign\\Fpdi\\PdfReader\\DataStructure\\Rectangle' => __DIR__ . '/..' . '/setasign/fpdi/src/PdfReader/DataStructure/Rectangle.php',
'setasign\\Fpdi\\PdfReader\\Page' => __DIR__ . '/..' . '/setasign/fpdi/src/PdfReader/Page.php',
'setasign\\Fpdi\\PdfReader\\PageBoundaries' => __DIR__ . '/..' . '/setasign/fpdi/src/PdfReader/PageBoundaries.php',
'setasign\\Fpdi\\PdfReader\\PdfReader' => __DIR__ . '/..' . '/setasign/fpdi/src/PdfReader/PdfReader.php',
'setasign\\Fpdi\\PdfReader\\PdfReaderException' => __DIR__ . '/..' . '/setasign/fpdi/src/PdfReader/PdfReaderException.php',
'setasign\\Fpdi\\TcpdfFpdi' => __DIR__ . '/..' . '/setasign/fpdi/src/TcpdfFpdi.php',
'setasign\\Fpdi\\Tcpdf\\Fpdi' => __DIR__ . '/..' . '/setasign/fpdi/src/Tcpdf/Fpdi.php',
'setasign\\Fpdi\\Tfpdf\\FpdfTpl' => __DIR__ . '/..' . '/setasign/fpdi/src/Tfpdf/FpdfTpl.php',
'setasign\\Fpdi\\Tfpdf\\Fpdi' => __DIR__ . '/..' . '/setasign/fpdi/src/Tfpdf/Fpdi.php',
);
public static function getInitializer(ClassLoader $loader)

View File

@@ -84,23 +84,23 @@
},
{
"name": "maennchen/zipstream-php",
"version": "3.1.2",
"version_normalized": "3.1.2.0",
"version": "3.2.0",
"version_normalized": "3.2.0.0",
"source": {
"type": "git",
"url": "https://github.com/maennchen/ZipStream-PHP.git",
"reference": "aeadcf5c412332eb426c0f9b4485f6accba2a99f"
"reference": "9712d8fa4cdf9240380b01eb4be55ad8dcf71416"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/maennchen/ZipStream-PHP/zipball/aeadcf5c412332eb426c0f9b4485f6accba2a99f",
"reference": "aeadcf5c412332eb426c0f9b4485f6accba2a99f",
"url": "https://api.github.com/repos/maennchen/ZipStream-PHP/zipball/9712d8fa4cdf9240380b01eb4be55ad8dcf71416",
"reference": "9712d8fa4cdf9240380b01eb4be55ad8dcf71416",
"shasum": ""
},
"require": {
"ext-mbstring": "*",
"ext-zlib": "*",
"php-64bit": "^8.2"
"php-64bit": "^8.3"
},
"require-dev": {
"brianium/paratest": "^7.7",
@@ -109,14 +109,14 @@
"guzzlehttp/guzzle": "^7.5",
"mikey179/vfsstream": "^1.6",
"php-coveralls/php-coveralls": "^2.5",
"phpunit/phpunit": "^11.0",
"phpunit/phpunit": "^12.0",
"vimeo/psalm": "^6.0"
},
"suggest": {
"guzzlehttp/psr7": "^2.4",
"psr/http-message": "^2.0"
},
"time": "2025-01-27T12:07:53+00:00",
"time": "2025-07-17T11:15:13+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
@@ -153,7 +153,7 @@
],
"support": {
"issues": "https://github.com/maennchen/ZipStream-PHP/issues",
"source": "https://github.com/maennchen/ZipStream-PHP/tree/3.1.2"
"source": "https://github.com/maennchen/ZipStream-PHP/tree/3.2.0"
},
"funding": [
{
@@ -278,17 +278,17 @@
},
{
"name": "phpmailer/phpmailer",
"version": "v6.10.0",
"version_normalized": "6.10.0.0",
"version": "v6.11.1",
"version_normalized": "6.11.1.0",
"source": {
"type": "git",
"url": "https://github.com/PHPMailer/PHPMailer.git",
"reference": "bf74d75a1fde6beaa34a0ddae2ec5fce0f72a144"
"reference": "d9e3b36b47f04b497a0164c5a20f92acb4593284"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/bf74d75a1fde6beaa34a0ddae2ec5fce0f72a144",
"reference": "bf74d75a1fde6beaa34a0ddae2ec5fce0f72a144",
"url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/d9e3b36b47f04b497a0164c5a20f92acb4593284",
"reference": "d9e3b36b47f04b497a0164c5a20f92acb4593284",
"shasum": ""
},
"require": {
@@ -309,6 +309,7 @@
},
"suggest": {
"decomplexity/SendOauth2": "Adapter for using XOAUTH2 authentication",
"ext-imap": "Needed to support advanced email address parsing according to RFC822",
"ext-mbstring": "Needed to send email in multibyte encoding charset or decode encoded addresses",
"ext-openssl": "Needed for secure SMTP sending and DKIM signing",
"greew/oauth2-azure-provider": "Needed for Microsoft Azure XOAUTH2 authentication",
@@ -318,7 +319,7 @@
"symfony/polyfill-mbstring": "To support UTF-8 if the Mbstring PHP extension is not enabled (^1.2)",
"thenetworg/oauth2-azure": "Needed for Microsoft XOAUTH2 authentication"
},
"time": "2025-04-24T15:19:31+00:00",
"time": "2025-09-30T11:54:53+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
@@ -350,7 +351,7 @@
"description": "PHPMailer is a full-featured email creation and transfer class for PHP",
"support": {
"issues": "https://github.com/PHPMailer/PHPMailer/issues",
"source": "https://github.com/PHPMailer/PHPMailer/tree/v6.10.0"
"source": "https://github.com/PHPMailer/PHPMailer/tree/v6.11.1"
},
"funding": [
{
@@ -362,21 +363,21 @@
},
{
"name": "phpoffice/phpspreadsheet",
"version": "2.3.8",
"version_normalized": "2.3.8.0",
"version": "5.1.0",
"version_normalized": "5.1.0.0",
"source": {
"type": "git",
"url": "https://github.com/PHPOffice/PhpSpreadsheet.git",
"reference": "7a700683743bf1c4a21837c84b266916f1aa7d25"
"reference": "fd26e45a814e94ae2aad0df757d9d1739c4bf2e0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/PHPOffice/PhpSpreadsheet/zipball/7a700683743bf1c4a21837c84b266916f1aa7d25",
"reference": "7a700683743bf1c4a21837c84b266916f1aa7d25",
"url": "https://api.github.com/repos/PHPOffice/PhpSpreadsheet/zipball/fd26e45a814e94ae2aad0df757d9d1739c4bf2e0",
"reference": "fd26e45a814e94ae2aad0df757d9d1739c4bf2e0",
"shasum": ""
},
"require": {
"composer/pcre": "^1 || ^2 || ^3",
"composer/pcre": "^1||^2||^3",
"ext-ctype": "*",
"ext-dom": "*",
"ext-fileinfo": "*",
@@ -405,9 +406,10 @@
"mitoteam/jpgraph": "^10.3",
"mpdf/mpdf": "^8.1.1",
"phpcompatibility/php-compatibility": "^9.3",
"phpstan/phpstan": "^1.1",
"phpstan/phpstan-phpunit": "^1.0",
"phpunit/phpunit": "^9.6 || ^10.5",
"phpstan/phpstan": "^1.1 || ^2.0",
"phpstan/phpstan-deprecation-rules": "^1.0 || ^2.0",
"phpstan/phpstan-phpunit": "^1.0 || ^2.0",
"phpunit/phpunit": "^10.5",
"squizlabs/php_codesniffer": "^3.7",
"tecnickcom/tcpdf": "^6.5"
},
@@ -418,7 +420,7 @@
"mpdf/mpdf": "Option for rendering PDF with PDF Writer",
"tecnickcom/tcpdf": "Option for rendering PDF with PDF Writer"
},
"time": "2025-02-08T03:01:45+00:00",
"time": "2025-09-04T05:34:49+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
@@ -464,7 +466,7 @@
],
"support": {
"issues": "https://github.com/PHPOffice/PhpSpreadsheet/issues",
"source": "https://github.com/PHPOffice/PhpSpreadsheet/tree/2.3.8"
"source": "https://github.com/PHPOffice/PhpSpreadsheet/tree/5.1.0"
},
"install-path": "../phpoffice/phpspreadsheet"
},
@@ -740,6 +742,81 @@
},
"install-path": "../setasign/fpdf"
},
{
"name": "setasign/fpdi",
"version": "v2.6.4",
"version_normalized": "2.6.4.0",
"source": {
"type": "git",
"url": "https://github.com/Setasign/FPDI.git",
"reference": "4b53852fde2734ec6a07e458a085db627c60eada"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Setasign/FPDI/zipball/4b53852fde2734ec6a07e458a085db627c60eada",
"reference": "4b53852fde2734ec6a07e458a085db627c60eada",
"shasum": ""
},
"require": {
"ext-zlib": "*",
"php": "^7.1 || ^8.0"
},
"conflict": {
"setasign/tfpdf": "<1.31"
},
"require-dev": {
"phpunit/phpunit": "^7",
"setasign/fpdf": "~1.8.6",
"setasign/tfpdf": "~1.33",
"squizlabs/php_codesniffer": "^3.5",
"tecnickcom/tcpdf": "^6.8"
},
"suggest": {
"setasign/fpdf": "FPDI will extend this class but as it is also possible to use TCPDF or tFPDF as an alternative. There's no fixed dependency configured."
},
"time": "2025-08-05T09:57:14+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
"psr-4": {
"setasign\\Fpdi\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Jan Slabon",
"email": "jan.slabon@setasign.com",
"homepage": "https://www.setasign.com"
},
{
"name": "Maximilian Kresse",
"email": "maximilian.kresse@setasign.com",
"homepage": "https://www.setasign.com"
}
],
"description": "FPDI is a collection of PHP classes facilitating developers to read pages from existing PDF documents and use them as templates in FPDF. Because it is also possible to use FPDI with TCPDF, there are no fixed dependencies defined. Please see suggestions for packages which evaluates the dependencies automatically.",
"homepage": "https://www.setasign.com/fpdi",
"keywords": [
"fpdf",
"fpdi",
"pdf"
],
"support": {
"issues": "https://github.com/Setasign/FPDI/issues",
"source": "https://github.com/Setasign/FPDI/tree/v2.6.4"
},
"funding": [
{
"url": "https://tidelift.com/funding/github/packagist/setasign/fpdi",
"type": "tidelift"
}
],
"install-path": "../setasign/fpdi"
},
{
"name": "stripe/stripe-php",
"version": "v17.6.0",

View File

@@ -3,7 +3,7 @@
'name' => 'your-vendor/api',
'pretty_version' => 'dev-main',
'version' => 'dev-main',
'reference' => 'f597c9aeb504adc2d733e5e2bd70820b06049df9',
'reference' => '2b3d05c981bd6fa1e80c3459d8648bc65bea72e2',
'type' => 'project',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
@@ -20,9 +20,9 @@
'dev_requirement' => false,
),
'maennchen/zipstream-php' => array(
'pretty_version' => '3.1.2',
'version' => '3.1.2.0',
'reference' => 'aeadcf5c412332eb426c0f9b4485f6accba2a99f',
'pretty_version' => '3.2.0',
'version' => '3.2.0.0',
'reference' => '9712d8fa4cdf9240380b01eb4be55ad8dcf71416',
'type' => 'library',
'install_path' => __DIR__ . '/../maennchen/zipstream-php',
'aliases' => array(),
@@ -47,18 +47,18 @@
'dev_requirement' => false,
),
'phpmailer/phpmailer' => array(
'pretty_version' => 'v6.10.0',
'version' => '6.10.0.0',
'reference' => 'bf74d75a1fde6beaa34a0ddae2ec5fce0f72a144',
'pretty_version' => 'v6.11.1',
'version' => '6.11.1.0',
'reference' => 'd9e3b36b47f04b497a0164c5a20f92acb4593284',
'type' => 'library',
'install_path' => __DIR__ . '/../phpmailer/phpmailer',
'aliases' => array(),
'dev_requirement' => false,
),
'phpoffice/phpspreadsheet' => array(
'pretty_version' => '2.3.8',
'version' => '2.3.8.0',
'reference' => '7a700683743bf1c4a21837c84b266916f1aa7d25',
'pretty_version' => '5.1.0',
'version' => '5.1.0.0',
'reference' => 'fd26e45a814e94ae2aad0df757d9d1739c4bf2e0',
'type' => 'library',
'install_path' => __DIR__ . '/../phpoffice/phpspreadsheet',
'aliases' => array(),
@@ -109,6 +109,15 @@
'aliases' => array(),
'dev_requirement' => false,
),
'setasign/fpdi' => array(
'pretty_version' => 'v2.6.4',
'version' => '2.6.4.0',
'reference' => '4b53852fde2734ec6a07e458a085db627c60eada',
'type' => 'library',
'install_path' => __DIR__ . '/../setasign/fpdi',
'aliases' => array(),
'dev_requirement' => false,
),
'stripe/stripe-php' => array(
'pretty_version' => 'v17.6.0',
'version' => '17.6.0.0',
@@ -121,7 +130,7 @@
'your-vendor/api' => array(
'pretty_version' => 'dev-main',
'version' => 'dev-main',
'reference' => 'f597c9aeb504adc2d733e5e2bd70820b06049df9',
'reference' => '2b3d05c981bd6fa1e80c3459d8648bc65bea72e2',
'type' => 'project',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),

View File

@@ -1,6 +0,0 @@
.gitignore text eol=lf
.gitattributes text eol=lf
*.md text eol=lf
*.php text eol=lf
*.yml text eol=lf
*.xml text eol=lf

View File

@@ -1,132 +0,0 @@
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, caste, color, religion, or sexual
identity and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
- Demonstrating empathy and kindness toward other people
- Being respectful of differing opinions, viewpoints, and experiences
- Giving and gracefully accepting constructive feedback
- Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
- Focusing on what is best not just for us as individuals, but for the overall
community
Examples of unacceptable behavior include:
- The use of sexualized language or imagery, and sexual attention or advances of
any kind
- Trolling, insulting or derogatory comments, and personal or political attacks
- Public or private harassment
- Publishing others' private information, such as a physical or email address,
without their explicit permission
- Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
jonatan@maennchen.ch.
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series of
actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or permanent
ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within the
community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.1, available at
[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
Community Impact Guidelines were inspired by
[Mozilla's code of conduct enforcement ladder][mozilla coc].
For answers to common questions about this code of conduct, see the FAQ at
[https://www.contributor-covenant.org/faq][faq]. Translations are available at
[https://www.contributor-covenant.org/translations][translations].
[homepage]: https://www.contributor-covenant.org
[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
[mozilla coc]: https://github.com/mozilla/diversity
[faq]: https://www.contributor-covenant.org/faq
[translations]: https://www.contributor-covenant.org/translations

View File

@@ -1,139 +0,0 @@
# Contributing to ZipStream-PHP
## Welcome!
We look forward to your contributions! Here are some examples how you can
contribute:
- [Report a bug](https://github.com/maennchen/ZipStream-PHP/issues/new?labels=bug&template=BUG.md)
- [Propose a new feature](https://github.com/maennchen/ZipStream-PHP/issues/new?labels=enhancement&template=FEATURE.md)
- [Send a pull request](https://github.com/maennchen/ZipStream-PHP/pulls)
## We have a Code of Conduct
Please note that this project is released with a
[Contributor Code of Conduct](CODE_OF_CONDUCT.md). By participating in this
project you agree to abide by its terms.
## Any contributions you make will be under the MIT License
When you submit code changes, your submissions are understood to be under the
same [MIT License](https://github.com/maennchen/ZipStream-PHP/blob/main/LICENSE)
that covers the project. By contributing to this project, you agree that your
contributions will be licensed under its MIT License.
## Write bug reports with detail, background, and sample code
In your bug report, please provide the following:
- A quick summary and/or background
- Steps to reproduce
- Be specific!
- Give sample code if you can.
- What you expected would happen
- What actually happens
- Notes (possibly including why you think this might be happening, or stuff you
- tried that didn't work)
Please do not report a bug for a version of ZIPStream-PHP that is no longer
supported (`< 3.0.0`). Please do not report a bug if you are using a version of
PHP that is not supported by the version of ZipStream-PHP you are using.
Please post code and output as text
([using proper markup](https://guides.github.com/features/mastering-markdown/)).
Do not post screenshots of code or output.
Please include the output of `composer info | sort`.
## Workflow for Pull Requests
1. Fork the repository.
2. Create your branch from `main` if you plan to implement new functionality or
change existing code significantly; create your branch from the oldest branch
that is affected by the bug if you plan to fix a bug.
3. Implement your change and add tests for it.
4. Ensure the test suite passes.
5. Ensure the code complies with our coding guidelines (see below).
6. Send that pull request!
Please make sure you have
[set up your user name and email address](https://git-scm.com/book/en/v2/Getting-Started-First-Time-Git-Setup)
for use with Git. Strings such as `silly nick name <root@localhost>` look really
stupid in the commit history of a project.
We encourage you to
[sign your Git commits with your GPG key](https://docs.github.com/en/github/authenticating-to-github/signing-commits).
Pull requests for new features must be based on the `main` branch.
We are trying to keep backwards compatibility breaks in ZipStream-PHP to a
minimum. Please take this into account when proposing changes.
Due to time constraints, we are not always able to respond as quickly as we
would like. Please do not take delays personal and feel free to remind us if you
feel that we forgot to respond.
## Coding Guidelines
This project comes with a configuration file (located at `/psalm.yml` in the
repository) that you can use to perform static analysis (with a focus on type
checking):
```bash
$ .composer run test:lint
```
This project comes with a configuration file (located at
`/.php-cs-fixer.dist.php` in the repository) that you can use to (re)format your
source code for compliance with this project's coding guidelines:
```bash
$ composer run format
```
Please understand that we will not accept a pull request when its changes
violate this project's coding guidelines.
## Using ZipStream-PHP from a Git checkout
The following commands can be used to perform the initial checkout of
ZipStream-PHP:
```bash
$ git clone git@github.com:maennchen/ZipStream-PHP.git
$ cd ZipStream-PHP
```
Install ZipStream-PHP's dependencies using [Composer](https://getcomposer.org/):
```bash
$ composer install
$ composer run install:tools # Install phpDocumentor using phive
```
## Running ZipStream-PHP's test suite
After following the steps shown above, ZipStream-PHP's test suite is run like
this:
```bash
$ composer run test:unit
```
There's some slow tests in the test suite that test the handling of big files in
the archives. To skip them use the following command instead:
```bash
$ composer run test:unit:fast
```
## Generating ZipStream-PHP Documentation
To generate the documentation for the library, run:
```bash
$ composer run docs:generate
```
The guide documentation pages can be found in the `/guides/` directory.

View File

@@ -1 +0,0 @@
github: maennchen

View File

@@ -1,71 +0,0 @@
name: 🐞 Bug Report
description: Something is broken?
labels: ["bug"]
body:
- type: markdown
attributes:
value: |
- Create a discussion instead if you are looking for support:
https://github.com/maennchen/ZipStream-PHP/discussions
- type: input
id: version
attributes:
label: ZipStream-PHP version
placeholder: x.y.z
validations:
required: true
- type: input
id: php-version
attributes:
label: PHP version
placeholder: x.y.z
validations:
required: true
- type: checkboxes
id: constraints
attributes:
label: Constraints for Bug Report
options:
- label: |
I'm using a version of ZipStream that is currently supported:
https://github.com/maennchen/ZipStream-PHP#version-support
required: true
- label: |
I'm using a version of PHP that has active support:
https://www.php.net/supported-versions.php
required: true
- label: |
I'm using a version of PHP that is compatible with your used
ZipStream version.
required: true
- label: |
I'm using the latest release of the used ZipStream major version.
required: true
- type: textarea
id: summary
attributes:
label: Summary
description: Provide a summary describing the problem you are experiencing.
validations:
required: true
- type: textarea
id: current-behaviour
attributes:
label: Current behavior
description: What is the current (buggy) behavior?
validations:
required: true
- type: textarea
id: reproduction
attributes:
label: How to reproduce
description: Provide steps to reproduce the bug.
validations:
required: true
- type: textarea
id: expected-behaviour
attributes:
label: Expected behavior
description: What was the expected (correct) behavior?
validations:
required: true

View File

@@ -1,11 +0,0 @@
name: 🎉 Feature Request
description: You have a neat idea that should be implemented?
labels: ["enhancement"]
body:
- type: textarea
id: description
attributes:
label: Description
description: Provide a summary of the feature you would like to see implemented.
validations:
required: true

View File

@@ -1,6 +0,0 @@
Please go the the `Preview` tab and select the appropriate sub-template:
* [🐞 Failing Test](?expand=1&template=FAILING_TEST.md)
* [🐞 Bug Fix](?expand=1&template=FIX.md)
* [⚙ Improvement](?expand=1&template=IMPROVEMENT.md)
* [🎉 New Feature](?expand=1&template=NEW_FEATURE.md)

View File

@@ -1,13 +0,0 @@
<!---
name: 🐞 Failing Test
about: You found a bug and have a failing test?
labels: bug, tests
--->
<!--
- Please do not send a pull request for an issue in a version of ZipStream-PHP
that is no longer supported.
See: https://github.com/maennchen/ZipStream-PHP#version-support
- Please target the oldest branch of ZipStream-PHP that is still supported and
where the test fails.
-->

View File

@@ -1,13 +0,0 @@
<!---
name: 🐞 Bug Fix
about: You have a fix for a bug?
labels: bug
--->
<!--
- Please do not send a pull request for an issue in a version of ZipStream-PHP
that is no longer supported.
See: https://github.com/maennchen/ZipStream-PHP#version-support
- Please target the oldest branch of ZipStream-PHP that is still supported and
affected by this bug.
-->

View File

@@ -1,9 +0,0 @@
<!---
name: ⚙ Improvement
about: You have some improvement to make ZipStream-PHP better?
labels: enhancement
--->
<!--
- Please target the `main` branch of ZipStream-PHP.
-->

View File

@@ -1,9 +0,0 @@
<!---
name: 🎉 New Feature
about: You have implemented some neat idea that you want to make part of ZipStream-PHP?
labels: type/enhancement
--->
<!--
- Please target the `main` branch of ZipStream-PHP.
-->

View File

@@ -1,22 +0,0 @@
# Security Policy
[![OpenSSF Vulnerability Disclosure](https://img.shields.io/badge/OpenSSF-Vulnerability_Disclosure-green)](https://github.com/ossf/oss-vulnerability-guide/blob/main/finder-guide.md)
[![GitHub Report](https://img.shields.io/badge/GitHub-Security_Advisories-blue)](https://github.com/maennchen/ZipStream-PHP/security/advisories/new)
[![Email Report](https://img.shields.io/badge/Email-jonatan%40maennchen.ch-blue)](mailto:jonatan@maennchen.ch)
This repository follows the
[OpenSSF Vulnerability Disclosure guide](https://github.com/ossf/oss-vulnerability-guide/tree/main).
You can learn more about it in the
[Finders Guide](https://github.com/ossf/oss-vulnerability-guide/blob/main/finder-guide.md).
Please report vulnerabilities via the
[GitHub Security Vulnerability Reporting](https://github.com/maennchen/ZipStream-PHP/security/advisories/new)
or via email to [`jonatan@maennchen.ch`](mailto:jonatan@maennchen.ch) if this does
not work for you.
Our vulnerability management team will respond within 3 working days of your
report. If the issue is confirmed as a vulnerability, we will open a Security
Advisory. This project follows a 90 day disclosure timeline.
If you have questions about reporting security issues, email the vulnerability
management team: [`jonatan@maennchen.ch`](mailto:jonatan@maennchen.ch)

View File

@@ -1,15 +0,0 @@
version: 2
updates:
- package-ecosystem: "composer"
directory: "/"
schedule:
interval: "daily"
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
groups:
github-actions:
applies-to: version-updates
patterns:
- "*"

View File

@@ -1,14 +0,0 @@
annotations:
- checks:
- fuzzing
reasons:
- reason: not-applicable # PHP is memory safe
- checks:
- packaging
reasons:
- reason: not-supported # Using Composer
- checks:
- signed-releases
reasons:
- reason: not-applicable # Releases are distributed via Composer

View File

@@ -1,24 +0,0 @@
on:
push:
branches:
- "main"
name: "Main Branch"
permissions:
contents: read
jobs:
test:
name: "Test"
permissions:
contents: read
security-events: write
uses: ./.github/workflows/part_test.yml
docs:
name: "Docs"
uses: ./.github/workflows/part_docs.yml

View File

@@ -1,30 +0,0 @@
on:
workflow_call: {}
name: "Dependabot"
permissions:
contents: read
jobs:
automerge_dependabot:
name: "Automerge PRs"
runs-on: ubuntu-latest
permissions:
pull-requests: write
contents: write
steps:
- name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
with:
egress-policy: audit
- uses: fastify/github-action-merge-dependabot@c3bde0759d4f24db16f7b250b2122bc2df57e817 # v3.11.0
with:
github-token: ${{ github.token }}
use-github-auto-merge: true
# Major Updates need to be merged manually
target: minor

View File

@@ -1,51 +0,0 @@
on:
workflow_call: {}
name: "Documentation"
permissions:
contents: read
jobs:
generate:
name: "Generate"
runs-on: ubuntu-latest
steps:
- name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
with:
egress-policy: audit
- name: Checkout Code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: SetUp PHP
id: setup-php
uses: shivammathur/setup-php@9e72090525849c5e82e596468b86eb55e9cc5401 # v2
with:
php-version: "8.3"
tools: phive
- name: Cache Tools
uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0
id: cache
with:
path: ~/.phive
key: tools-${{ runner.os }}-${{ steps.setup-php.outputs.php-version }}-${{ hashFiles('**/phars.xml') }}
restore-keys: |
tools-${{ runner.os }}-${{ steps.setup-php.outputs.php-version }}-
tools-${{ steps.setup-php.outputs.php-version }}-
tools-
- name: Install Tools
run: composer run install:tools
- name: Generate Docs
run: composer run docs:generate
- uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
with:
name: docs
path: docs
- name: Package for GitHub Pages
uses: actions/upload-pages-artifact@56afc609e74202658d3ffba0e8f6dda462b719fa # v3.0.1
with:
path: docs

View File

@@ -1,94 +0,0 @@
on:
workflow_call:
inputs:
releaseName:
required: true
type: string
stable:
required: false
type: boolean
default: false
name: "Release"
permissions:
contents: read
jobs:
create:
name: Create Release
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
with:
egress-policy: audit
- name: Create prerelease
if: ${{ !inputs.stable }}
env:
GITHUB_TOKEN: ${{ github.token }}
run: |
gh release create \
--repo ${{ github.repository }} \
--title ${{ inputs.releaseName }} \
--prerelease \
--generate-notes \
${{ inputs.releaseName }}
- name: Create release
if: ${{ inputs.stable }}
env:
GITHUB_TOKEN: ${{ github.token }}
run: |
gh release create \
--repo ${{ github.repository }} \
--title ${{ inputs.releaseName }} \
--generate-notes \
${{ inputs.releaseName }}
upload_release:
name: "Upload"
needs: ["create"]
runs-on: ubuntu-latest
permissions:
id-token: write
contents: write
attestations: write
steps:
- name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
with:
egress-policy: audit
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
with:
name: docs
path: docs
- run: |
tar -czvf docs.tar.gz docs
- name: "Attest Documentation"
id: attestation
uses: actions/attest-build-provenance@520d128f165991a6c774bcb264f323e3d70747f4 # v2.2.0
with:
subject-path: "docs.tar.gz"
- name: Copy Attestation
run: cp "$ATTESTATION" docs.tar.gz.sigstore
env:
ATTESTATION: "${{ steps.attestation.outputs.bundle-path }}"
- name: Upload
env:
GITHUB_TOKEN: ${{ github.token }}
run: |
gh release upload --clobber "${{ github.ref_name }}" \
docs.tar.gz docs.tar.gz.sigstore

View File

@@ -1,181 +0,0 @@
on:
workflow_call:
name: "Test"
permissions:
contents: read
jobs:
phpunit:
name: PHPUnit (PHP ${{ matrix.php }} on ${{ matrix.os }})
runs-on: ${{ matrix.os }}
continue-on-error: ${{ matrix.experimental }}
strategy:
fail-fast: false
matrix:
php: ["8.2", "8.3", "8.4"]
os: [ubuntu-latest]
experimental: [false]
include:
- php: nightly
os: ubuntu-latest
experimental: true
- php: "8.4"
os: windows-latest
experimental: false
- php: "8.4"
os: macos-latest
experimental: false
steps:
- name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
with:
egress-policy: audit
- name: Checkout Code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: SetUp PHP
id: setup-php
uses: shivammathur/setup-php@9e72090525849c5e82e596468b86eb55e9cc5401 # v2
with:
php-version: "${{ matrix.php }}"
tools: phpunit
coverage: xdebug
extensions: xdebug,zip
- name: Get composer cache directory
id: composer-cache-common
if: "${{ runner.os != 'Windows' }}"
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
- name: Get composer cache directory
id: composer-cache-windows
if: "${{ runner.os == 'Windows' }}"
run: echo "dir=$(composer config cache-files-dir)" >> $env:GITHUB_OUTPUT
- name: Cache Deps
uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0
id: cache
with:
path: ${{ steps.composer-cache-common.outputs.dir }}${{ steps.composer-cache-windows.outputs.dir }}
key: deps-${{ runner.os }}-${{ steps.setup-php.outputs.php-version }}-composer-${{ hashFiles('**/composer.lock') }}
restore-keys: |
deps-${{ runner.os }}-${{ steps.setup-php.outputs.php-version }}-composer-
deps-${{ runner.os }}-${{ steps.setup-php.outputs.php-version }}-
deps-${{ steps.setup-php.outputs.php-version }}-
deps-
- name: Install Deps
if: matrix.php != 'nightly'
run: composer install --prefer-dist
- name: Install Deps (ignore PHP requirement)
if: matrix.php == 'nightly'
run: composer install --prefer-dist --ignore-platform-req=php+
- name: Run PHPUnit
run: composer run test:unit:cov
- name: Upload coverage results to Coveralls
env:
COVERALLS_REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }}
COVERALLS_PARALLEL: true
COVERALLS_FLAG_NAME: ${{ runner.os }}-${{ steps.setup-php.outputs.php-version }}
run: composer run coverage:report
continue-on-error: ${{ matrix.experimental }}
mark_coverage_done:
needs: ["phpunit"]
runs-on: ubuntu-latest
steps:
- name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
with:
egress-policy: audit
- name: Coveralls Finished
uses: coverallsapp/github-action@648a8eb78e6d50909eff900e4ec85cab4524a45b # v2.3.6
with:
github-token: ${{ secrets.github_token }}
parallel-finished: true
psalm:
name: Run Psalm
runs-on: "ubuntu-latest"
permissions:
security-events: write
steps:
- name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
with:
egress-policy: audit
- name: Checkout Code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: SetUp PHP
id: setup-php
uses: shivammathur/setup-php@9e72090525849c5e82e596468b86eb55e9cc5401 # v2
with:
php-version: "8.3"
- name: Get composer cache directory
id: composer-cache
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
- name: Cache Deps
uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0
id: cache
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: deps-${{ runner.os }}-${{ steps.setup-php.outputs.php-version }}-composer-${{ hashFiles('**/composer.lock') }}
restore-keys: |
deps-${{ runner.os }}-${{ steps.setup-php.outputs.php-version }}-composer-
deps-${{ runner.os }}-${{ steps.setup-php.outputs.php-version }}-
deps-${{ steps.setup-php.outputs.php-version }}-
deps-
- name: Install Deps
run: composer install --prefer-dist
- name: Run Psalm
run: composer run test:lint -- --report=results.sarif
- name: "Upload SARIF"
uses: github/codeql-action/upload-sarif@f6091c0113d1dcf9b98e269ee48e8a7e51b7bdd4 # v3
with:
sarif_file: results.sarif
php-cs:
name: Run PHP-CS
runs-on: "ubuntu-latest"
steps:
- name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
with:
egress-policy: audit
- name: Checkout Code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: SetUp PHP
id: setup-php
uses: shivammathur/setup-php@9e72090525849c5e82e596468b86eb55e9cc5401 # v2
with:
php-version: "8.3"
- name: Get composer cache directory
id: composer-cache
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
- name: Cache Deps
uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0
id: cache
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: deps-${{ runner.os }}-${{ steps.setup-php.outputs.php-version }}-composer-${{ hashFiles('**/composer.lock') }}
restore-keys: |
deps-${{ runner.os }}-${{ steps.setup-php.outputs.php-version }}-composer-
deps-${{ runner.os }}-${{ steps.setup-php.outputs.php-version }}-
deps-${{ steps.setup-php.outputs.php-version }}-
deps-
- name: Install Deps
run: composer install --prefer-dist
- name: Run PHP-CS
run: composer run test:formatted

View File

@@ -1,50 +0,0 @@
on:
pull_request:
branches:
- "*"
workflow_dispatch: {}
name: "Pull Request"
permissions:
contents: read
jobs:
test:
name: "Test"
permissions:
contents: read
security-events: write
uses: ./.github/workflows/part_test.yml
docs:
name: "Docs"
uses: ./.github/workflows/part_docs.yml
dependabot:
name: "Dependabot"
if: ${{ github.actor == 'dependabot[bot]'}}
permissions:
pull-requests: write
contents: write
uses: ./.github/workflows/part_dependabot.yml
dependency-review:
name: Dependency Review
runs-on: ubuntu-latest
steps:
- name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
with:
egress-policy: audit
- name: 'Checkout Repository'
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: 'Dependency Review'
uses: actions/dependency-review-action@3b139cfc5fae8b618d3eae3675e383bb1769c019 # v4.5.0

View File

@@ -1,78 +0,0 @@
# This workflow uses actions that are not certified by GitHub. They are provided
# by a third-party and are governed by separate terms of service, privacy
# policy, and support documentation.
name: Scorecard supply-chain security
on:
# For Branch-Protection check. Only the default branch is supported. See
# https://github.com/ossf/scorecard/blob/main/docs/checks.md#branch-protection
branch_protection_rule:
# To guarantee Maintained check is occasionally updated. See
# https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained
schedule:
- cron: '28 11 * * 3'
push:
branches: [ "main" ]
# Declare default permissions as read only.
permissions: read-all
jobs:
analysis:
name: Scorecard analysis
runs-on: ubuntu-latest
permissions:
# Needed to upload the results to code-scanning dashboard.
security-events: write
# Needed to publish results and get a badge (see publish_results below).
id-token: write
# Uncomment the permissions below if installing in a private repository.
# contents: read
# actions: read
steps:
- name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
with:
egress-policy: audit
- name: "Checkout code"
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
persist-credentials: false
- name: "Run analysis"
uses: ossf/scorecard-action@62b2cac7ed8198b15735ed49ab1e5cf35480ba46 # v2.4.0
with:
results_file: results.sarif
results_format: sarif
# (Optional) "write" PAT token. Uncomment the `repo_token` line below if:
# - you want to enable the Branch-Protection check on a *public* repository, or
# - you are installing Scorecard on a *private* repository
# To create the PAT, follow the steps in https://github.com/ossf/scorecard-action?tab=readme-ov-file#authentication-with-fine-grained-pat-optional.
# repo_token: ${{ secrets.SCORECARD_TOKEN }}
# Public repositories:
# - Publish results to OpenSSF REST API for easy access by consumers
# - Allows the repository to include the Scorecard badge.
# - See https://github.com/ossf/scorecard-action#publishing-results.
# For private repositories:
# - `publish_results` will always be set to `false`, regardless
# of the value entered here.
publish_results: true
# Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
# format to the repository Actions tab.
- name: "Upload artifact"
uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
with:
name: SARIF file
path: results.sarif
retention-days: 5
# Upload the results to GitHub's code scanning dashboard (optional).
# Commenting out will disable upload of results to your repo's Code Scanning dashboard
- name: "Upload to code-scanning"
uses: github/codeql-action/upload-sarif@f6091c0113d1dcf9b98e269ee48e8a7e51b7bdd4 # v3.28.5
with:
sarif_file: results.sarif

View File

@@ -1,29 +0,0 @@
on:
push:
tags:
- "[0-9]+.[0-9]+.[0-9]+-beta.[0-9]+"
name: "Beta Tag"
permissions:
contents: read
jobs:
docs:
name: "Docs"
uses: ./.github/workflows/part_docs.yml
release:
name: "Release"
needs: ["docs"]
permissions:
id-token: write
contents: write
attestations: write
uses: ./.github/workflows/part_release.yml
with:
releaseName: "${{ github.ref_name }}"

View File

@@ -1,55 +0,0 @@
on:
push:
tags:
- "[0-9]+.[0-9]+.[0-9]+"
name: "Stable Tag"
permissions:
contents: read
jobs:
docs:
name: "Docs"
uses: ./.github/workflows/part_docs.yml
release:
name: "Release"
needs: ["docs"]
permissions:
id-token: write
contents: write
attestations: write
uses: ./.github/workflows/part_release.yml
with:
releaseName: "${{ github.ref_name }}"
stable: true
deploy_pages:
name: "Deploy to GitHub Pages"
needs: ["release", "docs"]
runs-on: ubuntu-latest
permissions:
pages: write
id-token: write
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
with:
egress-policy: audit
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e # v4.0.5

View File

@@ -1,12 +0,0 @@
/composer.lock
/cov
/coverage.clover.xml
/docs
.idea
/.php-cs-fixer.cache
/.phpdoc/cache
/.phpunit.result.cache
/phpunit.xml
/.phpunit.cache
/tools
/vendor

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<phive xmlns="https://phar.io/phive">
<phar name="phpdocumentor" version="^3.3.1" installed="3.6.0" location="./tools/phpdocumentor" copy="false"/>
<phar name="phpdocumentor" version="^3.3.1" installed="3.8.0" location="./tools/phpdocumentor" copy="false"/>
</phive>

View File

@@ -28,7 +28,8 @@ return $config->setRules([
'@PER' => true,
'@PER:risky' => true,
'@PHP83Migration' => true,
'@PHP84Migration' => true,
// Enable once PHP 8.4 is the minimum version
// '@PHP84Migration' => true,
'@PHPUnit84Migration:risky' => true,
'array_syntax' => ['syntax' => 'short'],
'class_attributes_separation' => true,

View File

@@ -1 +1 @@
php 8.4.3
php 8.4.10

View File

@@ -64,6 +64,50 @@ $zip->addFileFromPath(
$zip->finish();
```
### Callback Output
You can stream ZIP data to a custom callback function instead of directly to the browser:
```php
use ZipStream\ZipStream;
use ZipStream\Stream\CallbackStreamWrapper;
// Stream to a callback function with proper file handling
$outputFile = fopen('output.zip', 'wb');
$backupFile = fopen('backup.zip', 'wb');
$zip = new ZipStream(
outputStream: CallbackStreamWrapper::open(function (string $data) use ($outputFile, $backupFile) {
// Handle ZIP data as it's generated
fwrite($outputFile, $data);
// Send to multiple destinations efficiently
echo $data; // Browser
fwrite($backupFile, $data); // Backup file
}),
sendHttpHeaders: false,
);
$zip->addFile('hello.txt', 'Hello World!');
$zip->finish();
// Clean up resources
fclose($outputFile);
fclose($backupFile);
```
## Questions
**💬 Questions? Please Read This First!**
If you have a question about using this library, please *do not email the
authors directly*. Instead, head over to the
[GitHub Discussions](https://github.com/maennchen/ZipStream-PHP/discussions)
page — your question might already be answered there! Using Discussions helps
build a shared knowledge base, so others can also benefit from the answers. If
you need dedicated 1:1 support, check out the options available on
[@maennchen's sponsorship page](https://github.com/sponsors/maennchen?frequency=one-time&sponsor=maennchen).
## Upgrade to version 3.1.2
- Minimum PHP Version: `8.2`
@@ -76,7 +120,7 @@ $zip->finish();
- Only 64bit Architecture is supported.
- The class `ZipStream\Option\Method` has been replaced with the enum
`ZipStream\CompressionMethod`.
- Most clases have been flagged as `@internal` and should not be used from the
- Most classes have been flagged as `@internal` and should not be used from the
outside.
If you're using internal resources to extend this library, please open an
issue so that a clean interface can be added & published.
@@ -88,7 +132,7 @@ $zip->finish();
### Archive Options
- The class `ZipStream\Option\Archive` has been replaced in favor of named
arguments in the `ZipStream\ZipStream` constuctor.
arguments in the `ZipStream\ZipStream` constructor.
- The archive options `largeFileSize` & `largeFileMethod` has been removed. If
you want different `compressionMethods` based on the file size, you'll have to
implement this yourself.
@@ -101,7 +145,7 @@ $zip->finish();
filesizes this way.
- The archive option `deflateLevel` has been replaced with the option
`defaultDeflateLevel` and can be overridden for every file.
- The first argument (`name`) of the `ZipStream\ZipStream` constuctor has been
- The first argument (`name`) of the `ZipStream\ZipStream` constructor has been
replaced with the named argument `outputName`.
- Headers are now also sent if the `outputName` is empty. If you do not want to
automatically send http headers, set `sendHttpHeaders` to `false`.

View File

@@ -22,12 +22,12 @@
}
],
"require": {
"php-64bit": "^8.2",
"php-64bit": "^8.3",
"ext-mbstring": "*",
"ext-zlib": "*"
},
"require-dev": {
"phpunit/phpunit": "^11.0",
"phpunit/phpunit": "^12.0",
"guzzlehttp/guzzle": "^7.5",
"ext-zip": "*",
"mikey179/vfsstream": "^1.6",
@@ -57,7 +57,7 @@
"test:formatted": "@format --dry-run --stop-on-violation --using-cache=no",
"test:lint": "psalm --stats --show-info=true --find-unused-psalm-suppress",
"coverage:report": "php-coveralls --coverage_clover=coverage.clover.xml --json_path=coveralls-upload.json --insecure",
"install:tools": "phive install --trust-gpg-keys 0x67F861C3D889C656 --trust-gpg-keys 0x8AC0BAA79732DD42",
"install:tools": "phive install --trust-gpg-keys 0x67F861C3D889C656 --trust-gpg-keys 0x8AC0BAA79732DD42 --trust-gpg-keys 0x6DA3ACC4991FFAE5",
"docs:generate": "tools/phpdocumentor --sourcecode"
},
"autoload": {

View File

@@ -7,7 +7,7 @@ using the options ``SIMULATION_STRICT`` or ``SIMULATION_LAX`` in the
In the ``SIMULATION_STRICT`` mode, ``ZipStream`` will not allow to calculate the
size based on reading the whole file. ``SIMULATION_LAX`` will read the whole
file if neccessary.
file if necessary.
``SIMULATION_STRICT`` is therefore useful to make sure that the size can be
calculated efficiently.

View File

@@ -12,11 +12,14 @@ Here is the full list of options available to you. You can also have a look at
$zip = new ZipStream(
// Define output stream
// (argument is eiter a resource or implementing
// (argument is either a resource or implementing
// `Psr\Http\Message\StreamInterface`)
//
// Setup with `psr/http-message` & `guzzlehttp/psr7` dependencies
// required when using `Psr\Http\Message\StreamInterface`.
//
// Can also use CallbackStreamWrapper for custom output handling:
// outputStream: CallbackStreamWrapper::open(function($data) { /* handle data */ }),
outputStream: $filePointer,
// Set the deflate level (default is 6; use -1 to disable it)

View File

@@ -37,3 +37,77 @@ Stream to S3 Bucket
$zip->finish();
fclose($zipFile);
Stream to Callback Function
---------------------------
The CallbackStreamWrapper allows you to stream ZIP data to a custom callback function,
enabling flexible output handling such as streaming to multiple destinations,
progress tracking, or data transformation.
.. code-block:: php
use ZipStream\ZipStream;
use ZipStream\Stream\CallbackStreamWrapper;
// Example 1: Stream to multiple destinations with proper file handling
$backupFile = fopen('backup.zip', 'wb');
$logFile = fopen('transfer.log', 'ab');
$zip = new ZipStream(
outputStream: CallbackStreamWrapper::open(function (string $data) use ($backupFile, $logFile) {
// Send to browser
echo $data;
// Save to file efficiently
fwrite($backupFile, $data);
// Log transfer progress
fwrite($logFile, "Transferred " . strlen($data) . " bytes\n");
}),
sendHttpHeaders: false,
);
$zip->addFile('hello.txt', 'Hello World!');
$zip->finish();
// Clean up resources
fclose($backupFile);
fclose($logFile);
.. code-block:: php
// Example 2: Progress tracking
$totalBytes = 0;
$zip = new ZipStream(
outputStream: CallbackStreamWrapper::open(function (string $data) use (&$totalBytes) {
$totalBytes += strlen($data);
reportProgress($totalBytes); // Report progress to your tracking system
// Your actual output handling
echo $data;
}),
sendHttpHeaders: false,
);
$zip->addFile('large_file.txt', str_repeat('A', 10000));
$zip->finish();
.. code-block:: php
// Example 3: Data transformation using PHP stream filters
// For data transformations, prefer PHP's built-in stream filters
$outputStream = fopen('php://output', 'w');
stream_filter_append($outputStream, 'convert.base64-encode');
$zip = new ZipStream(
outputStream: $outputStream,
sendHttpHeaders: false,
);
$zip->addFile('secret.txt', 'Confidential data');
$zip->finish();
fclose($outputStream);
.. note::
For data transformations, PHP's built-in stream filters are preferred over callback transformations. Stream filters operate at the stream level and maintain data integrity. You can register custom filters using ``stream_filter_register()`` for specialized transformations.

View File

@@ -39,7 +39,7 @@ as well:
If ``composer install`` yields the following error, your installation is missing
the `mbstring extension <https://www.php.net/manual/en/book.mbstring.php>`_,
either `install it <https://www.php.net/manual/en/mbstring.installation.php>`_
or run the follwoing command:
or run the following command:
.. code-block::
Your requirements could not be resolved to an installable set of packages.
@@ -120,7 +120,7 @@ It is recommended to extract with another tool like
`7-zip <https://www.7-zip.org/>`_.
See `#146 <https://github.com/maennchen/ZipStream-PHP/issues/146>`_.
It is the responsability of the client code to make sure that files are not
It is the responsibility of the client code to make sure that files are not
saved with the same path, as it is not possible for the library to figure it out
while streaming a zip.
See `#154 <https://github.com/maennchen/ZipStream-PHP/issues/154>`_.

View File

@@ -4,6 +4,9 @@ declare(strict_types=1);
namespace ZipStream;
/**
* @api
*/
enum CompressionMethod: int
{
/**

View File

@@ -4,4 +4,7 @@ declare(strict_types=1);
namespace ZipStream;
/**
* @api
*/
abstract class Exception extends \Exception {}

View File

@@ -8,7 +8,9 @@ use DateTimeInterface;
use ZipStream\Exception;
/**
* This Exception gets invoked if a file wasn't found
* This Exception gets invoked if a DOS time is overflowing
*
* @api
*/
class DosTimeOverflowException extends Exception
{

View File

@@ -8,6 +8,8 @@ use ZipStream\Exception;
/**
* This Exception gets invoked if a file wasn't found
*
* @api
*/
class FileNotFoundException extends Exception
{

View File

@@ -7,7 +7,9 @@ namespace ZipStream\Exception;
use ZipStream\Exception;
/**
* This Exception gets invoked if a file wasn't found
* This Exception gets invoked if a file isn't readable
*
* @api
*/
class FileNotReadableException extends Exception
{

View File

@@ -8,6 +8,8 @@ use ZipStream\Exception;
/**
* This Exception gets invoked if a file is not as large as it was specified.
*
* @api
*/
class FileSizeIncorrectException extends Exception
{

View File

@@ -8,6 +8,8 @@ use ZipStream\Exception;
/**
* This Exception gets invoked if a counter value exceeds storage size
*
* @api
*/
class OverflowException extends Exception
{

View File

@@ -8,6 +8,8 @@ use ZipStream\Exception;
/**
* This Exception gets invoked if a resource like `fread` returns false
*
* @api
*/
class ResourceActionException extends Exception
{

View File

@@ -9,6 +9,8 @@ use ZipStream\Exception;
/**
* This Exception gets invoked if a strict simulation is executed and the file
* information can't be determined without reading the entire file.
*
* @api
*/
class SimulationFileUnknownException extends Exception
{

View File

@@ -8,6 +8,8 @@ use ZipStream\Exception;
/**
* This Exception gets invoked if a stream can't be read.
*
* @api
*/
class StreamNotReadableException extends Exception
{

View File

@@ -9,6 +9,8 @@ use ZipStream\Exception;
/**
* This Exception gets invoked if a non seekable stream is
* provided and zero headers are disabled.
*
* @api
*/
class StreamNotSeekableException extends Exception
{

View File

@@ -18,7 +18,7 @@ use ZipStream\Exception\StreamNotSeekableException;
/**
* @internal
*/
class File
final class File
{
private const CHUNKED_READ_BLOCK_SIZE = 0x1000000;

View File

@@ -6,6 +6,8 @@ namespace ZipStream;
/**
* ZipStream execution operation modes
*
* @api
*/
enum OperationMode
{

View File

@@ -10,7 +10,7 @@ use RuntimeException;
* @internal
* TODO: Make class readonly when requiring PHP 8.2 exclusively
*/
class PackField
final class PackField
{
public const MAX_V = 0xFFFFFFFF;

View File

@@ -4,6 +4,9 @@ declare(strict_types=1);
namespace ZipStream;
/**
* @api
*/
enum Version: int
{
case STORE = 0x000A; // 1.00

View File

@@ -64,6 +64,8 @@ use ZipStream\Exception\ResourceActionException;
* // write archive footer to stream
* $zip->finish();
* ```
*
* @api
*/
class ZipStream
{
@@ -691,7 +693,7 @@ class ZipStream
/**
* Write zip footer to stream.
*
* The clase is left in an unusable state after `finish`.
* The class is left in an unusable state after `finish`.
*
* ##### Example
*

View File

@@ -48,7 +48,7 @@ This software is distributed under the [LGPL 2.1](https://www.gnu.org/licenses/o
PHPMailer is available on [Packagist](https://packagist.org/packages/phpmailer/phpmailer) (using semantic versioning), and installation via [Composer](https://getcomposer.org) is the recommended way to install PHPMailer. Just add this line to your `composer.json` file:
```json
"phpmailer/phpmailer": "^6.10.0"
"phpmailer/phpmailer": "^6.11.1"
```
or run

View File

@@ -1 +1 @@
6.10.0
6.11.1

View File

@@ -49,14 +49,15 @@
},
"suggest": {
"decomplexity/SendOauth2": "Adapter for using XOAUTH2 authentication",
"ext-imap": "Needed to support advanced email address parsing according to RFC822",
"ext-mbstring": "Needed to send email in multibyte encoding charset or decode encoded addresses",
"ext-openssl": "Needed for secure SMTP sending and DKIM signing",
"greew/oauth2-azure-provider": "Needed for Microsoft Azure XOAUTH2 authentication",
"hayageek/oauth2-yahoo": "Needed for Yahoo XOAUTH2 authentication",
"league/oauth2-google": "Needed for Google XOAUTH2 authentication",
"psr/log": "For optional PSR-3 debug logging",
"thenetworg/oauth2-azure": "Needed for Microsoft XOAUTH2 authentication",
"symfony/polyfill-mbstring": "To support UTF-8 if the Mbstring PHP extension is not enabled (^1.2)"
"symfony/polyfill-mbstring": "To support UTF-8 if the Mbstring PHP extension is not enabled (^1.2)",
"thenetworg/oauth2-azure": "Needed for Microsoft XOAUTH2 authentication"
},
"autoload": {
"psr-4": {
@@ -71,6 +72,7 @@
"license": "LGPL-2.1-only",
"scripts": {
"check": "./vendor/bin/phpcs",
"style": "./vendor/bin/phpcbf",
"test": "./vendor/bin/phpunit --no-coverage",
"coverage": "./vendor/bin/phpunit",
"lint": [

View File

@@ -9,7 +9,7 @@
*/
$PHPMAILER_LANG['authenticate'] = 'Error SMTP: Imposible autentificar.';
$PHPMAILER_LANG['buggy_php'] = 'Tu versión de PHP está afectada por un bug que puede resultar en mensajes corruptos. Para arreglarlo, cambia a enviar usando SMTP, deshabilita la opción mail.add_x_header en tu php.ini, cambia a MacOS o Linux, o actualiza tu PHP a la versión 7.0.17+ o 7.1.3+.';
$PHPMAILER_LANG['buggy_php'] = 'Tu versión de PHP ha sido afectada por un bug que puede resultar en mensajes corruptos. Para arreglarlo, cambia a enviar usando SMTP, deshabilita la opción mail.add_x_header en tu php.ini, cambia a MacOS o Linux, o actualiza tu PHP a la versión 7.0.17+ o 7.1.3+.';
$PHPMAILER_LANG['connect_host'] = 'Error SMTP: Imposible conectar al servidor SMTP.';
$PHPMAILER_LANG['data_not_accepted'] = 'Error SMTP: Datos no aceptados.';
$PHPMAILER_LANG['empty_message'] = 'El cuerpo del mensaje está vacío.';
@@ -18,7 +18,7 @@ $PHPMAILER_LANG['execute'] = 'Imposible ejecutar: ';
$PHPMAILER_LANG['extension_missing'] = 'Extensión faltante: ';
$PHPMAILER_LANG['file_access'] = 'Imposible acceder al archivo: ';
$PHPMAILER_LANG['file_open'] = 'Error de Archivo: Imposible abrir el archivo: ';
$PHPMAILER_LANG['from_failed'] = 'La(s) siguiente(s) direcciones de remitente fallaron: ';
$PHPMAILER_LANG['from_failed'] = 'La siguiente dirección de remitente falló: ';
$PHPMAILER_LANG['instantiate'] = 'Imposible crear una instancia de la función Mail.';
$PHPMAILER_LANG['invalid_address'] = 'Imposible enviar: dirección de email inválido: ';
$PHPMAILER_LANG['invalid_header'] = 'Nombre o valor de encabezado no válido';
@@ -34,3 +34,5 @@ $PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() falló.';
$PHPMAILER_LANG['smtp_detail'] = 'Detalle: ';
$PHPMAILER_LANG['smtp_error'] = 'Error del servidor SMTP: ';
$PHPMAILER_LANG['variable_set'] = 'No se pudo configurar la variable: ';
$PHPMAILER_LANG['imap_recommended'] = 'No se recomienda usar el analizador de direcciones simplificado. Instala la extensión IMAP de PHP para un análisis RFC822 más completo.';
$PHPMAILER_LANG['deprecated_argument'] = 'El argumento $useimap ha quedado obsoleto';

View File

@@ -561,9 +561,9 @@ class PHPMailer
* string $body the email body
* string $from email address of sender
* string $extra extra information of possible use
* "smtp_transaction_id' => last smtp transaction id
* 'smtp_transaction_id' => last smtp transaction id
*
* @var string
* @var callable|callable-string
*/
public $action_function = '';
@@ -711,7 +711,7 @@ class PHPMailer
*
* @var array
*/
protected $language = [];
protected static $language = [];
/**
* The number of errors encountered.
@@ -768,7 +768,7 @@ class PHPMailer
*
* @var string
*/
const VERSION = '6.10.0';
const VERSION = '6.11.1';
/**
* Error severity: message only, continue processing.
@@ -1102,7 +1102,7 @@ class PHPMailer
//At-sign is missing.
$error_message = sprintf(
'%s (%s): %s',
$this->lang('invalid_address'),
self::lang('invalid_address'),
$kind,
$address
);
@@ -1187,7 +1187,7 @@ class PHPMailer
if (!in_array($kind, ['to', 'cc', 'bcc', 'Reply-To'])) {
$error_message = sprintf(
'%s: %s',
$this->lang('Invalid recipient kind'),
self::lang('Invalid recipient kind'),
$kind
);
$this->setError($error_message);
@@ -1201,7 +1201,7 @@ class PHPMailer
if (!static::validateAddress($address)) {
$error_message = sprintf(
'%s (%s): %s',
$this->lang('invalid_address'),
self::lang('invalid_address'),
$kind,
$address
);
@@ -1220,12 +1220,16 @@ class PHPMailer
return true;
}
} elseif (!array_key_exists(strtolower($address), $this->ReplyTo)) {
$this->ReplyTo[strtolower($address)] = [$address, $name];
} else {
foreach ($this->ReplyTo as $replyTo) {
if (0 === strcasecmp($replyTo[0], $address)) {
return false;
}
}
$this->ReplyTo[] = [$address, $name];
return true;
}
return false;
}
@@ -1238,15 +1242,18 @@ class PHPMailer
* @see https://www.andrew.cmu.edu/user/agreen1/testing/mrbs/web/Mail/RFC822.php A more careful implementation
*
* @param string $addrstr The address list string
* @param bool $useimap Whether to use the IMAP extension to parse the list
* @param null $useimap Deprecated argument since 6.11.0.
* @param string $charset The charset to use when decoding the address list string.
*
* @return array
*/
public static function parseAddresses($addrstr, $useimap = true, $charset = self::CHARSET_ISO88591)
public static function parseAddresses($addrstr, $useimap = null, $charset = self::CHARSET_ISO88591)
{
if ($useimap !== null) {
trigger_error(self::lang('deprecated_argument'), E_USER_DEPRECATED);
}
$addresses = [];
if ($useimap && function_exists('imap_rfc822_parse_adrlist')) {
if (function_exists('imap_rfc822_parse_adrlist')) {
//Use this built-in parser if it's available
$list = imap_rfc822_parse_adrlist($addrstr, '');
// Clear any potential IMAP errors to get rid of notices being thrown at end of script.
@@ -1256,20 +1263,13 @@ class PHPMailer
'.SYNTAX-ERROR.' !== $address->host &&
static::validateAddress($address->mailbox . '@' . $address->host)
) {
//Decode the name part if it's present and encoded
//Decode the name part if it's present and maybe encoded
if (
property_exists($address, 'personal') &&
//Check for a Mbstring constant rather than using extension_loaded, which is sometimes disabled
defined('MB_CASE_UPPER') &&
preg_match('/^=\?.*\?=$/s', $address->personal)
property_exists($address, 'personal')
&& is_string($address->personal)
&& $address->personal !== ''
) {
$origCharset = mb_internal_encoding();
mb_internal_encoding($charset);
//Undo any RFC2047-encoded spaces-as-underscores
$address->personal = str_replace('_', '=20', $address->personal);
//Decode the name
$address->personal = mb_decode_mimeheader($address->personal);
mb_internal_encoding($origCharset);
$address->personal = static::decodeHeader($address->personal, $charset);
}
$addresses[] = [
@@ -1280,40 +1280,51 @@ class PHPMailer
}
} else {
//Use this simpler parser
$list = explode(',', $addrstr);
foreach ($list as $address) {
$address = trim($address);
//Is there a separate name part?
if (strpos($address, '<') === false) {
//No separate name, just use the whole thing
if (static::validateAddress($address)) {
$addresses[] = [
'name' => '',
'address' => $address,
];
}
} else {
list($name, $email) = explode('<', $address);
$email = trim(str_replace('>', '', $email));
$name = trim($name);
if (static::validateAddress($email)) {
//Check for a Mbstring constant rather than using extension_loaded, which is sometimes disabled
//If this name is encoded, decode it
if (defined('MB_CASE_UPPER') && preg_match('/^=\?.*\?=$/s', $name)) {
$origCharset = mb_internal_encoding();
mb_internal_encoding($charset);
//Undo any RFC2047-encoded spaces-as-underscores
$name = str_replace('_', '=20', $name);
//Decode the name
$name = mb_decode_mimeheader($name);
mb_internal_encoding($origCharset);
}
$addresses[] = [
//Remove any surrounding quotes and spaces from the name
'name' => trim($name, '\'" '),
'address' => $email,
];
}
$addresses = static::parseSimplerAddresses($addrstr, $charset);
}
return $addresses;
}
/**
* Parse a string containing one or more RFC822-style comma-separated email addresses
* with the form "display name <address>" into an array of name/address pairs.
* Uses a simpler parser that does not require the IMAP extension but doesnt support
* the full RFC822 spec. For full RFC822 support, use the PHP IMAP extension.
*
* @param string $addrstr The address list string
* @param string $charset The charset to use when decoding the address list string.
*
* @return array
*/
protected static function parseSimplerAddresses($addrstr, $charset)
{
// Emit a runtime notice to recommend using the IMAP extension for full RFC822 parsing
trigger_error(self::lang('imap_recommended'), E_USER_NOTICE);
$addresses = [];
$list = explode(',', $addrstr);
foreach ($list as $address) {
$address = trim($address);
//Is there a separate name part?
if (strpos($address, '<') === false) {
//No separate name, just use the whole thing
if (static::validateAddress($address)) {
$addresses[] = [
'name' => '',
'address' => $address,
];
}
} else {
$parsed = static::parseEmailString($address);
$email = $parsed['email'];
if (static::validateAddress($email)) {
$name = static::decodeHeader($parsed['name'], $charset);
$addresses[] = [
//Remove any surrounding quotes and spaces from the name
'name' => trim($name, '\'" '),
'address' => $email,
];
}
}
}
@@ -1321,6 +1332,42 @@ class PHPMailer
return $addresses;
}
/**
* Parse a string containing an email address with an optional name
* and divide it into a name and email address.
*
* @param string $input The email with name.
*
* @return array{name: string, email: string}
*/
private static function parseEmailString($input)
{
$input = trim((string)$input);
if ($input === '') {
return ['name' => '', 'email' => ''];
}
$pattern = '/^\s*(?:(?:"([^"]*)"|\'([^\']*)\'|([^<]*?))\s*)?<\s*([^>]+)\s*>\s*$/';
if (preg_match($pattern, $input, $matches)) {
$name = '';
// Double quotes including special scenarios.
if (isset($matches[1]) && $matches[1] !== '') {
$name = $matches[1];
// Single quotes including special scenarios.
} elseif (isset($matches[2]) && $matches[2] !== '') {
$name = $matches[2];
// Simplest scenario, name and email are in the format "Name <email>".
} elseif (isset($matches[3])) {
$name = trim($matches[3]);
}
return ['name' => $name, 'email' => trim($matches[4])];
}
return ['name' => '', 'email' => $input];
}
/**
* Set the From and FromName properties.
*
@@ -1334,6 +1381,10 @@ class PHPMailer
*/
public function setFrom($address, $name = '', $auto = true)
{
if (is_null($name)) {
//Helps avoid a deprecation warning in the preg_replace() below
$name = '';
}
$address = trim((string)$address);
$name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim
//Don't validate now addresses with IDN. Will be done in send().
@@ -1345,7 +1396,7 @@ class PHPMailer
) {
$error_message = sprintf(
'%s (From): %s',
$this->lang('invalid_address'),
self::lang('invalid_address'),
$address
);
$this->setError($error_message);
@@ -1601,7 +1652,7 @@ class PHPMailer
&& ini_get('mail.add_x_header') === '1'
&& stripos(PHP_OS, 'WIN') === 0
) {
trigger_error($this->lang('buggy_php'), E_USER_WARNING);
trigger_error(self::lang('buggy_php'), E_USER_WARNING);
}
try {
@@ -1631,7 +1682,7 @@ class PHPMailer
call_user_func_array([$this, 'addAnAddress'], $params);
}
if (count($this->to) + count($this->cc) + count($this->bcc) < 1) {
throw new Exception($this->lang('provide_address'), self::STOP_CRITICAL);
throw new Exception(self::lang('provide_address'), self::STOP_CRITICAL);
}
//Validate From, Sender, and ConfirmReadingTo addresses
@@ -1648,7 +1699,7 @@ class PHPMailer
if (!static::validateAddress($this->{$address_kind})) {
$error_message = sprintf(
'%s (%s): %s',
$this->lang('invalid_address'),
self::lang('invalid_address'),
$address_kind,
$this->{$address_kind}
);
@@ -1670,7 +1721,7 @@ class PHPMailer
$this->setMessageType();
//Refuse to send an empty message unless we are specifically allowing it
if (!$this->AllowEmpty && empty($this->Body)) {
throw new Exception($this->lang('empty_message'), self::STOP_CRITICAL);
throw new Exception(self::lang('empty_message'), self::STOP_CRITICAL);
}
//Trim subject consistently
@@ -1809,8 +1860,10 @@ class PHPMailer
} else {
$sendmailFmt = '%s -oi -f%s -t';
}
} elseif ($this->Mailer === 'qmail') {
$sendmailFmt = '%s';
} else {
//allow sendmail to choose a default envelope sender. It may
//Allow sendmail to choose a default envelope sender. It may
//seem preferable to force it to use the From header as with
//SMTP, but that introduces new problems (see
//<https://github.com/PHPMailer/PHPMailer/issues/2298>), and
@@ -1828,33 +1881,35 @@ class PHPMailer
foreach ($this->SingleToArray as $toAddr) {
$mail = @popen($sendmail, 'w');
if (!$mail) {
throw new Exception($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
throw new Exception(self::lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
}
$this->edebug("To: {$toAddr}");
fwrite($mail, 'To: ' . $toAddr . "\n");
fwrite($mail, $header);
fwrite($mail, $body);
$result = pclose($mail);
$addrinfo = static::parseAddresses($toAddr, true, $this->CharSet);
$this->doCallback(
($result === 0),
[[$addrinfo['address'], $addrinfo['name']]],
$this->cc,
$this->bcc,
$this->Subject,
$body,
$this->From,
[]
);
$addrinfo = static::parseAddresses($toAddr, null, $this->CharSet);
foreach ($addrinfo as $addr) {
$this->doCallback(
($result === 0),
[[$addr['address'], $addr['name']]],
$this->cc,
$this->bcc,
$this->Subject,
$body,
$this->From,
[]
);
}
$this->edebug("Result: " . ($result === 0 ? 'true' : 'false'));
if (0 !== $result) {
throw new Exception($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
throw new Exception(self::lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
}
}
} else {
$mail = @popen($sendmail, 'w');
if (!$mail) {
throw new Exception($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
throw new Exception(self::lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
}
fwrite($mail, $header);
fwrite($mail, $body);
@@ -1871,7 +1926,7 @@ class PHPMailer
);
$this->edebug("Result: " . ($result === 0 ? 'true' : 'false'));
if (0 !== $result) {
throw new Exception($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
throw new Exception(self::lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
}
}
@@ -2010,17 +2065,19 @@ class PHPMailer
if ($this->SingleTo && count($toArr) > 1) {
foreach ($toArr as $toAddr) {
$result = $this->mailPassthru($toAddr, $this->Subject, $body, $header, $params);
$addrinfo = static::parseAddresses($toAddr, true, $this->CharSet);
$this->doCallback(
$result,
[[$addrinfo['address'], $addrinfo['name']]],
$this->cc,
$this->bcc,
$this->Subject,
$body,
$this->From,
[]
);
$addrinfo = static::parseAddresses($toAddr, null, $this->CharSet);
foreach ($addrinfo as $addr) {
$this->doCallback(
$result,
[[$addr['address'], $addr['name']]],
$this->cc,
$this->bcc,
$this->Subject,
$body,
$this->From,
[]
);
}
}
} else {
$result = $this->mailPassthru($to, $this->Subject, $body, $header, $params);
@@ -2030,7 +2087,7 @@ class PHPMailer
ini_set('sendmail_from', $old_from);
}
if (!$result) {
throw new Exception($this->lang('instantiate'), self::STOP_CRITICAL);
throw new Exception(self::lang('instantiate'), self::STOP_CRITICAL);
}
return true;
@@ -2116,12 +2173,12 @@ class PHPMailer
$header = static::stripTrailingWSP($header) . static::$LE . static::$LE;
$bad_rcpt = [];
if (!$this->smtpConnect($this->SMTPOptions)) {
throw new Exception($this->lang('smtp_connect_failed'), self::STOP_CRITICAL);
throw new Exception(self::lang('smtp_connect_failed'), self::STOP_CRITICAL);
}
//If we have recipient addresses that need Unicode support,
//but the server doesn't support it, stop here
if ($this->UseSMTPUTF8 && !$this->smtp->getServerExt('SMTPUTF8')) {
throw new Exception($this->lang('no_smtputf8'), self::STOP_CRITICAL);
throw new Exception(self::lang('no_smtputf8'), self::STOP_CRITICAL);
}
//Sender already validated in preSend()
if ('' === $this->Sender) {
@@ -2133,7 +2190,7 @@ class PHPMailer
$this->smtp->xclient($this->SMTPXClient);
}
if (!$this->smtp->mail($smtp_from)) {
$this->setError($this->lang('from_failed') . $smtp_from . ' : ' . implode(',', $this->smtp->getError()));
$this->setError(self::lang('from_failed') . $smtp_from . ' : ' . implode(',', $this->smtp->getError()));
throw new Exception($this->ErrorInfo, self::STOP_CRITICAL);
}
@@ -2155,7 +2212,7 @@ class PHPMailer
//Only send the DATA command if we have viable recipients
if ((count($this->all_recipients) > count($bad_rcpt)) && !$this->smtp->data($header . $body)) {
throw new Exception($this->lang('data_not_accepted'), self::STOP_CRITICAL);
throw new Exception(self::lang('data_not_accepted'), self::STOP_CRITICAL);
}
$smtp_transaction_id = $this->smtp->getLastTransactionID();
@@ -2186,7 +2243,7 @@ class PHPMailer
foreach ($bad_rcpt as $bad) {
$errstr .= $bad['to'] . ': ' . $bad['error'];
}
throw new Exception($this->lang('recipients_failed') . $errstr, self::STOP_CONTINUE);
throw new Exception(self::lang('recipients_failed') . $errstr, self::STOP_CONTINUE);
}
return true;
@@ -2240,7 +2297,7 @@ class PHPMailer
$hostinfo
)
) {
$this->edebug($this->lang('invalid_hostentry') . ' ' . trim($hostentry));
$this->edebug(self::lang('invalid_hostentry') . ' ' . trim($hostentry));
//Not a valid host entry
continue;
}
@@ -2252,7 +2309,7 @@ class PHPMailer
//Check the host name is a valid name or IP address before trying to use it
if (!static::isValidHost($hostinfo[2])) {
$this->edebug($this->lang('invalid_host') . ' ' . $hostinfo[2]);
$this->edebug(self::lang('invalid_host') . ' ' . $hostinfo[2]);
continue;
}
$prefix = '';
@@ -2272,7 +2329,7 @@ class PHPMailer
if (static::ENCRYPTION_STARTTLS === $secure || static::ENCRYPTION_SMTPS === $secure) {
//Check for an OpenSSL constant rather than using extension_loaded, which is sometimes disabled
if (!$sslext) {
throw new Exception($this->lang('extension_missing') . 'openssl', self::STOP_CRITICAL);
throw new Exception(self::lang('extension_missing') . 'openssl', self::STOP_CRITICAL);
}
}
$host = $hostinfo[2];
@@ -2324,7 +2381,7 @@ class PHPMailer
$this->oauth
)
) {
throw new Exception($this->lang('authenticate'));
throw new Exception(self::lang('authenticate'));
}
return true;
@@ -2374,7 +2431,7 @@ class PHPMailer
*
* @return bool Returns true if the requested language was loaded, false otherwise.
*/
public function setLanguage($langcode = 'en', $lang_path = '')
public static function setLanguage($langcode = 'en', $lang_path = '')
{
//Backwards compatibility for renamed language codes
$renamed_langcodes = [
@@ -2423,6 +2480,9 @@ class PHPMailer
'smtp_error' => 'SMTP server error: ',
'variable_set' => 'Cannot set or reset variable: ',
'no_smtputf8' => 'Server does not support SMTPUTF8 needed to send to Unicode addresses',
'imap_recommended' => 'Using simplified address parser is not recommended. ' .
'Install the PHP IMAP extension for full RFC822 parsing.',
'deprecated_argument' => 'Argument $useimap is deprecated',
];
if (empty($lang_path)) {
//Calculate an absolute path so it can work if CWD is not here
@@ -2489,7 +2549,7 @@ class PHPMailer
}
}
}
$this->language = $PHPMAILER_LANG;
self::$language = $PHPMAILER_LANG;
return $foundlang; //Returns false if language not found
}
@@ -2501,11 +2561,11 @@ class PHPMailer
*/
public function getTranslations()
{
if (empty($this->language)) {
$this->setLanguage(); // Set the default language.
if (empty(self::$language)) {
self::setLanguage(); // Set the default language.
}
return $this->language;
return self::$language;
}
/**
@@ -2928,10 +2988,6 @@ class PHPMailer
//Create unique IDs and preset boundaries
$this->setBoundaries();
if ($this->sign_key_file) {
$body .= $this->getMailMIME() . static::$LE;
}
$this->setWordWrap();
$bodyEncoding = $this->Encoding;
@@ -2963,6 +3019,12 @@ class PHPMailer
if (static::ENCODING_BASE64 !== $altBodyEncoding && static::hasLineLongerThanMax($this->AltBody)) {
$altBodyEncoding = static::ENCODING_QUOTED_PRINTABLE;
}
if ($this->sign_key_file) {
$this->Encoding = $bodyEncoding;
$body .= $this->getMailMIME() . static::$LE;
}
//Use this as a preamble in all multipart message types
$mimepre = '';
switch ($this->message_type) {
@@ -3144,12 +3206,12 @@ class PHPMailer
if ($this->isError()) {
$body = '';
if ($this->exceptions) {
throw new Exception($this->lang('empty_message'), self::STOP_CRITICAL);
throw new Exception(self::lang('empty_message'), self::STOP_CRITICAL);
}
} elseif ($this->sign_key_file) {
try {
if (!defined('PKCS7_TEXT')) {
throw new Exception($this->lang('extension_missing') . 'openssl');
throw new Exception(self::lang('extension_missing') . 'openssl');
}
$file = tempnam(sys_get_temp_dir(), 'srcsign');
@@ -3187,7 +3249,7 @@ class PHPMailer
$body = $parts[1];
} else {
@unlink($signed);
throw new Exception($this->lang('signing') . openssl_error_string());
throw new Exception(self::lang('signing') . openssl_error_string());
}
} catch (Exception $exc) {
$body = '';
@@ -3332,7 +3394,7 @@ class PHPMailer
) {
try {
if (!static::fileIsAccessible($path)) {
throw new Exception($this->lang('file_access') . $path, self::STOP_CONTINUE);
throw new Exception(self::lang('file_access') . $path, self::STOP_CONTINUE);
}
//If a MIME type is not specified, try to work it out from the file name
@@ -3345,7 +3407,7 @@ class PHPMailer
$name = $filename;
}
if (!$this->validateEncoding($encoding)) {
throw new Exception($this->lang('encoding') . $encoding);
throw new Exception(self::lang('encoding') . $encoding);
}
$this->attachment[] = [
@@ -3506,11 +3568,11 @@ class PHPMailer
{
try {
if (!static::fileIsAccessible($path)) {
throw new Exception($this->lang('file_open') . $path, self::STOP_CONTINUE);
throw new Exception(self::lang('file_open') . $path, self::STOP_CONTINUE);
}
$file_buffer = file_get_contents($path);
if (false === $file_buffer) {
throw new Exception($this->lang('file_open') . $path, self::STOP_CONTINUE);
throw new Exception(self::lang('file_open') . $path, self::STOP_CONTINUE);
}
$file_buffer = $this->encodeString($file_buffer, $encoding);
@@ -3563,9 +3625,9 @@ class PHPMailer
$encoded = $this->encodeQP($str);
break;
default:
$this->setError($this->lang('encoding') . $encoding);
$this->setError(self::lang('encoding') . $encoding);
if ($this->exceptions) {
throw new Exception($this->lang('encoding') . $encoding);
throw new Exception(self::lang('encoding') . $encoding);
}
break;
}
@@ -3671,6 +3733,42 @@ class PHPMailer
return trim(static::normalizeBreaks($encoded));
}
/**
* Decode an RFC2047-encoded header value
* Attempts multiple strategies so it works even when the mbstring extension is disabled.
*
* @param string $value The header value to decode
* @param string $charset The target charset to convert to, defaults to ISO-8859-1 for BC
*
* @return string The decoded header value
*/
public static function decodeHeader($value, $charset = self::CHARSET_ISO88591)
{
if (!is_string($value) || $value === '') {
return '';
}
// Detect the presence of any RFC2047 encoded-words
$hasEncodedWord = (bool) preg_match('/=\?.*\?=/s', $value);
if ($hasEncodedWord && defined('MB_CASE_UPPER')) {
$origCharset = mb_internal_encoding();
// Always decode to UTF-8 to provide a consistent, modern output encoding.
mb_internal_encoding($charset);
if (PHP_VERSION_ID < 80300) {
// Undo any RFC2047-encoded spaces-as-underscores.
$value = str_replace('_', '=20', $value);
} else {
// PHP 8.3+ already interprets underscores as spaces. Remove additional
// linear whitespace between adjacent encoded words to avoid double spacing.
$value = preg_replace('/(\?=)\s+(=\?)/', '$1$2', $value);
}
// Decode the header value
$value = mb_decode_mimeheader($value);
mb_internal_encoding($origCharset);
}
return $value;
}
/**
* Check if a string contains multi-byte characters.
*
@@ -3840,7 +3938,7 @@ class PHPMailer
}
if (!$this->validateEncoding($encoding)) {
throw new Exception($this->lang('encoding') . $encoding);
throw new Exception(self::lang('encoding') . $encoding);
}
//Append to $attachment array
@@ -3899,7 +3997,7 @@ class PHPMailer
) {
try {
if (!static::fileIsAccessible($path)) {
throw new Exception($this->lang('file_access') . $path, self::STOP_CONTINUE);
throw new Exception(self::lang('file_access') . $path, self::STOP_CONTINUE);
}
//If a MIME type is not specified, try to work it out from the file name
@@ -3908,7 +4006,7 @@ class PHPMailer
}
if (!$this->validateEncoding($encoding)) {
throw new Exception($this->lang('encoding') . $encoding);
throw new Exception(self::lang('encoding') . $encoding);
}
$filename = (string) static::mb_pathinfo($path, PATHINFO_BASENAME);
@@ -3974,7 +4072,7 @@ class PHPMailer
}
if (!$this->validateEncoding($encoding)) {
throw new Exception($this->lang('encoding') . $encoding);
throw new Exception(self::lang('encoding') . $encoding);
}
//Append to $attachment array
@@ -4231,7 +4329,7 @@ class PHPMailer
}
if (strpbrk($name . $value, "\r\n") !== false) {
if ($this->exceptions) {
throw new Exception($this->lang('invalid_header'));
throw new Exception(self::lang('invalid_header'));
}
return false;
@@ -4255,15 +4353,15 @@ class PHPMailer
if ('smtp' === $this->Mailer && null !== $this->smtp) {
$lasterror = $this->smtp->getError();
if (!empty($lasterror['error'])) {
$msg .= ' ' . $this->lang('smtp_error') . $lasterror['error'];
$msg .= ' ' . self::lang('smtp_error') . $lasterror['error'];
if (!empty($lasterror['detail'])) {
$msg .= ' ' . $this->lang('smtp_detail') . $lasterror['detail'];
$msg .= ' ' . self::lang('smtp_detail') . $lasterror['detail'];
}
if (!empty($lasterror['smtp_code'])) {
$msg .= ' ' . $this->lang('smtp_code') . $lasterror['smtp_code'];
$msg .= ' ' . self::lang('smtp_code') . $lasterror['smtp_code'];
}
if (!empty($lasterror['smtp_code_ex'])) {
$msg .= ' ' . $this->lang('smtp_code_ex') . $lasterror['smtp_code_ex'];
$msg .= ' ' . self::lang('smtp_code_ex') . $lasterror['smtp_code_ex'];
}
}
}
@@ -4388,21 +4486,21 @@ class PHPMailer
*
* @return string
*/
protected function lang($key)
protected static function lang($key)
{
if (count($this->language) < 1) {
$this->setLanguage(); //Set the default language
if (count(self::$language) < 1) {
self::setLanguage(); //Set the default language
}
if (array_key_exists($key, $this->language)) {
if (array_key_exists($key, self::$language)) {
if ('smtp_connect_failed' === $key) {
//Include a link to troubleshooting docs on SMTP connection failure.
//This is by far the biggest cause of support questions
//but it's usually not PHPMailer's fault.
return $this->language[$key] . ' https://github.com/PHPMailer/PHPMailer/wiki/Troubleshooting';
return self::$language[$key] . ' https://github.com/PHPMailer/PHPMailer/wiki/Troubleshooting';
}
return $this->language[$key];
return self::$language[$key];
}
//Return the key as a fallback
@@ -4417,7 +4515,7 @@ class PHPMailer
*/
private function getSmtpErrorMessage($base_key)
{
$message = $this->lang($base_key);
$message = self::lang($base_key);
$error = $this->smtp->getError();
if (!empty($error['error'])) {
$message .= ' ' . $error['error'];
@@ -4461,7 +4559,7 @@ class PHPMailer
//Ensure name is not empty, and that neither name nor value contain line breaks
if (empty($name) || strpbrk($name . $value, "\r\n") !== false) {
if ($this->exceptions) {
throw new Exception($this->lang('invalid_header'));
throw new Exception(self::lang('invalid_header'));
}
return false;
@@ -4854,7 +4952,7 @@ class PHPMailer
return true;
}
$this->setError($this->lang('variable_set') . $name);
$this->setError(self::lang('variable_set') . $name);
return false;
}
@@ -4992,7 +5090,7 @@ class PHPMailer
{
if (!defined('PKCS7_TEXT')) {
if ($this->exceptions) {
throw new Exception($this->lang('extension_missing') . 'openssl');
throw new Exception(self::lang('extension_missing') . 'openssl');
}
return '';

View File

@@ -46,7 +46,7 @@ class POP3
*
* @var string
*/
const VERSION = '6.10.0';
const VERSION = '6.11.1';
/**
* Default POP3 port number.

View File

@@ -35,7 +35,7 @@ class SMTP
*
* @var string
*/
const VERSION = '6.10.0';
const VERSION = '6.11.1';
/**
* SMTP line break constant.
@@ -205,6 +205,7 @@ class SMTP
'Haraka' => '/[\d]{3} Message Queued \((.*)\)/',
'ZoneMTA' => '/[\d]{3} Message queued as (.*)/',
'Mailjet' => '/[\d]{3} OK queued as (.*)/',
'Gsmtp' => '/[\d]{3} 2\.0\.0 OK (.*) - gsmtp/',
];
/**
@@ -633,10 +634,41 @@ class SMTP
return false;
}
$oauth = $OAuth->getOauth64();
//Start authentication
if (!$this->sendCommand('AUTH', 'AUTH XOAUTH2 ' . $oauth, 235)) {
return false;
/*
* An SMTP command line can have a maximum length of 512 bytes, including the command name,
* so the base64-encoded OAUTH token has a maximum length of:
* 512 - 13 (AUTH XOAUTH2) - 2 (CRLF) = 497 bytes
* If the token is longer than that, the command and the token must be sent separately as described in
* https://www.rfc-editor.org/rfc/rfc4954#section-4
*/
if ($oauth === '') {
//Sending an empty auth token is legitimate, but it must be encoded as '='
//to indicate it's not a 2-part command
if (!$this->sendCommand('AUTH', 'AUTH XOAUTH2 =', 235)) {
return false;
}
} elseif (strlen($oauth) <= 497) {
//Authenticate using a token in the initial-response part
if (!$this->sendCommand('AUTH', 'AUTH XOAUTH2 ' . $oauth, 235)) {
return false;
}
} else {
//The token is too long, so we need to send it in two parts.
//Send the auth command without a token and expect a 334
if (!$this->sendCommand('AUTH', 'AUTH XOAUTH2', 334)) {
return false;
}
//Send the token
if (!$this->sendCommand('OAuth TOKEN', $oauth, [235, 334])) {
return false;
}
//If the server answers with 334, send an empty line and wait for a 235
if (
substr($this->last_reply, 0, 3) === '334'
&& $this->sendCommand('AUTH End', '', 235)
) {
return false;
}
}
break;
default:
@@ -1309,7 +1341,16 @@ class SMTP
//stream_select returns false when the `select` system call is interrupted
//by an incoming signal, try the select again
if (stripos($message, 'interrupted system call') !== false) {
if (
stripos($message, 'interrupted system call') !== false ||
(
// on applications with a different locale than english, the message above is not found because
// it's translated. So we also check for the SOCKET_EINTR constant which is defined under
// Windows and UNIX-like platforms (if available on the platform).
defined('SOCKET_EINTR') &&
stripos($message, 'stream_select(): Unable to select [' . SOCKET_EINTR . ']') !== false
)
) {
$this->edebug(
'SMTP -> get_lines(): retrying stream_select',
self::DEBUG_LOWLEVEL

View File

@@ -3,36 +3,267 @@
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com)
and this project adheres to [Semantic Versioning](https://semver.org).
and this project adheres to [Semantic Versioning](https://semver.org). Thia is always true of the master branch. Some earlier branches remain supported and security fixes are applied to them; if the security fix represents a breaking change, it may have to be applied as a minor or patch version.
# 2025-02-07 - 2.3.8
## TBD - 5.2.0
### Fixed
### Added
- Xls writer Parser Mishandling True/False Argument. Backport of [PR #4333](https://github.com/PHPOffice/PhpSpreadsheet/pull/4333)
- Xls writer Parser Parse By Character Not Byte. Backport of [PR #4344](https://github.com/PHPOffice/PhpSpreadsheet/pull/4344)
- Nothing yet.
# 2025-01-26 - 2.3.7
### Removed
### Fixed
- Nothing yet.
- Backported security patch for control characters in protocol.
- Use Composer\Pcre in Xls/Parser. Partial backport of [PR #4203](https://github.com/PHPOffice/PhpSpreadsheet/pull/4203)
### Changed
# 2025-01-11 - 2.3.6
- Nothing yet.
### Moved
- Nothing yet.
### Deprecated
- Worksheet::getHashCode is no longer needed.
- Nothing yet.
### Fixed
- Backported security patch for Html navigation.
- Change hash code for worksheet. Backport of [PR #4207](https://github.com/PHPOffice/PhpSpreadsheet/pull/4207)
- Retitling cloned worksheets. Backport of [PR #4302](https://github.com/PHPOffice/PhpSpreadsheet/pull/4302)
- Nothing yet.
## 2025-09-03 - 5.1.0
# 2024-12-26 - 2.3.5
### Added
- Add Conditional Formatting with IconSet (Xlsx only). [Issue #4560](https://github.com/PHPOffice/PhpSpreadsheet/issues/4560) [PR #4574](https://github.com/PHPOffice/PhpSpreadsheet/pull/4574)
- Copy cell adjusting formula. [Issue #1203](https://github.com/PHPOffice/PhpSpreadsheet/issues/1203) [PR #4577](https://github.com/PHPOffice/PhpSpreadsheet/pull/4577)
- splitRange and ProtectedRange. [Issue #1457](https://github.com/PHPOffice/PhpSpreadsheet/issues/1457) [PR #4580](https://github.com/PHPOffice/PhpSpreadsheet/pull/4580)
- Option to create Blank Sheet if LoadSheetsOnly doesn't find any. [PR #4618](https://github.com/PHPOffice/PhpSpreadsheet/pull/4618)
### Fixed
- Google-only formulas exported from Google Sheets. [Issue #1637](https://github.com/PHPOffice/PhpSpreadsheet/issues/1637) [PR #4579](https://github.com/PHPOffice/PhpSpreadsheet/pull/4579)
- Maximum column width. [PR #4581](https://github.com/PHPOffice/PhpSpreadsheet/pull/4581)
- PrintArea after row/column delete. [Issue #2912](https://github.com/PHPOffice/PhpSpreadsheet/issues/2912) [PR #4598](https://github.com/PHPOffice/PhpSpreadsheet/pull/4598)
- Remove deprecated imagedestroy call. [PR #4625](https://github.com/PHPOffice/PhpSpreadsheet/pull/4625)
- Excel 2007 problem with newlines. [Issue #4619](https://github.com/PHPOffice/PhpSpreadsheet/issues/4619) [PR #4620](https://github.com/PHPOffice/PhpSpreadsheet/pull/4620)
- Compatibility changes for Php 8.5. [PR #4601](https://github.com/PHPOffice/PhpSpreadsheet/pull/4601) [PR #4611](https://github.com/PHPOffice/PhpSpreadsheet/pull/4611)
## 2025-08-10 - 5.0.0
### Breaking Changes
- Images will be loaded from an external source (e.g. http://example.com/img.png) only if the reader is explicitly set to allow it via `$reader->setAllowExternalImages(true)`. We do not believe that loading of external images is a widely used feature.
- Deletion of items deprecated in Release 4. See "removed" below.
- Move some properties from Base Reader to Html Reader. [PR #4551](https://github.com/PHPOffice/PhpSpreadsheet/pull/4551)
- DefaultValueBinder will treat integers with more than 15 digits as strings. [Issue #4522](https://github.com/PHPOffice/PhpSpreadsheet/issues/4522) [PR #4527](https://github.com/PHPOffice/PhpSpreadsheet/pull/4527)
### Removed
- Theme public constants COLOR_SCHEME_2013_PLUS_NAME (use COLOR_SCHEME_2013_2022_NAME) and COLOR_SCHEME_2013_PLUS (use COLOR_SCHEME_2013_2022).
### Fixed
- Additional floating-point precision changes. [Issue #1324](https://github.com/PHPOffice/PhpSpreadsheet/issues/1324) [PR #4575](https://github.com/PHPOffice/PhpSpreadsheet/pull/4575)
- Header/Footer images expand location. [Issue #484](https://github.com/PHPOffice/PhpSpreadsheet/issues/484) [Issue #1318](https://github.com/PHPOffice/PhpSpreadsheet/issues/1318) [PR #4572](https://github.com/PHPOffice/PhpSpreadsheet/pull/4572)
- Create uninitialized cell if used in calculation. [Issue #4558](https://github.com/PHPOffice/PhpSpreadsheet/issues/4558) [Issue #4530](https://github.com/PHPOffice/PhpSpreadsheet/issues/4530) [PR #4565](https://github.com/PHPOffice/PhpSpreadsheet/pull/4565)
- Shared/Date::isDateTime handle cells which calculate as arrays. [Issue #4557](https://github.com/PHPOffice/PhpSpreadsheet/issues/4557) [PR #4562](https://github.com/PHPOffice/PhpSpreadsheet/pull/4562)
- Xlsx Writer eliminate xml:space from non-text nodes. [Issue #4542](https://github.com/PHPOffice/PhpSpreadsheet/issues/4542) [PR #4556](https://github.com/PHPOffice/PhpSpreadsheet/pull/4556)
## 2025-07-23 - 4.5.0
### Added
- Add to all readers the option to allow or forbid fetching external images. This is unconditionally allowed now. The default will be set to "allow", so no code changes are necessary. However, we are giving consideration to changing the default. [PR #4543](https://github.com/PHPOffice/PhpSpreadsheet/pull/4543)
- Address Excel Inappropriate Number Format Substitution. [PR #4532](https://github.com/PHPOffice/PhpSpreadsheet/pull/4532)
### Fixed
- Html Writer Conditional Formatting Inline Css. [Issue #4539](https://github.com/PHPOffice/PhpSpreadsheet/issues/4539) [PR #4541](https://github.com/PHPOffice/PhpSpreadsheet/pull/4541)
- Do not use htmlspecialchars when formatting XML. [Issue #4537](https://github.com/PHPOffice/PhpSpreadsheet/issues/4537) [PR #4540](https://github.com/PHPOffice/PhpSpreadsheet/pull/4540)
- Writer Html/Pdf support RTL alignment of tables. [Issue #1104](https://github.com/PHPOffice/PhpSpreadsheet/issues/1104) [PR #4535](https://github.com/PHPOffice/PhpSpreadsheet/pull/4535)
- Xlsx Reader use dynamic arrays if spreadsheet did so. [PR #4533](https://github.com/PHPOffice/PhpSpreadsheet/pull/4533)
- Ods Reader Nested table-row. [Issue #4528](https://github.com/PHPOffice/PhpSpreadsheet/issues/4528) [Issue #2507](https://github.com/PHPOffice/PhpSpreadsheet/issues/2507) [PR #4531](https://github.com/PHPOffice/PhpSpreadsheet/pull/4531)
- Recognize application/x-empty mimetype. [Issue #4521](https://github.com/PHPOffice/PhpSpreadsheet/issues/4521) [PR #4524](https://github.com/PHPOffice/PhpSpreadsheet/pull/4524)
- Micro-optimization in getSheetByName. [PR #4499](https://github.com/PHPOffice/PhpSpreadsheet/pull/4499)
- Bug in resizeMatricesExtend. [Issue #4451](https://github.com/PHPOffice/PhpSpreadsheet/issues/4451) [PR #4474](https://github.com/PHPOffice/PhpSpreadsheet/pull/4474)
- Allow Replace of Dummy Function with Custom Function. [PR #4544](https://github.com/PHPOffice/PhpSpreadsheet/pull/4544)
- Preserve 0x0a in Strings if Desired. [Issue #347](https://github.com/PHPOffice/PhpSpreadsheet/issues/347) [PR #4536](https://github.com/PHPOffice/PhpSpreadsheet/pull/4536)
## 2025-06-22 - 4.4.0
### Added
- VSTACK and HSTACK. [Issue #4485](https://github.com/PHPOffice/PhpSpreadsheet/issues/4485) [PR #4492](https://github.com/PHPOffice/PhpSpreadsheet/pull/4492)
- TOCOL and TOROW. [PR #4493](https://github.com/PHPOffice/PhpSpreadsheet/pull/4493)
- Support Current Office Theme. [PR #4500](https://github.com/PHPOffice/PhpSpreadsheet/pull/4500)
### Deprecated
- Theme constants COLOR_SCHEME_2013_PLUS_NAME (use COLOR_SCHEME_2013_2022_NAME) and COLOR_SCHEME_2013_PLUS (use COLOR_SCHEME_2013_2022).
### Fixed
- Various Writers RichText TextElement Should Inherit Cell Style. [Issue #1154](https://github.com/PHPOffice/PhpSpreadsheet/issues/1154) [PR #4487](https://github.com/PHPOffice/PhpSpreadsheet/pull/4487)
- Minor Changes to FILTER function. [PR #4491](https://github.com/PHPOffice/PhpSpreadsheet/pull/4491)
- Allow Xlsx Reader/Writer to support Font Charset. [Issue #2760](https://github.com/PHPOffice/PhpSpreadsheet/issues/2760) [PR #4501](https://github.com/PHPOffice/PhpSpreadsheet/pull/4501)
- AutoColor for LibreOffice Dark Mode [Discussion 4502](https://github.com/PHPOffice/PhpSpreadsheet/discussions/4502) [PR #4503](https://github.com/PHPOffice/PhpSpreadsheet/pull/4503)
- Xlsx Style Writer Minor Refactoring. [PR #4508](https://github.com/PHPOffice/PhpSpreadsheet/pull/4508)
- Allow Xlsx Reader to Specify ParseHuge. [Issue #4260](https://github.com/PHPOffice/PhpSpreadsheet/issues/4260) [PR #4515](https://github.com/PHPOffice/PhpSpreadsheet/pull/4515)
## 2025-05-26 - 4.3.1
### Fixed
- Regression in Date::stringToExcel. [Issue #4488](https://github.com/PHPOffice/PhpSpreadsheet/issues/4488) [PR #4489](https://github.com/PHPOffice/PhpSpreadsheet/pull/4489)
## 2025-05-25 - 4.3.0
### Added
- Xml Reader recognize indents. [Issue #4448](https://github.com/PHPOffice/PhpSpreadsheet/issues/4448) [PR #4449](https://github.com/PHPOffice/PhpSpreadsheet/pull/4449)
### Changed
- Phpstan Level 10.
### Fixed
- Micro-optimization for excelToDateTimeObject. [Issue #4438](https://github.com/PHPOffice/PhpSpreadsheet/issues/4438) [PR #4442](https://github.com/PHPOffice/PhpSpreadsheet/pull/4442)
- Removing Columns/Rows Containing Merged Cells. [Issue #282](https://github.com/PHPOffice/PhpSpreadsheet/issues/282) [PR #4465](https://github.com/PHPOffice/PhpSpreadsheet/pull/4465)
- Print Area and Row Break. [Issue #1275](https://github.com/PHPOffice/PhpSpreadsheet/issues/1275) [PR #4450](https://github.com/PHPOffice/PhpSpreadsheet/pull/4450)
- Copy Styles after insertNewColumnBefore. [Issue #1425](https://github.com/PHPOffice/PhpSpreadsheet/issues/1425) [PR #4468](https://github.com/PHPOffice/PhpSpreadsheet/pull/4468)
- Xls Writer Treat Hyperlink Starting with # as Internal. [Issue #56](https://github.com/PHPOffice/PhpSpreadsheet/issues/56) [PR #4453](https://github.com/PHPOffice/PhpSpreadsheet/pull/4453)
- More Precision for Float to String Casts. [Issue #3899](https://github.com/PHPOffice/PhpSpreadsheet/issues/3899) [PR #4479](https://github.com/PHPOffice/PhpSpreadsheet/pull/4479)
- Hyperlink Styles. [Issue #1632](https://github.com/PHPOffice/PhpSpreadsheet/issues/1632) [PR #4478](https://github.com/PHPOffice/PhpSpreadsheet/pull/4478)
- ODS Handling of Ceiling and Floor. [Issue #477](https://github.com/PHPOffice/PhpSpreadsheet/issues/407) [PR #4466](https://github.com/PHPOffice/PhpSpreadsheet/pull/4466)
- Xlsx Reader Do Not Process Printer Settings for Dataonly. [Issue #4477](https://github.com/PHPOffice/PhpSpreadsheet/issues/4477) [PR #4480](https://github.com/PHPOffice/PhpSpreadsheet/pull/4480)
## 2025-04-16 - 4.2.0
### Added
- Add ability to add custom functions to Calculation. [PR #4390](https://github.com/PHPOffice/PhpSpreadsheet/pull/4390)
- Add FormulaRange to IgnoredErrors. [PR #4393](https://github.com/PHPOffice/PhpSpreadsheet/pull/4393)
- TextGrid improvements. [PR #4418](https://github.com/PHPOffice/PhpSpreadsheet/pull/4418)
- Permit read to class which extends Spreadsheet. [Discussion #4402](https://github.com/PHPOffice/PhpSpreadsheet/discussions/4402) [PR #4404](https://github.com/PHPOffice/PhpSpreadsheet/pull/4404)
- Conditional and table formatting support for html writer [PR #4412](https://github.com/PHPOffice/PhpSpreadsheet/pull/4412)
### Changed
- Phpstan Version 2. [PR #4384](https://github.com/PHPOffice/PhpSpreadsheet/pull/4384)
- Start migration to Phpstan level 9. [PR #4396](https://github.com/PHPOffice/PhpSpreadsheet/pull/4396)
- Calculation locale logic moved to separate class. [PR #4398](https://github.com/PHPOffice/PhpSpreadsheet/pull/4398)
- TREND_POLYNOMIAL_* and TREND_BEST_FIT do not work, and are changed to throw Exceptions if attempted. (TREND_BEST_FIT_NO_POLY works.) An attempt to use an unknown trend type will now also throw an exception. [Issue #4400](https://github.com/PHPOffice/PhpSpreadsheet/issues/4400) [PR #4339](https://github.com/PHPOffice/PhpSpreadsheet/pull/4339)
- Month parameter of DATE function will now return VALUE if an ordinal string (e.g. '3rd') is used, but will accept bool or null. [PR #4420](https://github.com/PHPOffice/PhpSpreadsheet/pull/4420)
### Fixed
- Ignore fractional part of Drawing Shadow Alpha. [Issue #4415](https://github.com/PHPOffice/PhpSpreadsheet/issues/4415) [PR #4417](https://github.com/PHPOffice/PhpSpreadsheet/pull/4417)
- BIN2DEC, OCT2DEC, and HEX2DEC return numbers rather than strings. [Issue #4383](https://github.com/PHPOffice/PhpSpreadsheet/issues/4383) [PR #4389](https://github.com/PHPOffice/PhpSpreadsheet/pull/4389)
- Fix TREND_BEST_FIT_NO_POLY. [Issue #4400](https://github.com/PHPOffice/PhpSpreadsheet/issues/4400) [PR #4339](https://github.com/PHPOffice/PhpSpreadsheet/pull/4339)
- Ods Reader No DataType for Null Value. [Issue #4435](https://github.com/PHPOffice/PhpSpreadsheet/issues/4435) [PR #4436](https://github.com/PHPOffice/PhpSpreadsheet/pull/4436)
- Column widths not preserved when using read filter. [Issue #4416](https://github.com/PHPOffice/PhpSpreadsheet/issues/4416) [PR #4423](https://github.com/PHPOffice/PhpSpreadsheet/pull/4423)
- Fix typo in Style exportArray quotePrefix. [Issue #4422](https://github.com/PHPOffice/PhpSpreadsheet/issues/4422) [PR #4424](https://github.com/PHPOffice/PhpSpreadsheet/pull/4424)
- Tweak Spreadsheet clone. [PR #4419](https://github.com/PHPOffice/PhpSpreadsheet/pull/4419)
- Better handling of Chart DisplayBlanksAs. [Issue #4411](https://github.com/PHPOffice/PhpSpreadsheet/issues/4411) [PR #4414](https://github.com/PHPOffice/PhpSpreadsheet/pull/4414)
## 2025-03-02 - 4.1.0
### Added
- Support Justify Last Line. [Issue #4374](https://github.com/PHPOffice/PhpSpreadsheet/issues/4374) [PR #4373](https://github.com/PHPOffice/PhpSpreadsheet/pull/4373)
- Allow Spreadsheet clone. [PR #4370](https://github.com/PHPOffice/PhpSpreadsheet/pull/4370)
### Changed
- ListWorksheetInfo will now return sheetState (visible, hidden, veryHidden). [Issue #4345](https://github.com/PHPOffice/PhpSpreadsheet/issues/4345) [PR #4366](https://github.com/PHPOffice/PhpSpreadsheet/pull/4366)
- Start migration to Phpstan 2. [PR #4359](https://github.com/PHPOffice/PhpSpreadsheet/pull/4359)
- IOFactory identify can return, and createReader and CreateWriter can accept, a class name rather than a file type. [Issue #4357](https://github.com/PHPOffice/PhpSpreadsheet/issues/4357) [PR #4361](https://github.com/PHPOffice/PhpSpreadsheet/pull/4361)
### Fixed
- Refactor Helper/Html. [PR #4359](https://github.com/PHPOffice/PhpSpreadsheet/pull/4359)
- Handle #REF! as Argument to AVERAGEIF/COUNTIF/SUMIF. [Issue #4381](https://github.com/PHPOffice/PhpSpreadsheet/issues/4381) [PR #4382](https://github.com/PHPOffice/PhpSpreadsheet/pull/4382)
- Ignore ignoredErrors when not applicable. [Issue #4375](https://github.com/PHPOffice/PhpSpreadsheet/issues/4375) [PR #4377](https://github.com/PHPOffice/PhpSpreadsheet/pull/4377)
- Better handling of defined names on sheets whose titles include apostrophes. [Issue #4356](https://github.com/PHPOffice/PhpSpreadsheet/issues/4356) [Issue #4362](https://github.com/PHPOffice/PhpSpreadsheet/issues/4362) [Issue #4376](https://github.com/PHPOffice/PhpSpreadsheet/issues/4376) [PR #4360](https://github.com/PHPOffice/PhpSpreadsheet/pull/4360)
- Partial solution for removing rows or columns that include edge ranges. [Issue #1449](https://github.com/PHPOffice/PhpSpreadsheet/issues/1449) [PR #3528](https://github.com/PHPOffice/PhpSpreadsheet/pull/3528)
- Prefer mb_str_split to str_split. [PR #3341](https://github.com/PHPOffice/PhpSpreadsheet/pull/3341)
## 2025-02-08 - 4.0.0
### BREAKING CHANGES
- Data Validations will be stored by worksheet, not cell. Index can be one or more cells or cell ranges. [Issue #797](https://github.com/PHPOffice/PhpSpreadsheet/issues/797) [Issue #4091](https://github.com/PHPOffice/PhpSpreadsheet/issues/4091) [Issue #4206](https://github.com/PHPOffice/PhpSpreadsheet/issues/4206) [PR #4240](https://github.com/PHPOffice/PhpSpreadsheet/pull/4240)
- Conditional Formatting adds Priority property and handles overlapping ranges better. [Issue #4312](https://github.com/PHPOffice/PhpSpreadsheet/issues/4312) [Issue #4318](https://github.com/PHPOffice/PhpSpreadsheet/issues/4318) [PR #4314](https://github.com/PHPOffice/PhpSpreadsheet/pull/4314)
- Csv Reader will no longer auto-detect Mac line endings by default. Prior behavior can be explicitly enabled via `setTestAutoDetect(true)`, and it will not be possible at all with Php9+. [Issue #4092](https://github.com/PHPOffice/PhpSpreadsheet/issues/4092) [PR #4340](https://github.com/PHPOffice/PhpSpreadsheet/pull/4340)
- Html Writer will now use "better boolean" logic. Booleans will now be output by default as TRUE/FALSE rather than 1/null-string. Prior behavior can be explicitly enabled via `setBetterBoolean(false)`. [PR #4340](https://github.com/PHPOffice/PhpSpreadsheet/pull/4340)
- Xlsx Writer will now use false as the default for `forceFullCalc`. This affects writes with `preCalculateFormulas` set to false. Prior behavior can be explicitly enabled via `setForceFullCalc(null)`.[PR #4340](https://github.com/PHPOffice/PhpSpreadsheet/pull/4340)
- Deletion of items deprecated in Release 3. See "removed" below.
### Added
- Pdf Charts and Drawings. [Discussion #4129](https://github.com/PHPOffice/PhpSpreadsheet/discussions/4129) [Discussion #4168](https://github.com/PHPOffice/PhpSpreadsheet/discussions/4168) [PR #4327](https://github.com/PHPOffice/PhpSpreadsheet/pull/4327)
- Allow spreadsheet serialization. [Discussion #4324](https://github.com/PHPOffice/PhpSpreadsheet/discussions/4324) [Issue #1741](https://github.com/PHPOffice/PhpSpreadsheet/issues/1741) [Issue #1757](https://github.com/PHPOffice/PhpSpreadsheet/issues/1757) [PR #4326](https://github.com/PHPOffice/PhpSpreadsheet/pull/4326)
### Removed
- Worksheet::getStyles - no replacement. [PR #4330](https://github.com/PHPOffice/PhpSpreadsheet/pull/4330)
- The following items were deprecated in release 3 and are now removed.
- Drawing::setIsUrl - no replacement.
- Settings::setLibXmlLoaderOptions() and Settings::getLibXmlLoaderOptions() - no replacement.
- Worksheet::getHashCode - no replacement.
- IReader::SKIP_EMPTY_CELLS - use its alias IGNORE_EMPTY_CELLS instead.
- Worksheet::getProtectedCells - use getProtectedCellRanges instead.
- Writer/Html::isMpdf property - use instanceof Mpdf instead.
### Changed
- Nothing yet.
### Moved
- Nothing yet.
### Deprecated
- Nothing yet.
### Fixed
- Xls writer Parser Mishandling True/False Argument. [Issue #4331](https://github.com/PHPOffice/PhpSpreadsheet/issues/4331) [PR #4333](https://github.com/PHPOffice/PhpSpreadsheet/pull/4333)
- Xls writer Parser Parse By Character Not Byte. [PR #4344](https://github.com/PHPOffice/PhpSpreadsheet/pull/4344)
- Minor changes to dynamic array calculations exposed by using explicit array return types in some tests. [PR #4328](https://github.com/PHPOffice/PhpSpreadsheet/pull/4328)
## 2025-01-26 - 3.9.0
### Added
- Methods to get style for row or column. [PR #4317](https://github.com/PHPOffice/PhpSpreadsheet/pull/4317)
- Method for duplicating worksheet in spreadsheet. [PR #4315](https://github.com/PHPOffice/PhpSpreadsheet/pull/4315)
### Fixed
- Security patch for control characters in protocol.
- Ods Reader Sheet Names with Period. [Issue #4311](https://github.com/PHPOffice/PhpSpreadsheet/issues/4311) [PR #4313](https://github.com/PHPOffice/PhpSpreadsheet/pull/4313)
- Mpdf and Tcpdf Hidden Columns and Merged Cells. [Issue #4319](https://github.com/PHPOffice/PhpSpreadsheet/issues/4319) [PR #4320](https://github.com/PHPOffice/PhpSpreadsheet/pull/4320)
- Html Writer Allow mailto. [Issue #4316](https://github.com/PHPOffice/PhpSpreadsheet/issues/4316) [PR #4322](https://github.com/PHPOffice/PhpSpreadsheet/pull/4322)
- Use composer/pcre rather than preg_* in Writer. [PR #4323](https://github.com/PHPOffice/PhpSpreadsheet/pull/4323)
## 2025-01-11 - 3.8.0
### Added
- CHOOSECOLS, CHOOSEROWS, DROP, TAKE, and EXPAND. [PR #4286](https://github.com/PHPOffice/PhpSpreadsheet/pull/4286)
### Fixed
- Security patch for Html navigation.
- Xlsx Reader Shared Formula with Boolean Result. Partial solution for [Issue #4280](https://github.com/PHPOffice/PhpSpreadsheet/issues/4280) [PR #4281](https://github.com/PHPOffice/PhpSpreadsheet/pull/4281)
- Retitling cloned Worksheets. [Issue #641](https://github.com/PHPOffice/PhpSpreadsheet/issues/641) [PR #4302](https://github.com/PHPOffice/PhpSpreadsheet/pull/4302)
- Extremely limited support for GROUPBY function. Partial response to [Issue #4282](https://github.com/PHPOffice/PhpSpreadsheet/issues/4282) [PR #4283](https://github.com/PHPOffice/PhpSpreadsheet/pull/4283)
## 2024-12-26 - 3.7.0
### Deprecated
@@ -40,58 +271,145 @@ and this project adheres to [Semantic Versioning](https://semver.org).
### Fixed
- More context options may be needed for http(s) image. Backport of [PR #4276](https://github.com/PHPOffice/PhpSpreadsheet/pull/4276)
- Backported security patches for Samples.
- Backported security patches for Html Writer.
- Security patches for Samples.
- Security patches for Html Writer.
- Avoid unexpected charset in currency symbol. [PR #4279](https://github.com/PHPOffice/PhpSpreadsheet/pull/4279)
- Add forceFullCalc option to Xlsx Writer. [Issue #4269](https://github.com/PHPOffice/PhpSpreadsheet/issues/4269) [PR #4271](https://github.com/PHPOffice/PhpSpreadsheet/pull/4271)
- More context options may be needed for http(s) image. [Php issue 17121](https://github.com/php/php-src/issues/17121) [PR #4276](https://github.com/PHPOffice/PhpSpreadsheet/pull/4276)
- Coverage-related tweaks to Xls Reader. [PR #4277](https://github.com/PHPOffice/PhpSpreadsheet/pull/4277)
- Several fixed to ODS Writer. [Issue #4261](https://github.com/PHPOffice/PhpSpreadsheet/issues/4261) [PR #4263](https://github.com/PHPOffice/PhpSpreadsheet/pull/4263) [PR #4264](https://github.com/PHPOffice/PhpSpreadsheet/pull/4264) [PR #4266](https://github.com/PHPOffice/PhpSpreadsheet/pull/4266)
## 2024-12-08 - 2.3.4
## 2024-12-08 - 3.6.0
### Fixed
### Added
- Fix Minor Break Handling Drawings. Backport of [PR #4244](https://github.com/PHPOffice/PhpSpreadsheet/pull/4244)
- Swapped Row and Column Indexes in Reference Helper. Backport of [PR #4247](https://github.com/PHPOffice/PhpSpreadsheet/pull/4247)
- Upgrade locked version of Dompdf (Php8.4 compatibility).
- Remove unnecessary files from Composer package.
## 2024-11-22 - 2.3.3
- Nothing yet.
### Changed
- Settings::libXmlLoaderOptions is ignored. Backport of [PR #4233](https://github.com/PHPOffice/PhpSpreadsheet/pull/4233)
- Nothing yet.
### Moved
- Nothing yet.
### Deprecated
- Nothing yet.
### Fixed
- Html Reader/Writer Better Handling of Booleans. [PR #4257](https://github.com/PHPOffice/PhpSpreadsheet/pull/4257)
- Fill Patterns/Colors When Xml Attributes are Missing. [Issue #4248](https://github.com/PHPOffice/PhpSpreadsheet/issues/4248) [PR #4250](https://github.com/PHPOffice/PhpSpreadsheet/pull/4250)
- Remove Unneccesary files from Composer Package. [PR #4262](https://github.com/PHPOffice/PhpSpreadsheet/pull/4262)
- Swapped row and column indexes in ReferenceHelper. [Issue #4246](https://github.com/PHPOffice/PhpSpreadsheet/issues/4246) [PR #4247](https://github.com/PHPOffice/PhpSpreadsheet/pull/4247)
- Fix minor break handling drawings. [Issue #4241](https://github.com/PHPOffice/PhpSpreadsheet/issues/4241) [PR #4244](https://github.com/PHPOffice/PhpSpreadsheet/pull/4244)
- Ignore cell formatting when the format is a single @. [Issue #4242](https://github.com/PHPOffice/PhpSpreadsheet/issues/4242) [PR #4243](https://github.com/PHPOffice/PhpSpreadsheet/pull/4243)
- Upgrade Dompdf to Php-8.4 compatible version [PR #4267](https://github.com/PHPOffice/PhpSpreadsheet/pull/4267)
## 2024-11-22 - 3.5.0
### Added
- Nothing yet.
### Changed
- Settings::libXmlLoaderOptions is ignored. [PR #4233](https://github.com/PHPOffice/PhpSpreadsheet/pull/4233)
### Moved
- Nothing yet.
### Deprecated
- Settings::setLibXmlLoaderOptions() and Settings::getLibXmlLoaderOptions() are no longer needed - no replacement.
## 2024-11-10 - 2.3.2
- Worksheet::getHashCode is no longer needed.
### Fixed
- 2.3.1 omitted.
- Backported security patches.
- Write ignoredErrors Tag Before Drawings. Backport of [PR #4212](https://github.com/PHPOffice/PhpSpreadsheet/pull/4212) intended for 3.4.0.
- Changes to ROUNDDOWN/ROUNDUP/TRUNC. Backport of [PR #4214](https://github.com/PHPOffice/PhpSpreadsheet/pull/4214) intended for 3.4.0.
- Add support for `<s>` tag when converting HTML to RichText. [Issue #4223](https://github.com/PHPOffice/PhpSpreadsheet/issues/4223) [PR #4224](https://github.com/PHPOffice/PhpSpreadsheet/pull/4224)
- Change hash code for worksheet. [Issue #4192](https://github.com/PHPOffice/PhpSpreadsheet/issues/4192) [PR #4207](https://github.com/PHPOffice/PhpSpreadsheet/pull/4207)
## 2024-11-10 - 3.4.0
### Security Fix
- Several security patches.
### Added
- Method to Test Whether Csv Will Be Affected by Php9. Backport of [PR #4189](https://github.com/PHPOffice/PhpSpreadsheet/pull/4189) intended for 3.4.0.
## 2024-09-29 - 2.3.0
### Fixed
- Backported security patches.
- Improve Xlsx Reader speed (backport of PR #4153 intended for 3.0.0). [Issue #3917](https://github.com/PHPOffice/PhpSpreadsheet/issues/3917)
- Change to Csv Reader (see below under Deprecated). Backport of PR #4162 intended for 3.0.0. [Issue #4161](https://github.com/PHPOffice/PhpSpreadsheet/issues/4161)
- Tweak to AMORDEGRC. Backport of PR #4164 intended for 3.0.0.
- Add Dynamic valueBinder Property to Spreadsheet and Readers. [Issue #1395](https://github.com/PHPOffice/PhpSpreadsheet/issues/1395) [PR #4185](https://github.com/PHPOffice/PhpSpreadsheet/pull/4185)
- Allow Omitting Chart Border. [Issue #562](https://github.com/PHPOffice/PhpSpreadsheet/issues/562) [PR #4188](https://github.com/PHPOffice/PhpSpreadsheet/pull/4188)
- Method to Test Whether Csv Will Be Affected by Php9. [PR #4189](https://github.com/PHPOffice/PhpSpreadsheet/pull/4189)
### Changed
- Refactor Xls Reader. [PR #4118](https://github.com/PHPOffice/PhpSpreadsheet/pull/4118)
### Deprecated
- IReader::SKIP_EMPTY_CELLS - use its alias IGNORE_EMPTY_CELLS instead.
- Worksheet::getProtectedCells was deprecated in release 2, but was not properly documented, and not removed in release 3. Use getProtectedCellRanges instead.
- Writer/Html::isMpdf property was deprecated in release 2, but was not properly documented, and not removed in release 3. Use instanceof Mpdf instead.
### Moved
- Nothing yet.
### Fixed
- Xls Writer Condtional Rules Applied to Whole Rows or Columns. [Issue #3185](https://github.com/PHPOffice/PhpSpreadsheet/issues/3185) [PR #4152](https://github.com/PHPOffice/PhpSpreadsheet/pull/4152)
- Xlsx Writer Duplicate ContentTypes Entry for Background Image. [Issue #4179](https://github.com/PHPOffice/PhpSpreadsheet/issues/4179) [PR #4180](https://github.com/PHPOffice/PhpSpreadsheet/pull/4180)
- Check strictNullComparison outside of loops. [PR #3347](https://github.com/PHPOffice/PhpSpreadsheet/pull/3347)
- SUMIFS Does Not Require xlfn. [Issue #4182](https://github.com/PHPOffice/PhpSpreadsheet/issues/4182) [PR #4186](https://github.com/PHPOffice/PhpSpreadsheet/pull/4186)
- Image Transparency/Opacity with Html Reader Changes. [Discussion #4117](https://github.com/PHPOffice/PhpSpreadsheet/discussions/4117) [PR #4142](https://github.com/PHPOffice/PhpSpreadsheet/pull/4142)
- Option to Write Hyperlink Rather Than Label to Csv. [Issue #1412](https://github.com/PHPOffice/PhpSpreadsheet/issues/1412) [PR #4151](https://github.com/PHPOffice/PhpSpreadsheet/pull/4151)
- Invalid Html Due to Cached Filesize. [Issue #1107](https://github.com/PHPOffice/PhpSpreadsheet/issues/1107) [PR #4184](https://github.com/PHPOffice/PhpSpreadsheet/pull/4184)
- Excel 2003 Allows Html Entities. [Issue #2157](https://github.com/PHPOffice/PhpSpreadsheet/issues/2157) [PR #4187](https://github.com/PHPOffice/PhpSpreadsheet/pull/4187)
- Changes to ROUNDDOWN/ROUNDUP/TRUNC. [Issue #4213](https://github.com/PHPOffice/PhpSpreadsheet/issues/4213) [PR #4214](https://github.com/PHPOffice/PhpSpreadsheet/pull/4214)
- Writer Xlsx ignoredErrors Before Drawings. [Issue #4200](https://github.com/PHPOffice/PhpSpreadsheet/issues/4200) [Issue #4145](https://github.com/PHPOffice/PhpSpreadsheet/issues/4145) [PR #4212](https://github.com/PHPOffice/PhpSpreadsheet/pull/4212)
- Allow ANCHORARRAY as Data Validation list. [Issue #4197](https://github.com/PHPOffice/PhpSpreadsheet/issues/4197) [PR #4203](https://github.com/PHPOffice/PhpSpreadsheet/pull/4203)
## 2024-09-29 - 3.3.0 (no 3.0.\*, 3.1.\*, 3.2.\*)
### Dynamic Arrays
- Support for Excel dynamic arrays is added. It is an opt-in feature, so our hope is that there will be no BC breaks, but it is a very large change. Full support is added for Xlsx. It is emulated as Ctrl-Shift-Enter arrays for Ods read and write and Excel2003 and Gnumeric read. Html/Pdf and Csv writers will populate cells on output if they are the result of array formulas. No support is added for Xls or Slk.
### Added
- Excel Dynamic Arrays. [Issue #3901](https://github.com/PHPOffice/PhpSpreadsheet/issues/3901) [Issue #3659](https://github.com/PHPOffice/PhpSpreadsheet/issues/3659) [Issue #1834](https://github.com/PHPOffice/PhpSpreadsheet/issues/1834) [PR #3962](https://github.com/PHPOffice/PhpSpreadsheet/pull/3962)
- String Value Binder Allow Setting "Ignore Number Stored as Text". [PR #4141](https://github.com/PHPOffice/PhpSpreadsheet/pull/4141)
### Changed
- Xlsx Reader default datatype when none is specified in Xml is changed from string to numeric, which is how Excel treats it. There is expected to be little impact because DefaultValueBinder and AdvancedValueBinder correct mis-identification as string, and StringValueBinder usually expects string. [PR #4139](https://github.com/PHPOffice/PhpSpreadsheet/pull/4139)
- Currency and Accounting Wizards are changed to act like Excel, and a new CurrencyBase Wizard is added for for non-Excel formats. [Issue #4125](https://github.com/PHPOffice/PhpSpreadsheet/issues/4125) [Issue #4124](https://github.com/PHPOffice/PhpSpreadsheet/issues/4124) [PR #4127](https://github.com/PHPOffice/PhpSpreadsheet/pull/4127)
- Images will not be added to spreadsheet if they cannot be validated as images.
### Deprecated
- Php8.4 will deprecate the escape parameter of fgetcsv. Csv Reader is affected by this; code is changed to be unaffected, but this will mean a breaking change is coming with Php9. Any code which uses the default escape value of backslash will fail in Php9. It is recommended to explicitly set the escape value to null string before then.
- Nothing yet.
### Removed
- The following items were deprecated in release 2 and are now removed.
- Writer\Xls\Style\ColorMap (no longer needed).
- Reader\Xml::trySimpleXMLLoadString (should not have been public, no public replacement).
- Calculation\Calculation::_translateFormulaToLocale (use method name translateFormulaToLocale without leading underscore).
- Calculation\Calculation::_translateFormulaToEnglish (use method name translateFormulaToEnglish without leading underscore).
### Moved
- Nothing yet.
### Fixed
- Several security patches.
- Xls Reader Some Ranges Not Handled Properly. [Issue #1570](https://github.com/PHPOffice/PhpSpreadsheet/issues/1570) [PR #4140](https://github.com/PHPOffice/PhpSpreadsheet/pull/4140)
- Better Handling of legacyDrawing Xml. [Issue #4105](https://github.com/PHPOffice/PhpSpreadsheet/issues/4105) [PR #4122](https://github.com/PHPOffice/PhpSpreadsheet/pull/4122)
- Improve Xlsx Reader Speed. [Issue #3917](https://github.com/PHPOffice/PhpSpreadsheet/issues/3917) [PR #4153](https://github.com/PHPOffice/PhpSpreadsheet/pull/4153)
## 2024-08-07 - 2.2.2

View File

@@ -4,10 +4,11 @@ If you would like to contribute, here are some notes and guidelines:
- All new development should be on feature/fix branches, which are then merged to the `master` branch once stable and approved; so the `master` branch is always the most up-to-date, working code
- If you are going to submit a pull request, please fork from `master`, and submit your pull request back as a fix/feature branch referencing the GitHub issue number
- Install (development) dependencies by running `composer install` inside your PhpSpreadsheet clone.
- The code must work with all PHP versions that we support.
- You can call `composer versions` to test version compatibility.
- Code style should be maintained.
- `composer style` will identify any issues with Coding Style`.
- `composer style` will identify any issues with Coding Style.
- `composer fix` will fix most issues with Coding Style.
- All code changes must be validated by `composer check`.
- Please include Unit Tests to verify that a bug exists, and that this PR fixes it.
@@ -39,7 +40,10 @@ This makes it easier to see exactly what is being tested when reviewing the PR.
2. Tag subject must be the version number, eg: `1.2.3`
3. Tag body must be a copy-paste of the changelog entries.
3. Push the tag with `git push --tags`, GitHub Actions will create a GitHub release automatically, and the release details will automatically be sent to packagist.
4. Github seems to remove markdown headings in the Release Notes, so you should edit to restore these.
> **Note:** Tagged releases are made from the `master` branch. Only in an emergency should a tagged release be made from the `release` branch. (i.e. cherry-picked hot-fixes.)
4. By default, Github removes markdown headings in the Release Notes. You can either edit to restore these, or, probably preferably, change the default comment character on your system - `git config core.commentChar ";"`.
> **Note:** Tagged releases are made from the `master` branch. Only in an emergency should a tagged release be made from the `release` branch. (i.e. cherry-picked hot-fixes.) However, there are 4 branches which have been updated to apply security patches, and those may be tagged if future security updates are needed.
- release1291 (no further updates aside from security patches, including code changes needed for Php 8.5 compatibility)
- release210 (no further updates aside from security patches, including code changes needed for Php 8.5 compatibility)
- release222
- release390

View File

@@ -1,8 +1,7 @@
# PhpSpreadsheet
[![Build Status](https://github.com/PHPOffice/PhpSpreadsheet/workflows/main/badge.svg)](https://github.com/PHPOffice/PhpSpreadsheet/actions)
[![Code Quality](https://scrutinizer-ci.com/g/PHPOffice/PhpSpreadsheet/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/PHPOffice/PhpSpreadsheet/?branch=master)
[![Code Coverage](https://scrutinizer-ci.com/g/PHPOffice/PhpSpreadsheet/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/PHPOffice/PhpSpreadsheet/?branch=master)
[![Code Coverage](https://coveralls.io/repos/github/PHPOffice/PhpSpreadsheet/badge.svg?branch=master)](https://coveralls.io/github/PHPOffice/PhpSpreadsheet?branch=master)
[![Total Downloads](https://img.shields.io/packagist/dt/PHPOffice/PhpSpreadsheet)](https://packagist.org/packages/phpoffice/phpspreadsheet)
[![Latest Stable Version](https://img.shields.io/github/v/release/PHPOffice/PhpSpreadsheet)](https://packagist.org/packages/phpoffice/phpspreadsheet)
[![License](https://img.shields.io/github/license/PHPOffice/PhpSpreadsheet)](https://packagist.org/packages/phpoffice/phpspreadsheet)
@@ -11,6 +10,17 @@
PhpSpreadsheet is a library written in pure PHP and offers a set of classes that
allow you to read and write various spreadsheet file formats such as Excel and LibreOffice Calc.
This is the master branch, and is maintained for security and bug fixes.
## PHP Version Support
LTS: For maintained branches, support for PHP versions will only be maintained for a period of six months beyond the
[end of life](https://www.php.net/supported-versions) of that PHP version.
Currently the required PHP minimum version is PHP __8.1__, and we [will support that version](https://www.php.net/supported-versions.php) until 30th June 2026.
See the `composer.json` for other requirements.
## Installation
See the [install instructions](https://phpspreadsheet.readthedocs.io/en/latest/#installation).

View File

@@ -15,6 +15,7 @@
"platform": {
"php" : "8.1.99"
},
"process-timeout": 600,
"sort-packages": true,
"allow-plugins": {
"dealerdirect/phpcodesniffer-composer-installer": true
@@ -45,12 +46,12 @@
],
"scripts": {
"check": [
"./bin/check-phpdoc-types",
"php bin/check-phpdoc-types.php",
"phpcs samples/ src/ tests/ --report=checkstyle",
"phpcs samples/ src/ tests/ --standard=PHPCompatibility --runtime-set testVersion 8.0- -n",
"phpcs samples/ src/ tests/ --standard=PHPCompatibility --runtime-set testVersion 8.0- --exclude=PHPCompatibility.Variables.ForbiddenThisUseContexts -n",
"php-cs-fixer fix --ansi --dry-run --diff",
"phpunit --color=always",
"phpstan analyse --ansi --memory-limit=2048M"
"phpstan analyse --ansi --memory-limit=2048M",
"phpunit --color=always"
],
"style": [
"phpcs samples/ src/ tests/ --report=checkstyle",
@@ -61,7 +62,7 @@
"php-cs-fixer fix"
],
"versions": [
"phpcs samples/ src/ tests/ --standard=PHPCompatibility --runtime-set testVersion 8.0- -n"
"phpcs samples/ src/ tests/ --standard=PHPCompatibility --runtime-set testVersion 8.0- --exclude=PHPCompatibility.Variables.ForbiddenThisUseContexts -n"
]
},
"require": {
@@ -79,7 +80,7 @@
"ext-xmlwriter": "*",
"ext-zip": "*",
"ext-zlib": "*",
"composer/pcre": "^1 || ^2 || ^3",
"composer/pcre": "^1||^2||^3",
"maennchen/zipstream-php": "^2.1 || ^3.0",
"markbaker/complex": "^3.0",
"markbaker/matrix": "^3.0",
@@ -94,9 +95,10 @@
"mitoteam/jpgraph": "^10.3",
"mpdf/mpdf": "^8.1.1",
"phpcompatibility/php-compatibility": "^9.3",
"phpstan/phpstan": "^1.1",
"phpstan/phpstan-phpunit": "^1.0",
"phpunit/phpunit": "^9.6 || ^10.5",
"phpstan/phpstan": "^1.1 || ^2.0",
"phpstan/phpstan-phpunit": "^1.0 || ^2.0",
"phpstan/phpstan-deprecation-rules": "^1.0 || ^2.0",
"phpunit/phpunit": "^10.5",
"squizlabs/php_codesniffer": "^3.7",
"tecnickcom/tcpdf": "^6.5"
},

View File

@@ -12,21 +12,25 @@ trait ArrayEnabled
private static ArrayArgumentHelper $arrayArgumentHelper;
/**
* @param array|false $arguments Can be changed to array for Php8.1+
* @param mixed[] $arguments
*/
private static function initialiseHelper($arguments): void
private static function initialiseHelper(array $arguments): void
{
if (self::$initializationNeeded === true) {
self::$arrayArgumentHelper = new ArrayArgumentHelper();
self::$initializationNeeded = false;
}
self::$arrayArgumentHelper->initialise(($arguments === false) ? [] : $arguments);
self::$arrayArgumentHelper->initialise($arguments);
}
/**
* Handles array argument processing when the function accepts a single argument that can be an array argument.
* Example use for:
* DAYOFMONTH() or FACT().
*
* @param mixed[] $values
*
* @return mixed[]
*/
protected static function evaluateSingleArgumentArray(callable $method, array $values): array
{
@@ -43,6 +47,8 @@ trait ArrayEnabled
* and any of them can be an array argument.
* Example use for:
* ROUND() or DATE().
*
* @return mixed[]
*/
protected static function evaluateArrayArguments(callable $method, mixed ...$arguments): array
{
@@ -58,6 +64,8 @@ trait ArrayEnabled
* Example use for:
* NETWORKDAYS() or CONCATENATE(), where the last argument is a matrix (or a series of values) that need
* to be treated as a such rather than as an array arguments.
*
* @return mixed[]
*/
protected static function evaluateArrayArgumentsSubset(callable $method, int $limit, mixed ...$arguments): array
{
@@ -80,6 +88,8 @@ trait ArrayEnabled
* Example use for:
* Z.TEST() or INDEX(), where the first argument 1 is a matrix that needs to be treated as a dataset
* rather than as an array argument.
*
* @return mixed[]
*/
protected static function evaluateArrayArgumentsSubsetFrom(callable $method, int $start, mixed ...$arguments): array
{
@@ -105,6 +115,8 @@ trait ArrayEnabled
* Example use for:
* HLOOKUP() and VLOOKUP(), where argument 1 is a matrix that needs to be treated as a database
* rather than as an array argument.
*
* @return mixed[]
*/
protected static function evaluateArrayArgumentsIgnore(callable $method, int $ignore, mixed ...$arguments): array
{

View File

@@ -14,13 +14,15 @@ class BinaryComparison
/**
* Compare two strings in the same way as strcmp() except that lowercase come before uppercase letters.
*
* @param null|string $str1 First string value for the comparison
* @param null|string $str2 Second string value for the comparison
* @param mixed $str1 First string value for the comparison, expect ?string
* @param mixed $str2 Second string value for the comparison, expect ?string
*/
private static function strcmpLowercaseFirst(?string $str1, ?string $str2): int
private static function strcmpLowercaseFirst(mixed $str1, mixed $str2): int
{
$inversedStr1 = StringHelper::strCaseReverse($str1 ?? '');
$inversedStr2 = StringHelper::strCaseReverse($str2 ?? '');
$str1 = StringHelper::convertToString($str1);
$str2 = StringHelper::convertToString($str2);
$inversedStr1 = StringHelper::strCaseReverse($str1);
$inversedStr2 = StringHelper::strCaseReverse($str2);
return strcmp($inversedStr1, $inversedStr2);
}
@@ -28,12 +30,15 @@ class BinaryComparison
/**
* PHP8.1 deprecates passing null to strcmp.
*
* @param null|string $str1 First string value for the comparison
* @param null|string $str2 Second string value for the comparison
* @param mixed $str1 First string value for the comparison, expect ?string
* @param mixed $str2 Second string value for the comparison, expect ?string
*/
private static function strcmpAllowNull(?string $str1, ?string $str2): int
private static function strcmpAllowNull(mixed $str1, mixed $str2): int
{
return strcmp($str1 ?? '', $str2 ?? '');
$str1 = StringHelper::convertToString($str1);
$str2 = StringHelper::convertToString($str2);
return strcmp($str1, $str2);
}
public static function compare(mixed $operand1, mixed $operand2, string $operator): bool

View File

@@ -18,4 +18,5 @@ abstract class Category
const CATEGORY_TEXT_AND_DATA = 'Text and Data';
const CATEGORY_WEB = 'Web';
const CATEGORY_UNCATEGORISED = 'Uncategorised';
const CATEGORY_MICROSOFT_INTERNAL = 'MS Internal';
}

View File

@@ -19,12 +19,12 @@ class DAverage extends DatabaseAbstract
* A database is a list of related data in which rows of related
* information are records, and columns of data are fields. The
* first row of the list contains labels for each column.
* @param null|array|int|string $field Indicates which column is used in the function. Enter the
* @param null|array<mixed>|int|string $field Indicates which column is used in the function. Enter the
* column label enclosed between double quotation marks, such as
* "Age" or "Yield," or a number (without quotation marks) that
* represents the position of the column within the list: 1 for
* the first column, 2 for the second column, and so on.
* @param mixed[] $criteria The range of cells that contains the conditions you specify.
* @param mixed[][] $criteria The range of cells that contains the conditions you specify.
* You can use any range for the criteria argument, as long as it
* includes at least one column label and at least one cell below
* the column label in which you specify a condition for the

View File

@@ -20,12 +20,12 @@ class DCount extends DatabaseAbstract
* A database is a list of related data in which rows of related
* information are records, and columns of data are fields. The
* first row of the list contains labels for each column.
* @param null|array|int|string $field Indicates which column is used in the function. Enter the
* @param null|array<mixed>|int|string $field Indicates which column is used in the function. Enter the
* column label enclosed between double quotation marks, such as
* "Age" or "Yield," or a number (without quotation marks) that
* represents the position of the column within the list: 1 for
* the first column, 2 for the second column, and so on.
* @param mixed[] $criteria The range of cells that contains the conditions you specify.
* @param mixed[][] $criteria The range of cells that contains the conditions you specify.
* You can use any range for the criteria argument, as long as it
* includes at least one column label and at least one cell below
* the column label in which you specify a condition for the

View File

@@ -19,12 +19,12 @@ class DCountA extends DatabaseAbstract
* A database is a list of related data in which rows of related
* information are records, and columns of data are fields. The
* first row of the list contains labels for each column.
* @param null|array|int|string $field Indicates which column is used in the function. Enter the
* @param null|array<mixed>|int|string $field Indicates which column is used in the function. Enter the
* column label enclosed between double quotation marks, such as
* "Age" or "Yield," or a number (without quotation marks) that
* represents the position of the column within the list: 1 for
* the first column, 2 for the second column, and so on.
* @param mixed[] $criteria The range of cells that contains the conditions you specify.
* @param mixed[][] $criteria The range of cells that contains the conditions you specify.
* You can use any range for the criteria argument, as long as it
* includes at least one column label and at least one cell below
* the column label in which you specify a condition for the

View File

@@ -19,12 +19,12 @@ class DGet extends DatabaseAbstract
* A database is a list of related data in which rows of related
* information are records, and columns of data are fields. The
* first row of the list contains labels for each column.
* @param null|array|int|string $field Indicates which column is used in the function. Enter the
* @param null|array<mixed>|int|string $field Indicates which column is used in the function. Enter the
* column label enclosed between double quotation marks, such as
* "Age" or "Yield," or a number (without quotation marks) that
* represents the position of the column within the list: 1 for
* the first column, 2 for the second column, and so on.
* @param mixed[] $criteria The range of cells that contains the conditions you specify.
* @param mixed[][] $criteria The range of cells that contains the conditions you specify.
* You can use any range for the criteria argument, as long as it
* includes at least one column label and at least one cell below
* the column label in which you specify a condition for the
@@ -42,6 +42,7 @@ class DGet extends DatabaseAbstract
return ExcelError::NAN();
}
/** @var array<null|float|int|string> */
$row = array_pop($columnData);
return array_pop($row);

View File

@@ -20,12 +20,12 @@ class DMax extends DatabaseAbstract
* A database is a list of related data in which rows of related
* information are records, and columns of data are fields. The
* first row of the list contains labels for each column.
* @param null|array|int|string $field Indicates which column is used in the function. Enter the
* @param null|array<mixed>|int|string $field Indicates which column is used in the function. Enter the
* column label enclosed between double quotation marks, such as
* "Age" or "Yield," or a number (without quotation marks) that
* represents the position of the column within the list: 1 for
* the first column, 2 for the second column, and so on.
* @param mixed[] $criteria The range of cells that contains the conditions you specify.
* @param mixed[][] $criteria The range of cells that contains the conditions you specify.
* You can use any range for the criteria argument, as long as it
* includes at least one column label and at least one cell below
* the column label in which you specify a condition for the

View File

@@ -20,12 +20,12 @@ class DMin extends DatabaseAbstract
* A database is a list of related data in which rows of related
* information are records, and columns of data are fields. The
* first row of the list contains labels for each column.
* @param null|array|int|string $field Indicates which column is used in the function. Enter the
* @param null|array<mixed>|int|string $field Indicates which column is used in the function. Enter the
* column label enclosed between double quotation marks, such as
* "Age" or "Yield," or a number (without quotation marks) that
* represents the position of the column within the list: 1 for
* the first column, 2 for the second column, and so on.
* @param mixed[] $criteria The range of cells that contains the conditions you specify.
* @param mixed[][] $criteria The range of cells that contains the conditions you specify.
* You can use any range for the criteria argument, as long as it
* includes at least one column label and at least one cell below
* the column label in which you specify a condition for the

View File

@@ -19,12 +19,12 @@ class DProduct extends DatabaseAbstract
* A database is a list of related data in which rows of related
* information are records, and columns of data are fields. The
* first row of the list contains labels for each column.
* @param null|array|int|string $field Indicates which column is used in the function. Enter the
* @param null|array<mixed>|int|string $field Indicates which column is used in the function. Enter the
* column label enclosed between double quotation marks, such as
* "Age" or "Yield," or a number (without quotation marks) that
* represents the position of the column within the list: 1 for
* the first column, 2 for the second column, and so on.
* @param mixed[] $criteria The range of cells that contains the conditions you specify.
* @param mixed[][] $criteria The range of cells that contains the conditions you specify.
* You can use any range for the criteria argument, as long as it
* includes at least one column label and at least one cell below
* the column label in which you specify a condition for the

View File

@@ -20,12 +20,12 @@ class DStDev extends DatabaseAbstract
* A database is a list of related data in which rows of related
* information are records, and columns of data are fields. The
* first row of the list contains labels for each column.
* @param null|array|int|string $field Indicates which column is used in the function. Enter the
* @param null|array<mixed>|int|string $field Indicates which column is used in the function. Enter the
* column label enclosed between double quotation marks, such as
* "Age" or "Yield," or a number (without quotation marks) that
* represents the position of the column within the list: 1 for
* the first column, 2 for the second column, and so on.
* @param mixed[] $criteria The range of cells that contains the conditions you specify.
* @param mixed[][] $criteria The range of cells that contains the conditions you specify.
* You can use any range for the criteria argument, as long as it
* includes at least one column label and at least one cell below
* the column label in which you specify a condition for the

View File

@@ -20,12 +20,12 @@ class DStDevP extends DatabaseAbstract
* A database is a list of related data in which rows of related
* information are records, and columns of data are fields. The
* first row of the list contains labels for each column.
* @param null|array|int|string $field Indicates which column is used in the function. Enter the
* @param null|array<mixed>|int|string $field Indicates which column is used in the function. Enter the
* column label enclosed between double quotation marks, such as
* "Age" or "Yield," or a number (without quotation marks) that
* represents the position of the column within the list: 1 for
* the first column, 2 for the second column, and so on.
* @param mixed[] $criteria The range of cells that contains the conditions you specify.
* @param mixed[][] $criteria The range of cells that contains the conditions you specify.
* You can use any range for the criteria argument, as long as it
* includes at least one column label and at least one cell below
* the column label in which you specify a condition for the

View File

@@ -19,12 +19,12 @@ class DSum extends DatabaseAbstract
* A database is a list of related data in which rows of related
* information are records, and columns of data are fields. The
* first row of the list contains labels for each column.
* @param null|array|int|string $field Indicates which column is used in the function. Enter the
* @param null|array<mixed>|int|string $field Indicates which column is used in the function. Enter the
* column label enclosed between double quotation marks, such as
* "Age" or "Yield," or a number (without quotation marks) that
* represents the position of the column within the list: 1 for
* the first column, 2 for the second column, and so on.
* @param mixed[] $criteria The range of cells that contains the conditions you specify.
* @param mixed[][] $criteria The range of cells that contains the conditions you specify.
* You can use any range for the criteria argument, as long as it
* includes at least one column label and at least one cell below
* the column label in which you specify a condition for the

View File

@@ -20,12 +20,12 @@ class DVar extends DatabaseAbstract
* A database is a list of related data in which rows of related
* information are records, and columns of data are fields. The
* first row of the list contains labels for each column.
* @param null|array|int|string $field Indicates which column is used in the function. Enter the
* @param null|array<mixed>|int|string $field Indicates which column is used in the function. Enter the
* column label enclosed between double quotation marks, such as
* "Age" or "Yield," or a number (without quotation marks) that
* represents the position of the column within the list: 1 for
* the first column, 2 for the second column, and so on.
* @param mixed[] $criteria The range of cells that contains the conditions you specify.
* @param mixed[][] $criteria The range of cells that contains the conditions you specify.
* You can use any range for the criteria argument, as long as it
* includes at least one column label and at least one cell below
* the column label in which you specify a condition for the

View File

@@ -20,12 +20,12 @@ class DVarP extends DatabaseAbstract
* A database is a list of related data in which rows of related
* information are records, and columns of data are fields. The
* first row of the list contains labels for each column.
* @param null|array|int|string $field Indicates which column is used in the function. Enter the
* @param null|array<mixed>|int|string $field Indicates which column is used in the function. Enter the
* column label enclosed between double quotation marks, such as
* "Age" or "Yield," or a number (without quotation marks) that
* represents the position of the column within the list: 1 for
* the first column, 2 for the second column, and so on.
* @param mixed[] $criteria The range of cells that contains the conditions you specify.
* @param mixed[][] $criteria The range of cells that contains the conditions you specify.
* You can use any range for the criteria argument, as long as it
* includes at least one column label and at least one cell below
* the column label in which you specify a condition for the

View File

@@ -5,9 +5,26 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\Database;
use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Calculation\Internal\WildcardMatch;
use PhpOffice\PhpSpreadsheet\Shared\StringHelper;
abstract class DatabaseAbstract
{
/**
* @param mixed[] $database The range of cells that makes up the list or database.
* A database is a list of related data in which rows of related
* information are records, and columns of data are fields. The
* first row of the list contains labels for each column.
* @param null|array<mixed>|int|string $field Indicates which column is used in the function. Enter the
* column label enclosed between double quotation marks, such as
* "Age" or "Yield," or a number (without quotation marks) that
* represents the position of the column within the list: 1 for
* the first column, 2 for the second column, and so on.
* @param mixed[] $criteria The range of cells that contains the conditions you specify.
* You can use any range for the criteria argument, as long as it
* includes at least one column label and at least one cell below
* the column label in which you specify a condition for the
* column.
*/
abstract public static function evaluate(array $database, array|null|int|string $field, array $criteria): null|float|int|string;
/**
@@ -27,12 +44,16 @@ abstract class DatabaseAbstract
*/
protected static function fieldExtract(array $database, mixed $field): ?int
{
$field = strtoupper(Functions::flattenSingleValue($field) ?? '');
/** @var ?string */
$single = Functions::flattenSingleValue($field);
$field = strtoupper($single ?? '');
if ($field === '') {
return null;
}
$fieldNames = array_map('strtoupper', array_shift($database));
/** @var callable */
$callable = 'strtoupper';
$fieldNames = array_map($callable, array_shift($database)); //* @phpstan-ignore-line
if (is_numeric($field)) {
$field = (int) $field - 1;
if ($field < 0 || $field >= count($fieldNames)) {
@@ -56,7 +77,7 @@ abstract class DatabaseAbstract
* A database is a list of related data in which rows of related
* information are records, and columns of data are fields. The
* first row of the list contains labels for each column.
* @param mixed[] $criteria The range of cells that contains the conditions you specify.
* @param mixed[][] $criteria The range of cells that contains the conditions you specify.
* You can use any range for the criteria argument, as long as it
* includes at least one column label and at least one cell below
* the column label in which you specify a condition for the
@@ -66,16 +87,25 @@ abstract class DatabaseAbstract
*/
protected static function filter(array $database, array $criteria): array
{
/** @var mixed[] */
$fieldNames = array_shift($database);
$criteriaNames = array_shift($criteria);
// Convert the criteria into a set of AND/OR conditions with [:placeholders]
/** @var string[] $criteriaNames */
$query = self::buildQuery($criteriaNames, $criteria);
// Loop through each row of the database
/** @var mixed[][] $criteriaNames */
return self::executeQuery($database, $query, $criteriaNames, $fieldNames);
}
/**
* @param mixed[] $database The range of cells that makes up the list or database
* @param mixed[][] $criteria
*
* @return mixed[]
*/
protected static function getFilteredColumn(array $database, ?int $field, array $criteria): array
{
// reduce the database to a set of rows that match all the criteria
@@ -84,6 +114,7 @@ abstract class DatabaseAbstract
// extract an array of values for the requested column
$columnData = [];
/** @var mixed[] $row */
foreach ($database as $rowKey => $row) {
$keys = array_keys($row);
$key = $keys[$field] ?? null;
@@ -94,6 +125,10 @@ abstract class DatabaseAbstract
return $columnData;
}
/**
* @param string[] $criteriaNames
* @param mixed[][] $criteria
*/
private static function buildQuery(array $criteriaNames, array $criteria): string
{
$baseQuery = [];
@@ -108,7 +143,7 @@ abstract class DatabaseAbstract
}
$rowQuery = array_map(
fn ($rowValue): string => (count($rowValue) > 1) ? 'AND(' . implode(',', $rowValue) . ')' : ($rowValue[0] ?? ''),
fn ($rowValue): string => (count($rowValue) > 1) ? 'AND(' . implode(',', $rowValue) . ')' : ($rowValue[0] ?? ''), // @phpstan-ignore-line
$baseQuery
);
@@ -135,12 +170,21 @@ abstract class DatabaseAbstract
return $condition;
}
/**
* @param mixed[] $database
* @param mixed[][] $criteria
* @param array<mixed> $fields
*
* @return mixed[]
*/
private static function executeQuery(array $database, string $query, array $criteria, array $fields): array
{
foreach ($database as $dataRow => $dataValues) {
// Substitute actual values from the database row for our [:placeholders]
$conditions = $query;
foreach ($criteria as $criterion) {
/** @var string $criterion */
/** @var mixed[] $dataValues */
$conditions = self::processCondition($criterion, $fields, $dataValues, $conditions);
}
@@ -156,6 +200,10 @@ abstract class DatabaseAbstract
return $database;
}
/**
* @param array<mixed> $fields
* @param array<mixed> $dataValues
*/
private static function processCondition(string $criterion, array $fields, array $dataValues, string $conditions): string
{
$key = array_search($criterion, $fields, true);
@@ -169,7 +217,10 @@ abstract class DatabaseAbstract
if (is_string($dataValue) && str_contains($dataValue, '"')) {
$dataValue = str_replace('"', '""', $dataValue);
}
$dataValue = (is_string($dataValue)) ? Calculation::wrapResult(strtoupper($dataValue)) : $dataValue;
if (is_string($dataValue)) {
$dataValue = Calculation::wrapResult(strtoupper($dataValue));
}
$dataValue = StringHelper::convertToString($dataValue);
}
return str_replace('[:' . $criterion . ']', $dataValue, $conditions);

View File

@@ -28,7 +28,7 @@ class Date
* A Month name or abbreviation (English only at this point) such as 'January' or 'Jan' will still be accepted,
* as will a day value with a suffix (e.g. '21st' rather than simply 21); again only English language.
*
* @param array|float|int|string $year The value of the year argument can include one to four digits.
* @param array<mixed>|float|int|string $year The value of the year argument can include one to four digits.
* Excel interprets the year argument according to the configured
* date system: 1900 or 1904.
* If year is between 0 (zero) and 1899 (inclusive), Excel adds that
@@ -39,7 +39,7 @@ class Date
* 2008.
* If year is less than 0 or is 10000 or greater, Excel returns the
* #NUM! error value.
* @param array|float|int|string $month A positive or negative integer representing the month of the year
* @param array<mixed>|float|int|string $month A positive or negative integer representing the month of the year
* from 1 to 12 (January to December).
* If month is greater than 12, month adds that number of months to
* the first month in the year specified. For example, DATE(2008,14,2)
@@ -48,7 +48,7 @@ class Date
* number of months, plus 1, from the first month in the year
* specified. For example, DATE(2008,-3,2) returns the serial number
* representing September 2, 2007.
* @param array|float|int|string $day A positive or negative integer representing the day of the month
* @param array<mixed>|float|int|string $day A positive or negative integer representing the day of the month
* from 1 to 31.
* If day is greater than the number of days in the month specified,
* day adds that number of days to the first day in the month. For
@@ -59,12 +59,12 @@ class Date
* example, DATE(2008,1,-15) returns the serial number representing
* December 16, 2007.
*
* @return array|DateTime|float|int|string Excel date/time serial value, PHP date/time serial value or PHP date/time object,
* @return array<mixed>|DateTime|float|int|string Excel date/time serial value, PHP date/time serial value or PHP date/time object,
* depending on the value of the ReturnDateType flag
* If an array of numbers is passed as the argument, then the returned result will also be an array
* with the same dimensions
*/
public static function fromYMD(array|float|int|string $year, array|float|int|string $month, array|float|int|string $day): float|int|DateTime|string|array
public static function fromYMD(array|float|int|string $year, null|array|bool|float|int|string $month, array|float|int|string $day): float|int|DateTime|string|array
{
if (is_array($year) || is_array($month) || is_array($day)) {
return self::evaluateArrayArguments([self::class, __FUNCTION__], $year, $month, $day);
@@ -92,7 +92,11 @@ class Date
*/
private static function getYear(mixed $year, int $baseYear): int
{
$year = ($year !== null) ? StringHelper::testStringAsNumeric((string) $year) : 0;
if ($year === null) {
$year = 0;
} elseif (is_scalar($year)) {
$year = StringHelper::testStringAsNumeric((string) $year);
}
if (!is_numeric($year)) {
throw new Exception(ExcelError::VALUE());
}
@@ -117,11 +121,15 @@ class Date
*/
private static function getMonth(mixed $month): int
{
if (($month !== null) && (!is_numeric($month))) {
$month = SharedDateHelper::monthStringToNumber($month);
if (is_string($month)) {
if (!is_numeric($month)) {
$month = SharedDateHelper::monthStringToNumber($month);
}
} elseif ($month === null) {
$month = 0;
} elseif (is_bool($month)) {
$month = (int) $month;
}
$month = ($month !== null) ? StringHelper::testStringAsNumeric((string) $month) : 0;
if (!is_numeric($month)) {
throw new Exception(ExcelError::VALUE());
}
@@ -134,11 +142,15 @@ class Date
*/
private static function getDay(mixed $day): int
{
if (($day !== null) && (!is_numeric($day))) {
if (is_string($day) && !is_numeric($day)) {
$day = SharedDateHelper::dayStringToNumber($day);
}
$day = ($day !== null) ? StringHelper::testStringAsNumeric((string) $day) : 0;
if ($day === null) {
$day = 0;
} elseif (is_scalar($day)) {
$day = StringHelper::testStringAsNumeric((string) $day);
}
if (!is_numeric($day)) {
throw new Exception(ExcelError::VALUE());
}
@@ -151,11 +163,11 @@ class Date
if ($month < 1) {
// Handle year/month adjustment if month < 1
--$month;
$year += ceil($month / 12) - 1;
$year += (int) (ceil($month / 12) - 1);
$month = 13 - abs($month % 12);
} elseif ($month > 12) {
// Handle year/month adjustment if month > 12
$year += floor($month / 12);
$year += intdiv($month, 12);
$month = ($month % 12);
}

View File

@@ -24,7 +24,7 @@ class DateParts
* PHP DateTime object, or a standard date string
* Or can be an array of date values
*
* @return array|int|string Day of the month
* @return array<mixed>|int|string Day of the month
* If an array of numbers is passed as the argument, then the returned result will also be an array
* with the same dimensions
*/
@@ -65,7 +65,7 @@ class DateParts
* PHP DateTime object, or a standard date string
* Or can be an array of date values
*
* @return array|int|string Month of the year
* @return array<mixed>|int|string Month of the year
* If an array of numbers is passed as the argument, then the returned result will also be an array
* with the same dimensions
*/
@@ -104,7 +104,7 @@ class DateParts
* PHP DateTime object, or a standard date string
* Or can be an array of date values
*
* @return array|int|string Year
* @return array<mixed>|int|string Year
* If an array of numbers is passed as the argument, then the returned result will also be an array
* with the same dimensions
*/

View File

@@ -25,7 +25,7 @@ class DateValue
* Excel Function:
* DATEVALUE(dateValue)
*
* @param null|array|bool|float|int|string $dateValue Text that represents a date in a Microsoft Excel date format.
* @param null|array<mixed>|bool|float|int|string $dateValue Text that represents a date in a Microsoft Excel date format.
* For example, "1/30/2008" or "30-Jan-2008" are text strings within
* quotation marks that represent dates. Using the default date
* system in Excel for Windows, date_text must represent a date from
@@ -35,7 +35,7 @@ class DateValue
* #VALUE! error value if date_text is out of this range.
* Or can be an array of date values
*
* @return array|DateTime|float|int|string Excel date/time serial value, PHP date/time serial value or PHP date/time object,
* @return array<mixed>|DateTime|float|int|string Excel date/time serial value, PHP date/time serial value or PHP date/time object,
* depending on the value of the ReturnDateType flag
* If an array of numbers is passed as the argument, then the returned result will also be an array
* with the same dimensions
@@ -47,7 +47,7 @@ class DateValue
}
// try to parse as date iff there is at least one digit
if (is_string($dateValue) && preg_match('/\\d/', $dateValue) !== 1) {
if (is_string($dateValue) && preg_match('/\d/', $dateValue) !== 1) {
return ExcelError::VALUE();
}
@@ -86,6 +86,7 @@ class DateValue
return self::finalResults($PHPDateArray, $dti, $baseYear);
}
/** @param mixed[] $t1 */
private static function t1ToString(array $t1, DateTimeImmutable $dti, bool $yearFound): string
{
if (count($t1) == 2) {
@@ -108,6 +109,8 @@ class DateValue
/**
* Parse date.
*
* @return mixed[]
*/
private static function setUpArray(string $dateValue, DateTimeImmutable $dti): array
{
@@ -132,6 +135,8 @@ class DateValue
/**
* Final results.
*
* @param mixed[] $PHPDateArray
*
* @return DateTime|float|int|string Excel date/time serial value, PHP date/time serial value or PHP date/time object,
* depending on the value of the ReturnDateType flag
*/
@@ -139,6 +144,7 @@ class DateValue
{
$retValue = ExcelError::Value();
if (Helpers::dateParseSucceeded($PHPDateArray)) {
/** @var array{year: int, month: int, day: int, hour: int, minute: int, second: int} $PHPDateArray */
// Execute function
Helpers::replaceIfEmpty($PHPDateArray['year'], $dti->format('Y'));
if ($PHPDateArray['year'] < $baseYear) {
@@ -146,12 +152,13 @@ class DateValue
}
Helpers::replaceIfEmpty($PHPDateArray['month'], $dti->format('m'));
Helpers::replaceIfEmpty($PHPDateArray['day'], $dti->format('d'));
/** @var array{year: int, month: int, day: int, hour: int, minute: int, second: int} $PHPDateArray */
$PHPDateArray['hour'] = 0;
$PHPDateArray['minute'] = 0;
$PHPDateArray['second'] = 0;
$month = (int) $PHPDateArray['month'];
$day = (int) $PHPDateArray['day'];
$year = (int) $PHPDateArray['year'];
$month = self::getInt($PHPDateArray, 'month');
$day = self::getInt($PHPDateArray, 'day');
$year = self::getInt($PHPDateArray, 'year');
if (!checkdate($month, $day, $year)) {
return ($year === 1900 && $month === 2 && $day === 29) ? Helpers::returnIn3FormatsFloat(60.0) : ExcelError::VALUE();
}
@@ -160,4 +167,10 @@ class DateValue
return $retValue;
}
/** @param mixed[] $array */
private static function getInt(array $array, string $index): int
{
return (array_key_exists($index, $array) && is_numeric($array[$index])) ? (int) $array[$index] : 0;
}
}

View File

@@ -20,14 +20,14 @@ class Days
* Excel Function:
* DAYS(endDate, startDate)
*
* @param array|DateTimeInterface|float|int|string $endDate Excel date serial value (float),
* @param array<mixed>|DateTimeInterface|float|int|string $endDate Excel date serial value (float),
* PHP date timestamp (integer), PHP DateTime object, or a standard date string
* Or can be an array of date values
* @param array|DateTimeInterface|float|int|string $startDate Excel date serial value (float),
* @param array<mixed>|DateTimeInterface|float|int|string $startDate Excel date serial value (float),
* PHP date timestamp (integer), PHP DateTime object, or a standard date string
* Or can be an array of date values
*
* @return array|int|string Number of days between start date and end date or an error
* @return array<mixed>|int|string Number of days between start date and end date or an error
* If an array of values is passed for the $startDate or $endDays,arguments, then the returned result
* will also be an array with matching dimensions
*/
@@ -50,7 +50,7 @@ class Days
$days = ExcelError::VALUE();
$diff = $PHPStartDateObject->diff($PHPEndDateObject);
if ($diff !== false && !is_bool($diff->days)) {
if (!is_bool($diff->days)) {
$days = $diff->days;
if ($diff->invert) {
$days = -$days;

View File

@@ -40,7 +40,7 @@ class Days360
* same month.
* Or can be an array of methods
*
* @return array|int|string Number of days between start date and end date
* @return array<mixed>|int|string Number of days between start date and end date
* If an array of values is passed for the $startDate or $endDays,arguments, then the returned result
* will also be an array with matching dimensions
*/

View File

@@ -22,9 +22,9 @@ class Difference
* @param mixed $endDate Excel date serial value, PHP date/time stamp, PHP DateTime object
* or a standard date string
* Or can be an array of date values
* @param array|string $unit Or can be an array of unit values
* @param array<mixed>|string $unit Or can be an array of unit values
*
* @return array|int|string Interval between the dates
* @return array<mixed>|int|string Interval between the dates
* If an array of values is passed for the $startDate or $endDays,arguments, then the returned result
* will also be an array with matching dimensions
*/

View File

@@ -44,7 +44,9 @@ class Helpers
if (!is_numeric($dateValue)) {
$saveReturnDateType = Functions::getReturnDateType();
Functions::setReturnDateType(Functions::RETURNDATE_EXCEL);
$dateValue = DateValue::fromString($dateValue);
if (is_string($dateValue)) {
$dateValue = DateValue::fromString($dateValue);
}
Functions::setReturnDateType($saveReturnDateType);
if (!is_numeric($dateValue)) {
throw new Exception(ExcelError::VALUE());
@@ -75,8 +77,10 @@ class Helpers
/**
* Adjust date by given months.
*
* @param float|int $dateValue date to be adjusted
*/
public static function adjustDateByMonths(mixed $dateValue = 0, float $adjustmentMonths = 0): DateTime
public static function adjustDateByMonths($dateValue = 0, float $adjustmentMonths = 0): DateTime
{
// Execute function
$PHPDateObject = SharedDateHelper::excelToDateTimeObject($dateValue);
@@ -119,7 +123,7 @@ class Helpers
if (!is_numeric($testVal1) || $testVal1 < 31) {
if (!is_numeric($testVal2) || $testVal2 < 12) {
if (is_numeric($testVal3) && $testVal3 < 12) {
$testVal3 += 2000;
$testVal3 = (string) ($testVal3 + 2000);
}
}
}
@@ -127,6 +131,8 @@ class Helpers
/**
* Return result in one of three formats.
*
* @param array{year: int, month: int, day: int, hour: int, minute: int, second: int} $dateArray
*/
public static function returnIn3FormatsArray(array $dateArray, bool $noFrac = false): DateTime|float|int
{
@@ -264,11 +270,16 @@ class Helpers
}
}
/** @return array{year: int, month: int, day: int, hour: int, minute: int, second: int} */
public static function dateParse(string $string): array
{
return self::forceArray(date_parse($string));
/** @var array{year: int, month: int, day: int, hour: int, minute: int, second: int} */
$temp = self::forceArray(date_parse($string));
return $temp;
}
/** @param mixed[] $dateArray */
public static function dateParseSucceeded(array $dateArray): bool
{
return $dateArray['error_count'] === 0;
@@ -278,10 +289,19 @@ class Helpers
* Despite documentation, date_parse probably never returns false.
* Just in case, this routine helps guarantee it.
*
* @param array|false $dateArray
* @param array<mixed>|false $dateArray
*
* @return mixed[]
*/
private static function forceArray(array|bool $dateArray): array
{
return is_array($dateArray) ? $dateArray : ['error_count' => 1];
}
public static function floatOrInt(mixed $value): float|int
{
$result = Functions::scalar($value);
return is_numeric($result) ? ($result + 0) : 0;
}
}

View File

@@ -24,12 +24,12 @@ class Month
* @param mixed $dateValue Excel date serial value (float), PHP date timestamp (integer),
* PHP DateTime object, or a standard date string
* Or can be an array of date values
* @param array|int $adjustmentMonths The number of months before or after start_date.
* @param array<mixed>|int $adjustmentMonths The number of months before or after start_date.
* A positive value for months yields a future date;
* a negative value yields a past date.
* Or can be an array of adjustment values
*
* @return array|DateTime|float|int|string Excel date/time serial value, PHP date/time serial value or PHP date/time object,
* @return array<mixed>|DateTime|float|int|string Excel date/time serial value, PHP date/time serial value or PHP date/time object,
* depending on the value of the ReturnDateType flag
* If an array of values is passed as the argument, then the returned result will also be an array
* with the same dimensions
@@ -68,12 +68,12 @@ class Month
* @param mixed $dateValue Excel date serial value (float), PHP date timestamp (integer),
* PHP DateTime object, or a standard date string
* Or can be an array of date values
* @param array|int $adjustmentMonths The number of months before or after start_date.
* @param array<mixed>|int $adjustmentMonths The number of months before or after start_date.
* A positive value for months yields a future date;
* a negative value yields a past date.
* Or can be an array of adjustment values
*
* @return array|DateTime|float|int|string Excel date/time serial value, PHP date/time serial value or PHP date/time object,
* @return array<mixed>|DateTime|float|int|string Excel date/time serial value, PHP date/time serial value or PHP date/time object,
* depending on the value of the ReturnDateType flag
* If an array of values is passed as the argument, then the returned result will also be an array
* with the same dimensions

View File

@@ -29,7 +29,7 @@ class NetworkDays
* Or can be an array of date values
* @param mixed $dateArgs An array of dates (such as holidays) to exclude from the calculation
*
* @return array|int|string Interval between the dates
* @return array<mixed>|int|string Interval between the dates
* If an array of values is passed for the $startDate or $endDate arguments, then the returned result
* will also be an array with matching dimensions
*/

View File

@@ -24,21 +24,21 @@ class Time
* Excel Function:
* TIME(hour,minute,second)
*
* @param null|array|bool|float|int|string $hour A number from 0 (zero) to 32767 representing the hour.
* @param null|array<mixed>|bool|float|int|string $hour A number from 0 (zero) to 32767 representing the hour.
* Any value greater than 23 will be divided by 24 and the remainder
* will be treated as the hour value. For example, TIME(27,0,0) =
* TIME(3,0,0) = .125 or 3:00 AM.
* @param null|array|bool|float|int|string $minute A number from 0 to 32767 representing the minute.
* @param null|array<mixed>|bool|float|int|string $minute A number from 0 to 32767 representing the minute.
* Any value greater than 59 will be converted to hours and minutes.
* For example, TIME(0,750,0) = TIME(12,30,0) = .520833 or 12:30 PM.
* @param null|array|bool|float|int|string $second A number from 0 to 32767 representing the second.
* @param null|array<mixed>|bool|float|int|string $second A number from 0 to 32767 representing the second.
* Any value greater than 59 will be converted to hours, minutes,
* and seconds. For example, TIME(0,0,2000) = TIME(0,33,22) = .023148
* or 12:33:20 AM
* If an array of numbers is passed as the argument, then the returned result will also be an array
* with the same dimensions
*
* @return array|DateTime|float|int|string Excel date/time serial value, PHP date/time serial value or PHP date/time object,
* @return array<mixed>|DateTime|float|int|string Excel date/time serial value, PHP date/time serial value or PHP date/time object,
* depending on the value of the ReturnDateType flag
* If an array of numbers is passed as the argument, then the returned result will also be an array
* with the same dimensions
@@ -87,13 +87,13 @@ class Time
private static function adjustSecond(int &$second, int &$minute): void
{
if ($second < 0) {
$minute += floor($second / 60);
$minute += (int) floor($second / 60);
$second = 60 - abs($second % 60);
if ($second == 60) {
$second = 0;
}
} elseif ($second >= 60) {
$minute += floor($second / 60);
$minute += intdiv($second, 60);
$second = $second % 60;
}
}
@@ -101,13 +101,13 @@ class Time
private static function adjustMinute(int &$minute, int &$hour): void
{
if ($minute < 0) {
$hour += floor($minute / 60);
$hour += (int) floor($minute / 60);
$minute = 60 - abs($minute % 60);
if ($minute == 60) {
$minute = 0;
}
} elseif ($minute >= 60) {
$hour += floor($minute / 60);
$hour += intdiv($minute, 60);
$minute = $minute % 60;
}
}

View File

@@ -23,7 +23,7 @@ class TimeParts
* PHP DateTime object, or a standard time string
* Or can be an array of date/time values
*
* @return array|int|string Hour
* @return array<mixed>|int|string Hour
* If an array of numbers is passed as the argument, then the returned result will also be an array
* with the same dimensions
*/
@@ -35,7 +35,7 @@ class TimeParts
try {
Helpers::nullFalseTrueToNumber($timeValue);
if (!is_numeric($timeValue)) {
if (is_string($timeValue) && !is_numeric($timeValue)) {
$timeValue = Helpers::getTimeValue($timeValue);
}
Helpers::validateNotNegative($timeValue);
@@ -64,7 +64,7 @@ class TimeParts
* PHP DateTime object, or a standard time string
* Or can be an array of date/time values
*
* @return array|int|string Minute
* @return array<mixed>|int|string Minute
* If an array of numbers is passed as the argument, then the returned result will also be an array
* with the same dimensions
*/
@@ -76,7 +76,7 @@ class TimeParts
try {
Helpers::nullFalseTrueToNumber($timeValue);
if (!is_numeric($timeValue)) {
if (is_string($timeValue) && !is_numeric($timeValue)) {
$timeValue = Helpers::getTimeValue($timeValue);
}
Helpers::validateNotNegative($timeValue);
@@ -105,7 +105,7 @@ class TimeParts
* PHP DateTime object, or a standard time string
* Or can be an array of date/time values
*
* @return array|int|string Second
* @return array<mixed>|int|string Second
* If an array of numbers is passed as the argument, then the returned result will also be an array
* with the same dimensions
*/
@@ -117,7 +117,7 @@ class TimeParts
try {
Helpers::nullFalseTrueToNumber($timeValue);
if (!is_numeric($timeValue)) {
if (is_string($timeValue) && !is_numeric($timeValue)) {
$timeValue = Helpers::getTimeValue($timeValue);
}
Helpers::validateNotNegative($timeValue);

View File

@@ -2,6 +2,7 @@
namespace PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel;
use Composer\Pcre\Preg;
use Datetime;
use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
@@ -12,6 +13,19 @@ class TimeValue
{
use ArrayEnabled;
private const EXTRACT_TIME = '/\b'
. '(\d+)' // match[1] - hour
. '(:' // start of match[2] (rest of string) - colon
. '(\d+' // start of match[3] - minute
. '(:\d+' // start of match[4] - colon and seconds
. '([.]\d+)?' // match[5] - optional decimal point followed by fractional seconds
. ')?' // end of match[4], which is optional
. ')' // end of match 3
// Excel does not require 'm' to trail 'a' or 'p'; Php does
. '(\s*(a|p))?' // match[6] optional whitespace followed by optional match[7] a or p
. ')' // end of match[2]
. '/i';
/**
* TIMEVALUE.
*
@@ -25,13 +39,13 @@ class TimeValue
* Excel Function:
* TIMEVALUE(timeValue)
*
* @param null|array|bool|float|int|string $timeValue A text string that represents a time in any one of the Microsoft
* @param null|array<mixed>|bool|float|int|string $timeValue A text string that represents a time in any one of the Microsoft
* Excel time formats; for example, "6:45 PM" and "18:45" text strings
* within quotation marks that represent time.
* Date information in time_text is ignored.
* Or can be an array of date/time values
*
* @return array|Datetime|float|int|string Excel date/time serial value, PHP date/time serial value or PHP date/time object,
* @return array<mixed>|Datetime|float|int|string Excel date/time serial value, PHP date/time serial value or PHP date/time object,
* depending on the value of the ReturnDateType flag
* If an array of numbers is passed as the argument, then the returned result will also be an array
* with the same dimensions
@@ -43,17 +57,20 @@ class TimeValue
}
// try to parse as time iff there is at least one digit
if (is_string($timeValue) && preg_match('/\\d/', $timeValue) !== 1) {
if (is_string($timeValue) && !Preg::isMatch('/\d/', $timeValue)) {
return ExcelError::VALUE();
}
$timeValue = trim((string) $timeValue, '"');
$timeValue = str_replace(['/', '.'], '-', $timeValue);
$arraySplit = preg_split('/[\/:\-\s]/', $timeValue) ?: [];
if ((count($arraySplit) == 2 || count($arraySplit) == 3) && $arraySplit[0] > 24) {
$arraySplit[0] = ((int) $arraySplit[0] % 24);
$timeValue = implode(':', $arraySplit);
if (Preg::isMatch(self::EXTRACT_TIME, $timeValue, $matches)) {
if (empty($matches[6])) { // am/pm
$hour = (int) $matches[0];
$timeValue = ($hour % 24) . $matches[2];
} elseif ($matches[6] === $matches[7]) { // Excel wants space before am/pm
return ExcelError::VALUE();
} else {
$timeValue = $matches[0] . 'm';
}
}
$PHPDateArray = Helpers::dateParse($timeValue);

View File

@@ -28,7 +28,7 @@ class Week
* @param mixed $dateValue Excel date serial value (float), PHP date timestamp (integer),
* PHP DateTime object, or a standard date string
* Or can be an array of date values
* @param array|int $method Week begins on Sunday or Monday
* @param array<mixed>|int $method Week begins on Sunday or Monday
* 1 or omitted Week begins on Sunday.
* 2 Week begins on Monday.
* 11 Week begins on Monday.
@@ -41,7 +41,7 @@ class Week
* 21 ISO (Jan. 4 is week 1, begins on Monday).
* Or can be an array of methods
*
* @return array|int|string Week Number
* @return array<mixed>|int|string Week Number
* If an array of values is passed as the argument, then the returned result will also be an array
* with the same dimensions
*/
@@ -101,7 +101,7 @@ class Week
* PHP DateTime object, or a standard date string
* Or can be an array of date values
*
* @return array|int|string Week Number
* @return array<mixed>|int|string Week Number
* If an array of numbers is passed as the argument, then the returned result will also be an array
* with the same dimensions
*/
@@ -137,7 +137,7 @@ class Week
* Excel Function:
* WEEKDAY(dateValue[,style])
*
* @param null|array|bool|float|int|string $dateValue Excel date serial value (float), PHP date timestamp (integer),
* @param null|array<mixed>|bool|float|int|string $dateValue Excel date serial value (float), PHP date timestamp (integer),
* PHP DateTime object, or a standard date string
* Or can be an array of date values
* @param mixed $style A number that determines the type of return value
@@ -146,7 +146,7 @@ class Week
* 3 Numbers 0 (Monday) through 6 (Sunday).
* Or can be an array of styles
*
* @return array|int|string Day of the week value
* @return array<mixed>|int|string Day of the week value
* If an array of values is passed as the argument, then the returned result will also be an array
* with the same dimensions
*/

View File

@@ -22,16 +22,16 @@ class WorkDay
* Excel Function:
* WORKDAY(startDate,endDays[,holidays[,holiday[,...]]])
*
* @param array|mixed $startDate Excel date serial value (float), PHP date timestamp (integer),
* @param array<mixed>|mixed $startDate Excel date serial value (float), PHP date timestamp (integer),
* PHP DateTime object, or a standard date string
* Or can be an array of date values
* @param array|int $endDays The number of nonweekend and nonholiday days before or after
* @param array<mixed>|int $endDays The number of nonweekend and nonholiday days before or after
* startDate. A positive value for days yields a future date; a
* negative value yields a past date.
* Or can be an array of int values
* @param null|mixed $dateArgs An array of dates (such as holidays) to exclude from the calculation
*
* @return array|DateTime|float|int|string Excel date/time serial value, PHP date/time serial value or PHP date/time object,
* @return array<mixed>|DateTime|float|int|string Excel date/time serial value, PHP date/time serial value or PHP date/time object,
* depending on the value of the ReturnDateType flag
* If an array of values is passed for the $startDate or $endDays,arguments, then the returned result
* will also be an array with matching dimensions
@@ -72,6 +72,8 @@ class WorkDay
/**
* Use incrementing logic to determine Workday.
*
* @param array<mixed> $holidayArray
*/
private static function incrementing(float $startDate, int $endDays, array $holidayArray): float|int|DateTime
{
@@ -103,10 +105,12 @@ class WorkDay
return Helpers::returnIn3FormatsFloat($endDate);
}
/** @param array<mixed> $holidayArray */
private static function incrementingArray(float $startDate, float $endDate, array $holidayArray): float
{
$holidayCountedArray = $holidayDates = [];
foreach ($holidayArray as $holidayDate) {
/** @var float $holidayDate */
if (self::getWeekDay($holidayDate, 3) < 5) {
$holidayDates[] = $holidayDate;
}
@@ -131,6 +135,8 @@ class WorkDay
/**
* Use decrementing logic to determine Workday.
*
* @param array<mixed> $holidayArray
*/
private static function decrementing(float $startDate, int $endDays, array $holidayArray): float|int|DateTime
{
@@ -162,10 +168,12 @@ class WorkDay
return Helpers::returnIn3FormatsFloat($endDate);
}
/** @param array<mixed> $holidayArray */
private static function decrementingArray(float $startDate, float $endDate, array $holidayArray): float
{
$holidayCountedArray = $holidayDates = [];
foreach ($holidayArray as $holidayDate) {
/** @var float $holidayDate */
if (self::getWeekDay($holidayDate, 3) < 5) {
$holidayDates[] = $holidayDate;
}

View File

@@ -31,7 +31,7 @@ class YearFrac
* @param mixed $endDate Excel date serial value (float), PHP date timestamp (integer),
* PHP DateTime object, or a standard date string
* Or can be an array of methods
* @param array|int $method Method used for the calculation
* @param array<mixed>|int $method Method used for the calculation
* 0 or omitted US (NASD) 30/360
* 1 Actual/actual
* 2 Actual/360
@@ -39,7 +39,7 @@ class YearFrac
* 4 European 30/360
* Or can be an array of methods
*
* @return array|float|int|string fraction of the year, or a string containing an error
* @return array<mixed>|float|int|string fraction of the year, or a string containing an error
* If an array of values is passed for the $startDate or $endDays,arguments, then the returned result
* will also be an array with matching dimensions
*/
@@ -62,11 +62,11 @@ class YearFrac
}
return match ($method) {
0 => Functions::scalar(Days360::between($startDate, $endDate)) / 360,
0 => Helpers::floatOrInt(Days360::between($startDate, $endDate)) / 360,
1 => self::method1($startDate, $endDate),
2 => Functions::scalar(Difference::interval($startDate, $endDate)) / 360,
3 => Functions::scalar(Difference::interval($startDate, $endDate)) / 365,
4 => Functions::scalar(Days360::between($startDate, $endDate, true)) / 360,
2 => Helpers::floatOrInt(Difference::interval($startDate, $endDate)) / 360,
3 => Helpers::floatOrInt(Difference::interval($startDate, $endDate)) / 365,
4 => Helpers::floatOrInt(Days360::between($startDate, $endDate, true)) / 360,
default => ExcelError::NAN(),
};
}
@@ -91,7 +91,7 @@ class YearFrac
private static function method1(float $startDate, float $endDate): float
{
$days = Functions::scalar(Difference::interval($startDate, $endDate));
$days = Helpers::floatOrInt(Difference::interval($startDate, $endDate));
$startYear = (int) DateParts::year($startDate);
$endYear = (int) DateParts::year($endDate);
$years = $endYear - $startYear + 1;

View File

@@ -8,14 +8,18 @@ class ArrayArgumentHelper
{
protected int $indexStart = 0;
/** @var mixed[] */
protected array $arguments;
protected int $argumentCount;
/** @var int[] */
protected array $rows;
/** @var int[] */
protected array $columns;
/** @param mixed[] $arguments */
public function initialise(array $arguments): void
{
$keys = array_keys($arguments);
@@ -34,6 +38,7 @@ class ArrayArgumentHelper
}
}
/** @return mixed[] */
public function arguments(): array
{
return $this->arguments;
@@ -65,6 +70,7 @@ class ArrayArgumentHelper
return count($rowVectors) === 1 ? array_pop($rowVectors) : null;
}
/** @return int[] */
private function getRowVectors(): array
{
$rowVectors = [];
@@ -84,6 +90,7 @@ class ArrayArgumentHelper
return count($columnVectors) === 1 ? array_pop($columnVectors) : null;
}
/** @return int[] */
private function getColumnVectors(): array
{
$columnVectors = [];
@@ -96,6 +103,7 @@ class ArrayArgumentHelper
return $columnVectors;
}
/** @return int[] */
public function getMatrixPair(): array
{
for ($i = $this->indexStart; $i < ($this->indexStart + $this->argumentCount - 1); ++$i) {
@@ -134,6 +142,11 @@ class ArrayArgumentHelper
return $this->columns[$argument];
}
/**
* @param mixed[] $arguments
*
* @return int[]
*/
private function rows(array $arguments): array
{
return array_map(
@@ -142,14 +155,17 @@ class ArrayArgumentHelper
);
}
/**
* @param mixed[] $arguments
*
* @return int[]
*/
private function columns(array $arguments): array
{
return array_map(
function (mixed $argument): int {
return is_array($argument) && is_array($argument[array_keys($argument)[0]])
fn (mixed $argument): int => is_array($argument) && is_array($argument[array_keys($argument)[0]])
? count($argument[array_keys($argument)[0]])
: 1;
},
: 1,
$arguments
);
}
@@ -166,6 +182,13 @@ class ArrayArgumentHelper
return $count;
}
/**
* @param mixed[] $arguments
* @param int[] $rows
* @param int[] $columns
*
* @return mixed[]
*/
private function flattenSingleCellArrays(array $arguments, array $rows, array $columns): array
{
foreach ($arguments as $index => $argument) {
@@ -180,6 +203,11 @@ class ArrayArgumentHelper
return $arguments;
}
/**
* @param mixed[] $array
*
* @return mixed[]
*/
private function filterArray(array $array): array
{
return array_filter(

View File

@@ -2,12 +2,14 @@
namespace PhpOffice\PhpSpreadsheet\Calculation\Engine;
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
class ArrayArgumentProcessor
{
private static ArrayArgumentHelper $arrayArgumentHelper;
/** @return mixed[] */
public static function processArguments(
ArrayArgumentHelper $arrayArgumentHelper,
callable $method,
@@ -54,23 +56,30 @@ class ArrayArgumentProcessor
return ['#VALUE!'];
}
/**
* @param int[] $matrixIndexes
*
* @return mixed[]
*/
private static function evaluateVectorMatrixPair(callable $method, array $matrixIndexes, mixed ...$arguments): array
{
$matrix2 = array_pop($matrixIndexes);
/** @var array $matrixValues2 */
$matrix2 = array_pop($matrixIndexes) ?? throw new Exception('empty array 2');
/** @var mixed[][] $matrixValues2 */
$matrixValues2 = $arguments[$matrix2];
$matrix1 = array_pop($matrixIndexes);
/** @var array $matrixValues1 */
$matrix1 = array_pop($matrixIndexes) ?? throw new Exception('empty array 1');
/** @var mixed[][] $matrixValues1 */
$matrixValues1 = $arguments[$matrix1];
$rows = min(array_map([self::$arrayArgumentHelper, 'rowCount'], [$matrix1, $matrix2]));
$columns = min(array_map([self::$arrayArgumentHelper, 'columnCount'], [$matrix1, $matrix2]));
/** @var non-empty-array<int> */
$matrix12 = [$matrix1, $matrix2];
$rows = min(array_map(self::$arrayArgumentHelper->rowCount(...), $matrix12));
$columns = min(array_map(self::$arrayArgumentHelper->columnCount(...), $matrix12));
if ($rows === 1) {
$rows = max(array_map([self::$arrayArgumentHelper, 'rowCount'], [$matrix1, $matrix2]));
$rows = max(array_map(self::$arrayArgumentHelper->rowCount(...), $matrix12));
}
if ($columns === 1) {
$columns = max(array_map([self::$arrayArgumentHelper, 'columnCount'], [$matrix1, $matrix2]));
$columns = max(array_map(self::$arrayArgumentHelper->columnCount(...), $matrix12));
}
$result = [];
@@ -92,13 +101,18 @@ class ArrayArgumentProcessor
return $result;
}
/**
* @param mixed[] $matrixIndexes
*
* @return mixed[]
*/
private static function evaluateMatrixPair(callable $method, array $matrixIndexes, mixed ...$arguments): array
{
$matrix2 = array_pop($matrixIndexes);
/** @var array $matrixValues2 */
/** @var mixed[][] $matrixValues2 */
$matrixValues2 = $arguments[$matrix2];
$matrix1 = array_pop($matrixIndexes);
/** @var array $matrixValues1 */
/** @var mixed[][] $matrixValues1 */
$matrixValues1 = $arguments[$matrix1];
$result = [];
@@ -119,6 +133,7 @@ class ArrayArgumentProcessor
return $result;
}
/** @return mixed[] */
private static function evaluateVectorPair(callable $method, int $rowIndex, int $columnIndex, mixed ...$arguments): array
{
$rowVector = Functions::flattenArray($arguments[$rowIndex]);
@@ -141,11 +156,13 @@ class ArrayArgumentProcessor
/**
* Note, offset is from 1 (for the first argument) rather than from 0.
*
* @return mixed[]
*/
private static function evaluateNthArgumentAsArray(callable $method, int $nthArgument, mixed ...$arguments): array
{
$values = array_slice($arguments, $nthArgument - 1, 1);
/** @var array $values */
/** @var mixed[] $values */
$values = array_pop($values);
$result = [];

View File

@@ -16,40 +16,30 @@ class FormattedNumber
// preg_quoted string for major currency symbols, with a %s for locale currency
private const CURRENCY_CONVERSION_LIST = '\$€£¥%s';
private const STRING_CONVERSION_LIST = [
[self::class, 'convertToNumberIfNumeric'],
[self::class, 'convertToNumberIfFraction'],
[self::class, 'convertToNumberIfPercent'],
[self::class, 'convertToNumberIfCurrency'],
];
/**
* Identify whether a string contains a formatted numeric value,
* and convert it to a numeric if it is.
*
* @param string $operand string value to test
* @param float|string $operand string value to test
*/
public static function convertToNumberIfFormatted(string &$operand): bool
public static function convertToNumberIfFormatted(float|string &$operand): bool
{
foreach (self::STRING_CONVERSION_LIST as $conversionMethod) {
if ($conversionMethod($operand) === true) {
return true;
}
}
return false;
return self::convertToNumberIfNumeric($operand)
|| self::convertToNumberIfFraction($operand)
|| self::convertToNumberIfPercent($operand)
|| self::convertToNumberIfCurrency($operand);
}
/**
* Identify whether a string contains a numeric value,
* and convert it to a numeric if it is.
*
* @param string $operand string value to test
* @param float|string $operand string value to test
*/
public static function convertToNumberIfNumeric(string &$operand): bool
public static function convertToNumberIfNumeric(float|string &$operand): bool
{
$thousandsSeparator = preg_quote(StringHelper::getThousandsSeparator(), '/');
$value = preg_replace(['/(\d)' . $thousandsSeparator . '(\d)/u', '/([+-])\s+(\d)/u'], ['$1$2', '$1$2'], trim($operand));
$value = preg_replace(['/(\d)' . $thousandsSeparator . '(\d)/u', '/([+-])\s+(\d)/u'], ['$1$2', '$1$2'], trim("$operand"));
$decimalSeparator = preg_quote(StringHelper::getDecimalSeparator(), '/');
$value = preg_replace(['/(\d)' . $decimalSeparator . '(\d)/u', '/([+-])\s+(\d)/u'], ['$1.$2', '$1$2'], $value ?? '');
@@ -68,13 +58,15 @@ class FormattedNumber
*
* @param string $operand string value to test
*/
public static function convertToNumberIfFraction(string &$operand): bool
public static function convertToNumberIfFraction(float|string &$operand): bool
{
if (preg_match(self::STRING_REGEXP_FRACTION, $operand, $match)) {
if (is_string($operand) && preg_match(self::STRING_REGEXP_FRACTION, $operand, $match)) {
$sign = ($match[1] === '-') ? '-' : '+';
$wholePart = ($match[3] === '') ? '' : ($sign . $match[3]);
$fractionFormula = '=' . $wholePart . $sign . $match[4];
$operand = Calculation::getInstance()->_calculateFormulaValue($fractionFormula);
/** @var string */
$operandx = Calculation::getInstance()->_calculateFormulaValue($fractionFormula);
$operand = $operandx;
return true;
}
@@ -86,12 +78,12 @@ class FormattedNumber
* Identify whether a string contains a percentage, and if so,
* convert it to a numeric.
*
* @param string $operand string value to test
* @param float|string $operand string value to test
*/
public static function convertToNumberIfPercent(string &$operand): bool
public static function convertToNumberIfPercent(float|string &$operand): bool
{
$thousandsSeparator = preg_quote(StringHelper::getThousandsSeparator(), '/');
$value = preg_replace('/(\d)' . $thousandsSeparator . '(\d)/u', '$1$2', trim($operand));
$value = preg_replace('/(\d)' . $thousandsSeparator . '(\d)/u', '$1$2', trim("$operand"));
$decimalSeparator = preg_quote(StringHelper::getDecimalSeparator(), '/');
$value = preg_replace(['/(\d)' . $decimalSeparator . '(\d)/u', '/([+-])\s+(\d)/u'], ['$1.$2', '$1$2'], $value ?? '');
@@ -111,13 +103,13 @@ class FormattedNumber
* Identify whether a string contains a currency value, and if so,
* convert it to a numeric.
*
* @param string $operand string value to test
* @param float|string $operand string value to test
*/
public static function convertToNumberIfCurrency(string &$operand): bool
public static function convertToNumberIfCurrency(float|string &$operand): bool
{
$currencyRegexp = self::currencyMatcherRegexp();
$thousandsSeparator = preg_quote(StringHelper::getThousandsSeparator(), '/');
$value = preg_replace('/(\d)' . $thousandsSeparator . '(\d)/u', '$1$2', $operand);
$value = preg_replace('/(\d)' . $thousandsSeparator . '(\d)/u', '$1$2', "$operand");
$match = [];
if ($value !== null && preg_match($currencyRegexp, $value, $match, PREG_UNMATCHED_AS_NULL)) {

Some files were not shown because too many files have changed in this diff Show More