Commit Graph

6585 Commits

Author SHA1 Message Date
oleibman 2ad65fccb5 Merge pull request #4968 from sapientpro/feature/table-header-row-needs-a-data-row
Xlsx writer: a header-row table takes the empty row below it
2026-09-02 05:08:05 +00:00
oleibman df95a8665e Merge pull request #4967 from DIReports/fix/vlookup-column-range-empty-end-column
Fix VLOOKUP #N/A with whole-column ranges when the end column contains no data
2026-09-02 05:05:11 +00:00
oleibman 11645d54ac Merge pull request #4972 from oleibman/doctypo
Minor Documentation Updates
2026-08-22 05:00:37 +00:00
oleibman b9f5c37ec4 Minor Documentation Updates 2026-08-21 21:55:09 -07:00
DIReports 24fe547e0b Remove trailing empty line in ParseFormulaTest 2026-08-20 09:28:59 +02:00
DIReports 2c83284f42 Move whole-column VLOOKUP tests to VLookupTest
Move testVlookupWholeColumnRange and providerVlookupWholeColumnRange
from ParseFormulaTest to the correct location VLookupTest, which
extends AllSetupTeardown. Adapted to use $this->getSpreadsheet()
instead of managing the Spreadsheet lifecycle manually.
2026-08-20 09:27:25 +02:00
oleibman 1f3ed4977a Merge pull request #4960 from oleibman/odsmoredates
Slight Improvement in Ods Reader Date Handling
2026-08-20 03:26:27 +00:00
oleibman 7a4832f59f Update CHANGELOG.md 2026-08-19 20:22:41 -07:00
oleibman f0e7a67c3d Merge branch 'master' into odsmoredates 2026-08-19 20:13:24 -07:00
oleibman 5619827ae9 Merge pull request #4956 from oleibman/odsdrawings2
Drawings for ODS
2026-08-20 03:05:23 +00:00
oleibman 56631e36d3 Merge pull request #4962 from saifulferoz/fix/issue-4454-ods-strings
Ods Writer: do not convert inside string literals
2026-08-20 03:03:56 +00:00
oleibman 16c49b80db Merge pull request #4958 from JulienChavee/master
Avoid getStyle on every setValueExplicit quote-prefix check
2026-08-20 01:10:00 +00:00
Dmytro Kulyk d8c46b48f9 Xlsx writer: a header-row table takes the empty row below it
A table whose range covers its header row alone makes Excel report the
workbook as unreadable; it repairs the file by dropping the table, so the
markup the table was written for is lost without a word.

Excel itself never writes such a table. Asked to make one over a single row
of headings, it writes the table over the row below as well and leaves that
row empty — its `sheetData` holds no cell for it, and the sheet dimension
stays at the headings. The writer now does the same, so what is written is
what Excel would have written.

The row below is taken only when it holds nothing. A table silently
swallowing a row that belongs to something else would change what the sheet
says, so that case throws instead, naming the row in the way.
2026-08-20 00:29:44 +03:00
Julien Chavée 241635d8c9 Fix quote-prefix numeric test to cover clearing behavior 2026-08-19 22:23:29 +02:00
Julien Chavée 5083bf023f Merge branch 'master' into master 2026-08-19 22:01:59 +02:00
Dick Ittmann 67c0c51810 Apply PHP-CS-Fixer formatting 2026-08-19 18:08:34 +02:00
Dick Ittmann f5f02202a5 Remove comment 2026-08-19 18:01:15 +02:00
Dick Ittmann 89c1b9f2fa Move tests to ParseFormulaTest 2026-08-19 18:01:05 +02:00
DIReports 5e91ce2ba2 Fix VLOOKUP #N/A with whole-column ranges when end column has no data
When resolving the end reference of a whole-column range (e.g. $A:$F),
getHighestDataRow($col) was called for the specific end column. If that
column contains no data it returns 1, producing an inverted range such as
A4:F1. This caused VLOOKUP and similar functions to return #N/A when the
formula used a whole-column reference across sheets where data only exists
in the left-hand columns.

Fix: call getHighestDataRow() without a column argument so the overall
highest data row across all columns is used for the end reference.

Reproducer:
  Sheet2!A:D has data in cols A–C only; $A:$F produced A4:F1 → #N/A.
  After fix: A1:F4 → VLOOKUP finds the value correctly.
