611 Commits

Author SHA1 Message Date
oleibman 4b8a929fc1 Merge commit from fork
* Validate Mime Type for Images

* Extend Change to Xlsx Reader

* Attach Drawing to Sheet Only If Valid

* Suppress Some Theoretical Warning Messages

* Minor Tweak
2024-09-23 13:28:31 -07:00
oleibman 63ccb02ab9 Merge commit from fork
* Check for Whitespace Around Xml Encoding

* More Tests
2024-09-13 18:17:30 -07:00
oleibman 259db50132 Merge branch 'master' into pr607 2024-08-19 13:50:05 -07:00
oleibman 30384ac043 Xls Reader Some Ranges Not Handled Properly
This supersedes PR #607 by @christian-forgacs, who deserves all the credit for reporting the problem and devising the solution. The PR went stale in 2018, and it is just easier to resubmit a clean version rather than clean up the old one. Among the suggestions in the PR was that you should try to create a spreadsheet from scratch to demonstrate the problem rather than supply one. However, my attempts to match the failing spreadsheet do not have a problem when they are read. So, a supplied spreadsheet it is.

Fix #1570. No sample spreadsheet was supplied with that issue, but I am almost certain that this is another example of the same problem. I am removing the stale label from that issue; it will be closed properly when this PR is merged.
2024-08-13 14:27:42 -07:00
oleibman 17e894e21b Merge branch 'master' into issue4125 2024-08-12 09:11:58 -07:00
oleibman ee1d4d0367 Currency and Accounting Formats
Fix #4125. Currency and Accounting Wizards generate styles for ISO codes, but these are incorrect and cause a problem when Excel tries to open a spreadsheet containing these styles. Debugging that problem, other problems with Wizards came to light:
- Currency Wizard should permit four different styles for negative numbers (as Excel does) - minus sign, minus sign and red font, paretheses, and parenthese and red font. It currently uses only minus sign.
- Accounting Wizard should use parentheses for negative numbers (as Excel does). It currently uses minus sign.
- Accounting Wizard should always use SYMBOL_WITH_SPACING (as Excel does). It currently permits the use of SYMBOL_WITHOUT_SPACING. What WITH_SPACING really does is to ensure decimal-point alignment among adjacent cells in a column with the same format.
- Currency Wizard should always use SYMBOL_WITHOUT_SPACING (as Excel does). It currently permits the use of SYMBOL_WITH_SPACING.

