Fix#1324, which went stale many years ago, and is now re-opened. It can be considered a follow-on to PR #4479 which was installed in May. The user complains of a *very* small loss of precision. This can be corrected by using `StringHelper::convertToString` in lieu of a simple cast from float to string in two places. `Style\NumberFormat\Formatter` is quite straightforward. `Writer\Csv` is a bit more complicated. If you put a float with more than 15 digits precision in a Csv, on opening it Excel will give a pop-up, saying something inaccurate like "We've corrected this for you - is that okay?" Better to avoid that by making sure to avoid too much precision when writing to Csv.
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.
This came to light while cleaning up ComplexAssert. Many tests are calling `_calculateFormulaValue` rather than `calculateFormula`, and, as a result, have to be trimmed before asserting. This PR changes those calls, and does a bit more to simplify the tests. There are a lot of other non-Engineering tests which call `_calculateFormulaValue`, but none of those need to manipulate the result after the test.
This PR changes only tests, no source code.
Its use is already causes an issue with Phpstan. It uses interfaces marked as internal by Phpunit, and it will not work with Phpunit 12. It is more complicated than needed. This PR corrects all these problems. It also corrects a handful of other problems that will show up with Phpunit 12. Only tests are changed - no source code.
Fix#4558. Fix#4530. 4558 deals with a problem with COUNTA. Excel does not count empty cells, but it does count literal nulls (usually empty parameters) in the argument list. PhpSpreadsheet has till now not created empty cells during calculation, and so winds up treating them as literals. It is changed to create the cell when appropriate.
4530 has a similar problem. When INDIRECT winds up evaluating an uninitialized cell, it treats it as a null literal, leading to incorrect results. It is now changed to create the missing cell.
A number of functions, almost all of them Financial, have a related problem. They test for a null literal when initializing some of their parameters, but they should be testing for null literal or cell containing null. They are changed to do the right thing.
SUMIF and related functions are slightly affected by this change, and are changed so that they are no longer affected.
New tests have been added. Only one existing test had to change. MergeBehaviorTest for `[12, '=5+1', '=A1/A2']`, where cell A2 was uninitialized formerly returned one row, but now returns a second all-null row because A2, by virtue of being used in a calculation, now winds up defined. I do not consider this a significant difference.
In issue #4557, the user complains, with some justification, about the way Excel handles certain calculations. We are not able to help with that problem. However, the user also notes a problem in Shared/Date when `isDateTime` has to evaluate a cell whose calculated value is an array. This is solved by flattening the calculated result to a single value.
It became obvious while working on this change that the code to set `instanceArrayReturnType` was kind of awkward. Simpler methods `returnArrayAsArray` and `returnArrayAsValue` are added to `Spreadsheet`. Even these started out a bit awkward because `Spreadsheet::calculationEngine` was defined as nullable, which really isn't true. It is allocated by the constructor, and never freed except in the destructor. It is no longer nullable.
Fix#4542. PhpSpreadsheet has been writing attribute `xml:space="preserve"` to the `table` tag when writing a Table. According to the issue, Excel 2016 is treating the resulting file as corrupt. I do not have access to a version of Excel 2016 to confirm. This seems to be a bug with that release. Nevertheless, the OOXML spec, with over 100 references to `xml:space` does not indicate that it is a permitted attribute for `table`. It should only be specified for text nodes. This PR eliminates the undocumented, and unneeded, usage.
Investigating further, PhpSpreadsheet also writes this attribute for `workbook`, `styleSheet`, and `worksheet` tags. It is again undocumented and unneeded in those cases. Although all Excel releases, including 2016, apparently tolerate such usage, this PR also eliminates those.
Finally, there is one case where PhpSpreadsheet omits this tag when it is needed. When writing a cell whose data type is an inline string, and the string contains leading or trailing whitespace, the text tag needs to specify `xml:space`, and is now changed to do so.
In Theme, change COLOR_SCHEME_2013_PLUS_NAME to private (use COLOR_SCHEME_2013_2022_NAME instead), and delete COLOR_SCHEME_2013_PLUS (use COLOR_SCHEME_2013_2022).
Custom functions were introduced recently, with a restriction that non-custom functions could not be replaced. However, reviewing a recent issue has led me to the conclusion that it might sometimes be impractical to implement an Excel function in PhpSpreadsheet for all users, but it could still be helpful to some users to offer an implementation anyhow.
The Excel ASC function is currently unimplemented in PhpSpreadsheet, and is a candidate for replacement using the functionality added in this PR. This PR supersedes PR #4513, which I will now close, and its earlier incarnation PR #4511. For reasons discussed in 4513, I don't see a way forward for implementing the Excel ASC function in a way that would be generally usable. However, this PR would permit a user to implement ASC in a way which would satisfy the user's local requirements. See the new `testReplaceDummyFunction`; I think, or at least hope, that, despite the deficiencies of 4511 and 4513, this might satisfy the author's requirement.
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.
Xlsx conditional styles cannot be used to change alignment, nor font family, nor font size.
Conditional::getStyle currently allocates a new style as an unconditional style; it is changed to do so a conditional ctyle.
Border should not be conditionally merged if borderStyle is OMIT.
Inline Css was generating `class="gridlines gridlinesp"` for all cells. It is changed to use the worksheet settings to decide which classes to use.
Fix#4539. Conditional Formatting was recently added to Html Writer. It works fine when not using inline Css. However, when using inline Css, the code inadvertently added 2 different `style` attributes (one for the unconditional style and one for the conditional style) to the same cell. This is not valid html, and results in losing the conditional styling. This PR combines the two `style` attributes into one, which will now come after the `class`, `colspan`, and `rowspan` attributes.
Aside from the new tests, this PR changes an unusually large number of existing tests. While this might normally be considered a red flag, it is not a problem here. All of the changes involve merely changing the order of attributes within html tags; none of them affect how the generated html would appear in a browser.
Fix#4537. PhpSpreadsheet currently changes apostrophes in text values to `'`. This is perfectly valid Xml. Issue was opened because R does not handle this correctly; this is unquestionably a bug on R's part. So I was not inclined to do anything about it. However ...
User suggested a change to how `htmlspecialchars` was called. Investigating the use of that routine in PhpSpreadsheet, I found that there was some double escaping going on for cells whose type was set to `TYPE_INLINE` - `htmlspecialchars` escaped the string correctly, but it was later written as Xml using a method which escaped the data a second time. So, a real bug in PhpSpreadsheet after all.
There was one call to `htmlspecialchars` in `Shared\XmlWriter`. I replaced `writeRaw(htmlspecialchars(...))` with `text(...)`. And one call in `Writer\Xlsx\Worksheet`, the source of the double escaping bug above; the call to `htmlspecialchars` can just be eliminated there.
Making those changes, the only remaining calls to `htmlspecialchars` are in `Writer\Html`, where they belong. As a bonus, apostrophes now wind up unescaped, so R will be satisfied (even though they should fix their bug).
Fix#347, which had gone stale but is now reopened. PhpSpreadsheet is automatically replacing CR-LF and CR with LF. The reason for this is unknown, although I suggest a possibility in the issue. I am not willing to make this a breaking change. This PR adds a new property `preserveCr` with setter and getter to DefaultValueBinder (and, by extension, to StringValueBinder and AdvancedValueBinder). The property defaults to false, but users who wish to preserve CR-LF and CR can set it to true for a Spreadsheet or a Reader.
Fix#1104, which went stale over 6 years ago, and is now reopened. This PR addresses the alignment of the table, not alignment of text. Support is added for the following:
- Html. Full support.
- Mpdf. Full support, except that, when mixed LTR and RTL worksheets are output, all tables will be on the left of the page (but will be properly aligned).
- Tcpdf. Full support when all worksheets being output are RTL; no support when mixed LTR and RTL worksheets are output.
- Dompdf. No support.
By default, when an Xlsx spreadsheet is read, its calculation engine is set to `RETURN_ARRAY_AS_VALUE` for array formulas. The user does have the option to change this. However, the presence of certain metadata in the file indicates that it was saved as if `RETURN_ARRAY_AS_ARRAY` was in use. This PR tests for the metadata, and, if present, sets `...ARRAY` rather than `...VALUE`. This eliminates the need for any extra action on the user's part.
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`.
Fix#4528. Fix#2507. Ods Reader expects `table:table-row` to descend directly from `table:table`. But it turns out that it can be nested under `table:table-header-rows`, `table:table-rows`, or `table:table-row-group`. Similar considerations apply to `table:table-column`. Ods Reader is changed to process the nesting tags, and therefore the nested tags underneath them. This is a major change, but it doesn't seem to have broken any existing tests or samples.
No attempt is made to add any of the nesting tags in Ods Writer.
It should be noted that 4528 has an additional problem, which has been reported as issue #4530. It is not fixed by this PR.
Fix#4522. Although this is technically a breaking change, it is expected that very few, if any, existing programs will be affected. Nevertheless, DefaultValueBinder is implicitly used by the vast majority of programs out there, and I am reluctant to install a breaking change for something so widespread. So I will save this change for the next breaking release, which should be PhpSpreadsheet 5.0.0. There is no current schedule for that release.
For strings consisting entirely of digits, DefaultValueBinder treats the value as a string if greater than PHP_INT_MAX, or an int otherwise. This prevents the loss of precision in large integers. This treatment dates back to PHPExcel, and has been in place since 2014.
There are several problems with this approach. Excel itself maintains
[15 digits of precision](https://support.microsoft.com/en-us/office/excel-specifications-and-limits-1672b34d-7043-467e-8e27-269d656771c3).
So, string-vs-int should be decided at 999_999_999_999_999. This is much lower than PHP_INT_MAX for 64-bit, and much higher than for 32-bit. DefaultValueBinder is changed to use that new limit.
A second problem is that DefaultValueBinder is only making this adjustment for positive integers. It is changed to test absolute value.
A third problem is that DefaultValueBinder is making this adjustment only for strings, so that if you pass the number in as an int, it will not be adjusted (and will lose precision). It is changed to apply the same test for int.
Fix#4521. Reader/Csv (which can be invoked by IOFactory::read), checks the mimetype of files if they don't have a csv/tsv extension. It allows empty files, whose mimetype was set to `inode/x-empty` for Php5.3.11 through Php7.3.33 (except for 5.4.0). For 5.3.1-5.3.10, 5.4.0, and 7.4.0+, the mimetype is `application/x-empty`. Reader/Csv recognizes the `inode` version but not the `application` version, which this PR adds.
The person who issued the report also noted that, for a file consisting of cr-lf, Php8.1.* and Php8.2.* report the mimetype as `application/octet-stream`, whereas all other releases report it as `text/plain`. The behavior of Php8.1/2 seems to be a bug, and I cannot possibly guess all the conditions that might lead to that bug. So I will not fix that problem. Anyone who is adversely affected by it can either add a `csv` extension to the filename, or upgrade to Php8.3+, or pre-process the file (e.g. to make it truly empty) before passing it to PhpSpreadsheet. A test case to document the problem is added for documentary purposes; the test will be skipped for Php8.1/2, but run for all other releases.