2026-08-19 16:25:33 +02:00
oleibman 930293a32a Merge pull request #4965 from oleibman/reflect86
Php8.6 Deprecation in Reflection::invokeArgs
2026-08-17 04:01:42 +00:00
oleibman 96d442ab66 Php8.6 Deprecation in Reflection::invokeArgs
Affects one test member, no source code.
2026-08-16 20:55:28 -07:00
oleibman 746430695c Merge branch 'master' into odsmoredates 2026-08-16 20:09:53 -07:00
oleibman 3b6f63599e Handle Dates A Bit Better 2026-08-16 19:41:14 -07:00
saifulislamferoz 416cc52a94 Assert round-tripped values rather than Ods xml
Rewrite the test to write the spreadsheet, read it back and check
getValue() and getCalculatedValue(), following DurationTest, instead of
matching against the generated content.xml.
2026-08-15 15:28:08 +06:00
saifulislamferoz d3ae79dfaf Ods Writer: do not convert inside string literals
convertFormula() ran the cell reference, defined name and function name
conversions over the whole formula, so anything that looked like a reference
inside a quoted string was rewritten: ="THIS IS E1" was written out as
="THIS IS [.E1]". The comma to semicolon replacement had the same problem,
turning =IF(A1>1,"yes, really","no") into a formula whose text reads
"yes; really".

Split the formula on string literals and convert only the segments outside
of them. A range cannot be interrupted by a string literal, so every
reference still sees the context the conversion relies on.

Fixes #4454
2026-08-15 10:28:48 +06:00
oleibman 65b080eef4 Merge pull request #4952 from oleibman/stancomments
Update Phpstan and Tcpdf
2026-08-11 22:20:21 +00:00
oleibman 84de45c2f4 Slight Improvement in Ods Reader Date Handling
Based on recent discussions in #2938, it can do a bit better with date cells that do not use a recognized date style. Improve differentiating `date` from `date+time`, and in deciding whether 4-digit years have been used in the input cells. This causes a change to one test, where the old result incorrectly expected a 2-digit year (you can verify by opening the spreadsheet in question that it is saved with a 4-digit year).
2026-08-11 14:09:12 -07:00
oleibman 3431af42f9 Reorder Some Tests in RowCellIterator
Prevent exceptions in obscure situations.

Accommodate some differences with Ods format saved by Excel.
2026-08-11 11:45:03 -07:00
oleibman 538ede3aa0 Merge pull request #4959 from oleibman/fix861
First Php8.6 (Extremely Minor) Problem
2026-08-11 04:34:49 +00:00
oleibman ffac2cbe29 First Php8.6 (Extremely Minor) Problem
In 8.6, XmlWriter is declared non-serializable. This changes the result of one unit test (we receive a different exception than we had expected).
2026-08-10 21:27:15 -07:00
oleibman 50654a3e69 Add Xls to Sample 25 2026-08-10 07:14:22 -07:00
Julien Chavée bf9a0210e2 Avoid getStyle on every setValueExplicit quote-prefix check 2026-08-10 11:21:39 +02:00
oleibman e3af14f762 Coverage Tweak
Comment out some uncovered code while I figure out how to execute it.
2026-08-10 01:14:00 -07:00
oleibman 5f40cd3a06 Fix Problem with Multiple Images on Multiple Sheets
Sample 25 now provides better coverage.
2026-08-10 00:40:26 -07:00
oleibman 229ae783df Address Some Coverage Issues
I hoped to address more in Sample 25, but there were some peculiar problems. I will continue to work on those, but no reason to delay what is working.
2026-08-09 18:45:41 -07:00
oleibman 78221785c1 Add Memory Drawing Sample 2026-08-09 09:09:35 -07:00
oleibman cf709f3d3f Drawings for ODS
Fix #4809. This initial work for this PR was done by @xxltomcat-ux in PR #4812. That PR needed some work, and was accidentally closed in a manner that caused all its work to be lost. As compared with that version, this version corrects a write bug when Ods output is added to 27_Images_Xlsx, adds limited support for Read, and adds some tests (more are probably needed). What follows here is the original description from the closed PR.

# Summary

Currently, the ODS writer in PhpSpreadsheet does not support exporting images. Images (Drawing or MemoryDrawing objects) are completely ignored in ODS exports, though they work correctly for XLSX. This issue proposes and provides a full implementation to add support for image/drawing export in ODS, bringing feature parity with the XLSX writer.

# Problem

- ODS exports silently drop images and worksheet graphics
- This is a required feature for interoperability with LibreOffice/OpenOffice users

# Key Implementation:

- Update: Writer/Ods.php to collect/package images into the export ZIP
- Update: Writer/Ods/Content.php to integrate images into content.xml and table cells
- New: Writer/Ods/Drawing.php to manage extraction & XML for worksheet images (Drawing & MemoryDrawing)
- Update: Writer/Ods/MetaInf.php to list all Pictures/ images in the manifest
- Update: Reader/Ods.php to read drawing-related Xml and add those which meet certain criteria to spreadsheet.

# Features