I am correcting these problems by:
- renaming Currency Wizard to CurrencyBase
- adding a `negative` property with setter to it and its constructor.
- adding a new Currency which extends CurrencyBase, always using SYMBOL_WITHOUT_SPACING when formatting.
- having Accounting extend CurrencyBase rather than Currency, always using SYMBOL_WITH_SPACING and NEGATIVE_PARENS when formatting.
- CurrencyBase can be used if the restrictions on Currency and Accounting are not desired (e.g. the suggested accounting constant from [this unimplemented PR](https://github.com/PHPOffice/PhpSpreadsheet/pull/1576)).

Excel does some funny stuff with these formats. In particular, it might try to guess if you have a particular Accounting format in mind. So the Accounting wizard for dollar sign generates a format which (a) matches FORMAT_ACCOUNTING_USD, and (b) Excel (correctly) interprets as an Accounting format for symbol $. On the other hand, the Accounting wizard for euro sign generates a format which (a) matches FORMAT_ACCOUNTING_EUR, but (b) Excel interprets as a custom code rather than an Accounting format. This in itself is not a particularly big deal, but it has made it impossible for me to see exactly what format Excel uses for trailing currency symbols for negative numbers. I can't get them to decimal-point align with positive numbers if I put any kind of space between the trailing parenthesis and the currency symbol, so I omit that. It doesn't look terrible, and it keeps everything aligned, but it might not be what people are used to.

I've also changed the formatting to use spaces rather than non-breaking spaces. They seem to work just fine, and the constants mentioned above use them rather than nbsp.

Fix #4124. Currency formats that contain an ISO currency code which contains one of the characters used to recognize a date format (hmsdy), e.g. [$HUF], are being formatted by PhpSpreadsheet as dates rather than currencies. Code is changed to recognize open bracket followed by dollar sign followed by 3 Latin alphabetic characters followed by close bracket as a non-date.
2024-08-05 18:36:06 -07:00
oleibman f3ae0bd944 Merge branch 'master' into atsign 2024-08-02 09:01:06 -07:00
oleibman b1e5e326ac Merge branch 'master' into issue4113 2024-08-02 08:42:52 -07:00
oleibman 85629b77a0 More Extreme Cases 2024-07-31 12:47:19 -07:00
oleibman 768dd75ba1 Merge branch 'master' into atsign 2024-07-30 22:51:13 -07:00
oleibman 523afe57f0 Merge pull request #4107 from oleibman/pr848
RATE Function Permits Floating Point NPER
2024-07-30 22:05:12 +00:00
oleibman 6de86f5d77 Deal With Scientific Notation 2024-07-30 07:37:57 -07:00
oleibman 58ff1491ba Additional Examples Which Were Failing 2024-07-29 08:24:56 -07:00
Adrien Crivelli bea2d4b30f Security: prevent XXE (XML External Entity) when loading files
Prevent XEE by hiding custom entities by using single quote to
declare a non-UTF-8 encoding.

XML standard, https://www.w3.org/TR/xml/#NT-EncodingDecl, allows single
quote to declare encoding, but we did not support it. Instead, we
incorrectly fell back on the default of UTF-8. That incorrectly kept the
XML as non-UTF-8, and thus prevented our regexp-based custom entity
detection mechanism to work.
2024-07-29 16:22:43 +09:00
oleibman ab5965affb Merge branch 'master' into issue4099 2024-07-27 07:36:13 -07:00
oleibman f553019f95 New Algorithm for TRUNC, ROUNDUP, and ROUNDDOWN
Fix #4113. TRUNC isn't always producing the expected result. There was a promising algorithm at https://stackoverflow.com/questions/4668628/truncate-float-numbers-with-php from user Juan. It works through Php8.3, but failed in Php8.4 (more on this later). User Savageman on the same page has a solution that needs work, but, once the work had taken place, it works on Php8.1-8.4.

The ROUNDUP and ROUNDDOWN functions were adversely affected by Php8.4, probably for the same reasons as Juan's TRUNC suggestion. I put a kludge in place for them some time ago, but I wasn't happy with it. The solution used for TRUNC here suggested a change to the ROUNDUP and ROUNDDOWN code that would no longer require the kludge. The change to those functions now works more cleanly on Php8.1-8.4.
2024-07-26 23:02:11 -07:00
oleibman 312cd5a6a0 Merge branch 'master' into atsign 2024-07-23 06:25:08 -07:00
oleibman b6ff857ba7 RATE Function Permits Floating Point NPER
Suggested by PR #848 from @markkimsal. The RATE calculation had already been corrected, so that part of the PR was unnecessary, however one of the tests included a floating point value for Number of Periods, which Excel permits. PhpSpreadsheet till now expected that parameter to be an integer. This is trivially changed with some tests added.
2024-07-22 08:32:54 -07:00
oleibman 2952cf5526 Ods Reader Allow Omission of Some Page Settings Tags
Fix #4099. Ods Reader was expecting there to always be `header-style` and `footer-style` tags when `page-layout` tag is present, but these need not exist. It seemed like there might be other exposures along this line in `readPageSettingStyles`; rather than waiting for a problem report to show up for each, the code is updated to use `->item(0)` in place of `[0]` when appropriate, and make use of the nullsafe `?->` operator introduced with Php8.
2024-07-18 13:30:58 -07:00
oleibman 73eeba0f1b Merge branch 'master' into issue476 2024-07-17 17:42:28 -07:00
oleibman f4ef625fdb Merge pull request #4093 from oleibman/issue460
Ods Boolean Data
2024-07-17 23:29:35 +00:00
oleibman 59dfd1f20d Merge branch 'master' into issue64 2024-07-11 20:39:49 -07:00
oleibman 6ab27d2931 Xlsx Writer Rich Text and TYPE_STRING
Fix #476. Another in the "better late than never" series, closed as stale in June 2018. Xlsx Writer expects cells containing RichText to have DataType `TYPE_INLINE`; but the spreadsheet associated with the issue has the cell defined as `TYPE_STRING`. Change Writer to handle RichText TYPE_STRING appropriately.
2024-07-11 20:05:16 -07:00
oleibman 18e3c00e40 Performance Improvements for Csv Reader
Fix #460. Another in the "better late than never" series, closed as stale in June 2018. Ods Writer and Ods Reader handle booleans differently; what is worse, neither of them do it correctly. They will now match the behavior of LibreOffice. Reporter said that part of the xml would vary depending on locale; I believe that part is never actually used, but I do emulate that behavior.
2024-07-11 19:48:12 -07:00
oleibman 2c150d5381 Merge branch 'master' into issue804 2024-07-10 20:14:46 -07:00
oleibman 5b18dcf04d Shot Myself in Foot
PR #4073 adds parsing of formulas for `$cell->setValue()`, but the spill operator won't parse correctly, breaking some of this PR. Add code to avoid that problem.
2024-07-07 21:49:07 -07:00
oleibman b22d1f52e7 Merge branch 'master' into atsign 2024-07-07 16:46:50 -07:00
oleibman 96f09441ca Merge branch 'master' into issue4081 2024-07-07 07:27:49 -07:00
oleibman 22bac3eb49 Merge branch 'master' into issue2581 2024-07-05 22:48:45 -07:00
oleibman 070ceef5d0 Changes to INDEX Function
Fix #64 (really!), closed as stale in December 2017, another in our "better late than never" series. Excel's INDEX function doesn't really behave quite as described. If a single row is used as an argument, either in literal form `{item1, item2, item3}` or expressed as a range `A1:A6`, INDEX is happy to evaluate the array as if each entry were a row rather than a single item. PhpSpreadsheet is changed to do likewise.

INDEX also returned `#REF!` when it would normally return an array (which would often be reduced to its leftmost topmost entry later). This code is deleted, invalidating one existing test, and INDEX will now operate like other functions which can return arrays.
2024-07-05 20:57:43 -07:00
oleibman 1d86675e04 Ods Xml Reader and Whitespace Text Nodes
Fix #804, opened in Dec. 2018, and closed as stale in Feb. 2019, and which I have re-opened to be closed properly by this PR. Better late than never, I suppose. A third party generated an ODS spreadsheet which PhpSpreadsheet could not read. By way of explanation, the xml in the file contained lots of whitespace between tags, which is wonderful for those humans among us who have to analyze it; but PhpSpreadsheet was not prepared for it. It is now.
2024-07-03 19:56:38 -07:00
oleibman 8557ccb72a Ods Comments With Newlines
Fix #4081. Ods Reader was not reading entire contents of comment. On further inspection, Ods Writer also was not handling comments completely correctly. Ods comments are recorded as `text:p` children of `office:annotation` elements. A newline is inserted between successive `text:p` elements. The `text:p` element itself can have as descendants (at least):
- raw text
- `text:span` elements
- `text:line-break` elements, which also causes the insertion of a newline

Ods Writer is changed to use a single `text:p` with multiple span/linebreak elements. Ods Reader is changed to process in their entirety either that form, or multiple `text:p` elements. Styling of the individual elements of the comment is permitted in Ods. That has not been supported till now by PhpSpreadsheet, and this PR will not address that situation - Ods Reader hast little style support, and this would hardly be the most urgent case where it is missing.
2024-07-01 14:52:23 -07:00
oleibman edf7f71e2a Merge branch 'master' into atsign 2024-06-30 00:28:18 -07:00
oleibman b051d4946c Use CELL("width") As Another Unimplemented Array Function
I might want to implement CHOOSECOLS after this PR is merged.
2024-06-29 23:28:21 -07:00
oleibman 4b04cc1c8d Propagate Errors in Text Functions
Fix #2581 (not obvious - see next paragraph for explanation). This continues the work of PR #2902 (and also PR #3467) to have errors propagated through function calculations rather than treating them as strings. All text functions, and the concatenation operator, are addressed in this PR.

In the original issue, the spreadsheet being loaded uses the result of an unimplemented function as an argument to another function. When `getCalculatedValue` is used on the cell in question, the result is returned as `#VALUE!`. If the cell had just contained a function call to the unimplemented function, getCalculatedValue would have recognized the situation and returned oldCalculatedValue as the result. Not perfect, but good enough most of the time. User would like oldCalculatedValue returned here as well, which seems like a reasonable request.

PhpSpreadsheet always returns `#Not Yet Implemented` as the result for a function which it knows about but which is not yet implemented. That is the key to the `Cell` class being able to substitute oldCalculatedValue in the first place. However, in order to do that for the issue in question, that result has to be propagated to any functions for which the result is an argument. I don't want to add unimplemented to the list of known error codes, but I am willing to add a parameter to `ErrorValue::isError` to indicate whether that value should be considered an error (default is "no").

The first use of that new parameter would be by the text functions. They go through a common Helper routine, so it is pretty easily implemented. And, as it turns out, most of the text functions do not currently propagate errors, e.g. if A1 results in a value error, `=LEFT(A1,2)` will result in `#V` rather than `#VALUE!`. With this PR, they will now be handled correctly.
2024-06-29 22:00:39 -07:00
oleibman 6d06bf94b0 Merge branch 'master' into issue1310 2024-06-25 23:18:38 -07:00
oleibman e40438916f Change Style Without Affecting Current Cell/Sheet, and Invalid Formulas
Fix #1310, which was closed as stale in 2020, but which I will now reopen. Supersedes PR #1311 (@jaiminmoslake7020), from which I will remove the stale label but leave closed. The issue and the PR were too limited  - they detected that the use of two equal signs at the start of a string made for an invalid formula, but there are variations, trivial and otherwise, which might also be detected. Using `setValue` with a string which starts with an equal sign will now attempt to parse (not evaluate) the formula; for certain situations in which the parser throws an exception, the string will be treated as a string rather than a formula. An example where it will still be treated as a formula is a 3D range reference, where the problem is not that it can't be parsed, but rather that the formula isn't supported (see unit test Calculation/Engine/RangeTest::test3dRangeEvaluation). Allowing such a formula might cause problems later on, but that is already what happens.

A string beginning with an equal sign but which isn't treated as a formula will automatically set the `quotePrefix` attribute to `true`; all other `setValue` attempts will set it to `false`. This avoids the problem of a lingering value causing problems later on.

It has long been a matter of discontent that setting a style can change the selected cells. A new method is added to `Worksheet`:
```php
applyStylesFromArray(string $coordinate, array $styleArray)
```
This will attempt to guarantee that the active sheet in the current spreadsheet, and the selected cells in the current worksheet, remain undisturbed after the call. The setting of `quotePrefix` above is the first use of the new method.
2024-06-25 22:06:36 -07:00
oleibman f181a4c66e Merge branch 'master' into year1904 2024-06-22 22:13:42 -07:00
oleibman 43589bc9b6 Make Base Date a Property of Spreadsheet
This change is extracted from PR #2787 by @MarkBaker. That change mostly deals with array functions, and that part will be superseded by PR #3962. However, this part of 2787 is not included in 3962.

Fix #1036 (closed as stale in 2019 and just reopened). Excel spreadsheets can have either of 2 base dates, 1900 or 1904, and the numeric value of any date cells will vary depending on which base date is in use. PhpSpreadsheet has, till now, handled that as a static property of Shared/Date. This does not work well if two spreadsheets with different base dates are open simultaneously. The code is changed to store the base date as a property of the spreadsheet when an Xls/Xlsx spreadsheet is loaded, and use that property when saving an Xls/Xlsx spreadsheet. Any call to `getCalculatedValue` or `getFormattedValue` will temporarily set the Shared/Date value to that of the spreadsheet, and restore it at completion. In order to avoid a BC break, the Xls and Xlsx readers will continue to populate the Shared/Date value as before.
2024-06-22 22:09:22 -07:00
oleibman cabd60ca09 Merge pull request #4060 from oleibman/stan9d
Better Definitions for Mixed Parameters and Values Part 3 of Many
2024-06-23 04:31:16 +00:00
oleibman ef2b5b9e00 Mostly Docs and Tests
Also support for Xml format.
2024-06-21 21:55:05 -07:00
oleibman 3a690a755c SINGLE Function, and Gnumeric
SINGLE function can be used to return first value from a dynamic array result, or to return the value of the cell which matches the current row (VALUE error if not match) for a range. Excel allows you to specify an at-sign unary operator rather than SINGLE function; this PR does not permit that.

Add support for reading CSE array functions for Gnumeric.

Throw an exception if setValueExplicit Formula is invalid (not a string, or doesn't begin with equal sign. This is equivalent to what happens when setValueExplicit Numeric specifies a non-numeric value.

Added a number of tests from PR #2787.
2024-06-21 07:08:22 -07:00
oleibman d7700125fa Spills
Implement SPILL for dynamic arrays. Calculating a dynamic array function will result in a SPILL error if it attempts to overlay a non-null cell which was not part of its previous calculation. Furthermore, it will set to null all cells which were part of its previous calculation but which are not part of the current one (i.e. one or both of the dimensions of the calculation is smaller than it had been); this should also apply for spills (whose result is reduced to 1*1).

Excel will stop you from changing the value in any cell in a dynamic array except the formula cell itself. I have not built this particular aspect into PhpSpreadsheet.

As usual, MS has taken some unusual steps here. If the result of a dynamic array calculation is #SPILL!, it will nevertheless be written to the xml as #VALUE!. It recognizes this situation by adding a new `vm` attribute to the cell, and expanding metadata.xml to recognize this.

A new optional parameter `$reduceArrays` is added to `toArray` and related functions. This will reduce a dynamic array to its first cell, which seems more useful than outputing it as an array (default).
2024-06-17 14:22:52 -07:00
oleibman ad2194d737 CONCATENATE Changes, and Csv/Html/Ods Support
The CONCATENATE function has been treated as equivalent to CONCAT. This is not how it is treated in Excel; it is closer to (and probably identical to) the ampersand concatenate operator. The difference manifests itself when any of the arguments is an array (typically a cell range). Code is added to support this difference.

Support for array results is added to Csv Writer, Html Writer, and Ods Reader and Writer. I have not figured out how to get it to work with Xls.
2024-06-14 08:30:18 -07:00
oleibman 08ba00b575 Populate Rest of Array Cells, UNIQUE Changes
See issue #4062. When calculating an array formula, populate all the cells associated with the result. This is almost the same as Excel's behavior. As yet, there is no attempt to create a #SPILL error, so cells may be inappropriately overwritten. Also, if the array size shrinks (e.g. there are fewer unique values than before),  no attempt is made to unpopulate the cells which were in range but are now outside the new dimensions. Spill and unpopulation are somewhat related, and will probably be handled at the same time, but their time has not yet come.

UNIQUE, at least for rows, was treating all cell (calculated) values as strings. This is not the same behavior as Excel, which will preserve datatypes, and treat int 3 and string 3 as unique values. Excel will, however, treat int 3 and float 3.0 as non-unique. Within UNIQUE, private function uniqueByRow is changed to try to preserve the the datatype when executing (it will probably treat 3.0 as int - I don't know how I can, or even if I should attempt to, do better - but no int nor float should be treated as a string).
2024-06-06 06:52:14 -07:00
oleibman 5e26de63a9 Handle Empty String in SharedStrings
Fix #4063. Fix #1560. Fix #1293. PhpSpreadsheet is not accounting for an empty string in Xlsx sharedStrings.xml.The code which parses it in Reader/Xlsx looks for a `t` or `r` tag descending from `si`, but, in this case, the tag is coded as `<si/>`, with neither t nor r tag descending. An else clause is added to set the string to empty string in this case.

I was surprised that this had not turned up before, and a search through the archives found at least 2 earlier reports from 4 years ago. Those had been marked stale; the stale indicator is removed, and the issues are re-opened, to be closed when this PR is merged.
2024-06-06 06:17:02 -07:00
oleibman 85c1512b67 Better Definitions for Mixed Parameters and Values Part 3 of Many
Continuing work started with PR #4016 and PR #4026. Improve documentation within program by making explicit what types of values are allowed for variables described as "mixed". In order to avoid broken functionality, this is done mainly through doc-blocks. This will get us closer to Phpstan Level 9, but many changes will be needed before we can consider that.

This change has more executable code changes than its predecessor. I will wait longer than normal before merging it to allow for additional testing.
2024-06-04 06:47:51 -07:00
oleibman 5e7ebf3d91 Merge branch 'master' into atsign 2024-06-03 06:32:43 -07:00
oleibman 9b239ebdb0 Phpunit 10 and Phpstan 1.11
Dependabot suggested some changes this month which required an unusual effort to implement successfully. With the elimination of Php 8.0 as a supported environment, it became possible to use Phpunit 10 rather than 9. Among other considerations, the configuration file for Phpunit is changed. I preserved the Phpunit 9 version under a different name. Aside from the configuration change, several other changes needed to be made to accommodate the change:
- Fix #3993. A peculiar problem indeed. One of the reporters said it had something to do with mocking, but I couldn't duplicate it. But Phpunit 10 revealed the problem in one test (Reader/Xlsx/AutoFilterTest), and that was sufficient for me to apply the trivial source code change to Worksheet/Worksheet.
- Some extra stringency on data providers required extra work in Calculation/CalculationFunctionListTest.
- There was a misplaced label in Calculation/ParseFormulaTest. Likewise in the data member CellGetRangeBoundaries.
- More stringency required changes to data members Shared/Trend/ExponentialBestFit and Shared/Trend/LinearBestFit.
- Issue3982Test testLoadAllRows seemed to go into a memory-acquiring loop in 10 that was not evident in 9. This particular test uses a lot of memory by design, but was included only to establish a base level for the other tests in that member. I feel it is acceptable to skip it for 10.

Phpstan errors with a new release are not unusual. One of the problems this time around was, however, unusual - it is fixed when Phpstan runs under Php8.3, but not for earlier Php releases. Our tools currently use Php 8.1. It is on my to-do list to get Phpstan and other test tools running under 8.3 before 8.1 goes EOL. There are also some configuration file changes needed for Phpstan.

Php-cs-fixer has been taking an increasingly long time to run. They've added an experimental option to permit it to run its checks in parallel. I've changed its configuration to use that option.
2024-06-01 17:39:39 -07:00
oleibman 15fb1b542a Merge branch 'master' into issue4049 2024-05-31 08:50:17 -07:00