Fix#4836, an issue which I was about to dismiss out-of-hand, but I decided that we could and should be making it a bit easier for our users to avoid problems. To that end, I have changed most of the private properties in Reader/Csv from `private` to `protected`. This allows users to extend the class easily; it is a better option than the existing `constructorCallback` - less awkward, not reliant on static settings, etc. (I know more now than I did when I introduced it.) Taking advantage of the new extendability, a new class `Reader\CsvNoEscape` is added which forces the use of null-string as the escape character, and prevents the use of auto-detection of Mac line-endings; both of these are schedule for removal with Php9.
This actually makes `CsvNoEscape` a better option than `Csv`;
it should probably be used for all new development.
Because `IOFactory` is heavily used for loading files, it has some changes to better accommodate `CsvNoEscape` (and other classes). In particular, methods `createReader`, `load`, `identify`, and `createReaderForFile` now allow a new `mergeArray` parameter, where that parameter is merged with the static `IOFactory::$readers` array when deciding on a Reader class to be used. This allows the user to override the default Csv Reader, without having to change a static array, and without affecting IOFactory's ability to find other matching readers if no suitable entry is found in `mergeArray`.
Fix#993, which went stale in 2019 and is now reopened. It was not explicitly stated in the documentation, but Xlsx supports hyperlinks when clicking on a drawing. User tried to use the same format for internal hyperlink that is documented for cell internal hyperlink, and that failed (corrupt spreadsheet, hyperlink doesn't work). That was because Xlsx uses `#` rather than `sheet://`. For drawings, Xlsx Writer will now automatically convert `sheet://` to `#`, and Xlsx Reader will now convert the other way. No change is needed for cell hyperlinks. Documentation is now updated, including a statement that drawing hyperlinks work only for Xlsx.
Fix#954, which went stale 6 years ago and which I have now reopened. The `setLocale` method in `Calculation` and `Settings` does not affect the 3 localizable properties in `StringHelper` - `currencyCode`, `decimalSeparator`, and `thousandsSeparator`. One way to work around this problem is to set those properties separately; this is probably how most people handle it. Another way is to call Php's own `setlocale` function; this does not require any foreknowledge of what the values need to be, but it comes with baggage (data is maintained at process level rather than thread level), so its use is discouraged.
This PR adds a new `setLocale` method to `StringHelper`. It sets the 3 properties and the `Calculation` language all at once. It depends on the `Intl` extension, which is a recommendation but not a formal requirement for PhpSpreadsheet; the method will return `false` if `Intl` is not available or it thinks the supplied locale is not valid.
This PR started because the documentation on how to configure an Http client was out of date. However, as I investigated further, I found problems. GuzzleHttp, a client mentioned in the documentation, for example - it probably works fine when executed from a browser, but it does not work for `https:` requests from the Windows command line. See https://github.com/guzzle/guzzle/issues/2601, where a user notes that Guzzle's own program to demonstrate how to use it doesn't work, a result that I can confirm is still true. A linked explanation says that the solution is to explicitly specify a path to a CA bundle. For starters, this is impractical from our perspective. One possible solution is to change a php.ini option which is not needed for any other purpose, and which probably needs to change frequently - a burden on users who follow that route. An alternative solution is to use a method `request` to specify the path to the certificate store; this also will need to change from time to time, and, worse, the only method defined in ClientInterface is `sendRequest`, so using this solution isn't client-agnostic, which is a stated goal of https://github.com/PHPOffice/PhpSpreadsheet/commit/7cb4884b96174eb611621635e6fb603ef54178f7. Additionally, it is not clear why an external interface is needed rather than a call to file_get_contents, used elsewhere in PhpSpreadsheet, and not requiring a path to a certificate store.
I also believe that automatically evaluating WEBSERVICE for any arbitrary argument is not a good idea. I am adding a domain whitelist which the user must populate. For domains not in the whitelist, the calculation will revert to `oldCalculatedValue`, which is good enough for pass-through purposes, which probably encompasses most cases. That is how Excel behaves by default - it disables WEBSERVICE calls when it opens a spreadsheet which contains them. For cases where the user adds a new WEBSERVICE call, there is a choice of whitelisting the domain, or getting the result in some other way and using `setCalculatedValue` to store it.
Finally, when a WEBSERVICE call *is* evaluated, it will now accept a cell-address argument rather than just a literal string as is now the case.
Intl is only a "suggested" extension. A lot of the NumberFormat Wizard code depends on it. That's insufficient reason to make it required, but the suggestion text now mentions this dependency explicitly. Also clean up the Wizard documentation to reflect some changes since PhpSpreadsheet 1.28.
Fix#4626. Previous changes had increased the precision of floating point numbers when cast to string, making for greater accuracy after save and load operations, without affecting the values displayed by Excel. Although the results of the cast are now more accurate computationally, they can appear unexpected to humans. A new boolean parameter `lessFloatPrecision` (defaulting to false) is added to `StringHelper::convertToString`, to `NumberFormat::toFormattedString` and `NumberFormat\Formatter::toFormattedString`, and to the entire `Worksheet::toArray` family of functions. When the new parameter is set to true, the result can be less surprising to humans. It should not, however, be used in subsequent computations.
In the case of the NumberFormat functions, the new parameter will be considered only when the NumberFormat for the cell in question is `General` or equivalent. Setting an actual numeric format for the cell is probably a better solution than using the new parameter.
Fix#4600. String incrementation through the `++` operator is deprecated in Php 8.5. Because we make use of that operator to iterate through columns, we are particularly hard hit by that change - unaddressed, it causes over 2,000 errors in our test suite! It is, fortunately, not as difficult as I feared to correct. Replacing the `++` operator with a call to new method `StringHelper::stringIncrement` in 79 statements scattered over 31 source modules (in src, samples, test, and infra) eliminates all the messages in the test suite. It is possible that others are lurking, but I don't know a systematic way of determining if there are others. We'll stick with this for now, and deal with any others as they show up.
This PR will be applied to the master, release390, and release222 branches. It will not be applied to the release210 or release1291 branches, which will now accept security changes only.
PR #455 was submitted by @Aketos in 2018. It added no unit tests, so it was not merged, and it eventually went stale. Without the tests, I'm not sure exactly what the user had in mind. But my investigation indicates the following:
- for Xls files, if the column width in the file specifies a value greater than 255, Excel will choose its own width when it opens the file.
- for Xlsx files:
- Excel does not allow you to set a column width > 255, neither by dragging the column boundary, nor by right-clicking and setting a value, nor by auto-fitting the column width.
- Nevertheless, if the XML specifies a column width > 255, Excel will honor that value in the displayed spreadsheet, and even write it out if the file is saved.
I have taken a different approach than the original PR, which changed `Worksheet::calculateColumnWidths`. Instead, this PR adds an option to the Xlsx Writer to either restrict column widths to 255 or not. The default is "not" in order to avoid a breaking change. For emulating Excel's behavior, in the unusual situation where it might matter, the user might consider using the non-default option.
This PR also restricts column dimension width to 255 when saving an Xls file.
Fix#484. Fix#1318. Both went stale a long time ago. The images can currently specify their location as Left, Center, or Right. However, they also need to specify their type - first page, even pages, or odd pages (which is what is used when neither of the others is applicable). This is accomplished by adding 18 new constants to `Worksheet\HeaderFooter`, any of which can be specified as the second argument to `HeaderFooter::addImage`. Somewhat surprisingly, no changes are required to Xlsx Writer or Reader.
Xls Reader and Writer support header/footer, but do not support using images in them. No other readers nor writers support header/footer.
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.
My system short date format is set to `yyyy-mm-dd`.
I used Excel to create a spreadsheet, and included some dates, specifying `yyyy-mm-dd` formatting. When I looked at the resulting spreadsheet, I was surprised to see that Excel had stored the style not as `yyyy-mm-dd`, but rather as builtin style 14 (system short date format). Apparently the fact that the Excel styling matched my system choice was sufficient for it to override my choice! This is an astonishingly user-hostile implementation. Even though there are formats which, by design, "respond to changes in regional date and time settings", and even though the format I selected was not among those, Excel decided it was appropriate to vary the display even when I said I wanted an unvarying format.
This PR adds a new method `replaceBuiltinNumberFormat` to undo the damage that Excel does in such a situation. It also adds an `Excel Anomalies` document to the formal documentation, just to make situations like this readily available to the community.
BTW, Excel's sabotage can be avoided by using a number format style like `[Black]yyyy-mm-dd`.
Theme colors subject to tints occur in the wild, and should not be targeted by this PR. Our use case is an unmodified Theme color. There is probably a decent case to be made for adding a Tint property to Color, but that can come later if desired.
`Color::setHyperlinkTheme` will now try to fill in `rgb` as well as `theme` if it can locate an appropriate value in the Spreadsheet Theme. This will permit non-Xlsx formats to at least duplicate the color that Xlsx uses for hyperlinks.
Setting `Color::rgb\argb` will reset `theme` to none. If you want to use both, do rgb first, then theme. This will, I hope, avoid surpises for end-users.
Fix#1275, which had been closed as stale, and is now reopened pending the implementation of this PR. If there is a page break inside a defined print area, Excel may not render the print correctly unless the xml `brk` tag contains a `max` attribute. Libre Office renders it correctly. This seems like a bug in Excel (https://learn.microsoft.com/en-us/openspecs/office_standards/ms-oe376/b32ae11b-dee7-4dcb-9b46-a0feb32ce94f states that Office ignores min and max). PR #3345 (issue #3143) already addressed this problem by allowing the user to explicitly specify a `max` property in the PageBreak object. This PR eliminates the need for the user to make use of that kludge, by adding `max` to the xml whenever a page break is specified on a sheet with a defined print area. Xlsx Reader will now ignore the `max` attribute for row breaks, since it is no longer needed; it already ignores it for column breaks. The user may still set the `max` property if desired, just in case the new treatment is not adequate (I have not found a case where that is true). Two existing unit tests are very marginally changed because of this PR.
Document some cases where solution might not work well. Making class extendable and offering some over-rideable methods may allow for solutions to some of these problems.
Helper/TextGrid was intended to assist with some samples. However, it has emerged recently on two tickets. PR #4342 intended to introduce functionality very similar to TextGrid, and was closed for that reason. Issue #1640 was closed as stale over 4 years ago, despite the fact that TextGrid seems an adequate resolution for it.
Since it seems that there is a use for this function beyond its original intended usage, I added a few parameters to give it some flexibility - the ability to omit row and/or column headers, and the ability to add a divider line between rows.
A description of this function is added to the formal documentation.
Fix #4357.`identify` returns a type, not a class name, and this result is not always usable for createReader. The docs say that it is usable in that manner. Changing the behavior of `identify` would be a breaking change, but adding an optional parameter (defaulting to current behavior) allowing it to return a class name rather than a type would not. This PR adds that parameter and updates the documentation to suggest its use for the code in question.
To complete this change, `createReader` now accepts either a type (current behavior) or class name (new). Although it is not particularly identified as a possible problem by the issue, `createWriter` is similarly changed for consistency's sake.