- Exports all worksheet images (Drawing, MemoryDrawing)
- Embeds images in Pictures/ directory inside ODS
- Writes <draw:frame> and <draw:image> elements linked to cell positions
- Updates META-INF/manifest.xml with all images
- Handles cell/row mapping & coordinates
- Supports PNG, JPEG, GIF, BMP
2026-08-09 08:37:59 -07:00
oleibman 585d3c0ce4 Merge branch 'master' into stancomments 2026-08-09 02:42:11 -07:00
oleibman b9f6ba4667 2.2.7 Reported Internal Error on Win11 - Upgrade to 2.2.8 2026-08-09 02:25:59 -07:00
oleibman 33e837480c Tweaks 2026-08-09 01:20:05 -07:00
oleibman 49affe510f Merge pull request #4954 from gaoflow/fix-betainv-underflow-false-convergence
Fix BETAINV false convergence when the Beta CDF underflows
2026-08-09 07:03:04 +00:00
oleibman 3518d40436 Merge branch 'master' into fix-betainv-underflow-false-convergence 2026-08-08 23:59:16 -07:00
oleibman e91b33a638 Merge pull request #4953 from gaoflow/fix-gamma-large-shape
Fix gamma-family overflow for large shape parameters
2026-08-09 03:57:53 +00:00
oleibman 5278916aab Merge pull request #4935 from kemo/perf/xlsx-writer-cell-fetch
Reduce redundant cell lookups in Xlsx writer hot path
2026-08-09 03:49:27 +00:00
oleibman d46c2ff387 Merge pull request #4955 from PHPOffice/dependabot/composer/squizlabs/php_codesniffer-3.13.6
Bump squizlabs/php_codesniffer from 3.13.5 to 3.13.6
2026-08-08 14:52:10 +00:00
dependabot[bot] 688c44f4db Bump squizlabs/php_codesniffer from 3.13.5 to 3.13.6
Bumps [squizlabs/php_codesniffer](https://github.com/PHPCSStandards/PHP_CodeSniffer) from 3.13.5 to 3.13.6.
- [Release notes](https://github.com/PHPCSStandards/PHP_CodeSniffer/releases)
- [Changelog](https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/4.x/CHANGELOG-3.x.md)
- [Commits](https://github.com/PHPCSStandards/PHP_CodeSniffer/compare/3.13.5...3.13.6)

---
updated-dependencies:
- dependency-name: squizlabs/php_codesniffer
  dependency-version: 3.13.6
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-08-08 08:27:06 +00:00
Vincent Gao 52da37f4a7 Fix gamma-family overflow for large shape parameters
GAMMA.INV silently returned the first bisection midpoint for alpha in
~[143, 171.62] (e.g. GAMMA.INV(0.5, 143, 1) gave 358.0 instead of
142.667) and #NUM! above that, because the Newton-step pdf evaluates
Gamma(a), b**a and value**(a-1) in linear domain, all of which overflow
even though the density itself is a small representable number. The same
pattern breaks the GAMMA.DIST, CHISQ.DIST and F.DIST densities and
GAMMALN, which computed log(Gamma(x)) through Gamma(x).

Evaluate these in log domain via the existing logGamma, and scale the
incomplete-gamma series/continued-fraction iteration cap as O(sqrt(a)),
which both expansions need to converge near x ~ a once the shape is
large (GAMMA.INV drifted from the true quantile above alpha ~5000 and
returned alpha+1 by alpha=10000; same for CHISQ.INV at high df).
2026-08-07 01:14:45 +02:00
Vincent Gao 3046ce9214 Add changelog entry for #4954 2026-08-05 12:29:20 +02:00
Vincent Gao f687d261e8 Fix BETAINV false convergence when the Beta CDF underflows
calculateInverse() treated a CDF value of exactly 0.0 as "the guess is the
root" and collapsed the bracket with $b = $a, ending the search. inverse()
already rejects probability <= 0, so a CDF of 0.0 inside the bisection can
only be a float64 underflow at a guess far below the root - never an exact
hit. It is just an ordinary "guess too low" and belongs in the existing
else branch.

The underflow is reached whenever a probe lands many standard deviations
from the mean, so the search collapses after two or three iterations and
returns whichever midpoint it was holding. BETAINV(0.5, 5000, 5000) gave
0.25, though Beta(a, a) is symmetric and its median is exactly 0.5;
BETAINV(0.5, 20000, 3) gave 0.5 against a true 0.99986. Onset is around
alpha = 1080 for beta = 1, where the closed form 0.5 ** (1 / alpha) is
available to check against.

That test also happened to stop the search for shapes where incompleteBeta
declines to evaluate at all and returns 0 for every x, so inverse() now
rejects alpha + beta above that documented limit up front: the CDF is
identically zero there, so no quantile exists to search for.

Tests cover a shape x probability grid against scipy reference values plus
three checks that need no external oracle: the symmetric median, the
Beta(alpha, 1) closed form, and the BETADIST round trip / mirror identity.
2026-08-05 12:28:05 +02:00
oleibman 7e7c5eb2c8 Add Some @var Doc Blocks 2026-08-04 22:34:04 -07:00