Skip to content

2.4.0

Latest

Choose a tag to compare

@iliaal iliaal released this 10 Jul 00:37
2.4.0
93cd0bb

Security

  • excel.license_key and excel.license_name are now PHP_INI_SYSTEM, so a per-request ini_set() or .user.ini can no longer overwrite the commercial license in a shared pool (a runtime key can still be passed to the ExcelBook constructor).

Added

  • ExcelSheet::getIndexRange() now includes the range's "name" in the returned array (libxl exposes it; it was previously discarded).

Changed

  • ExcelBook::load(), loadFile(), and save() now emit an E_WARNING carrying the underlying libxl error message on failure, matching ExcelSheet::write(); they previously returned a bare false with no diagnostic.
  • SECURITY.md and the README now document writing untrusted values with ExcelFormat::AS_TEXT to prevent spreadsheet formula injection (the implicit leading-'=' formula promotion is unchanged).
  • Documented the previously-undocumented ExcelSheet::removeComment() method and the load()/loadFile() contract that a load invalidates any previously-fetched child wrappers (they must be re-fetched), success or failure.

Fixed

  • ExcelFont::size() now rejects a non-positive size (E_WARNING + false) instead of silently ignoring it and returning the current size as if it were a getter. Getter mode (no argument or null) and valid sizes are unchanged.
  • ExcelBook::save() to a stream path (e.g. file://) no longer truncates and destroys the caller's existing file on a short or interrupted write; wrappers that cannot rename fall back to a non-atomic direct write (plain paths were already atomic via libxl).
  • load(), loadFile(), loadInfoRaw(), and addPictureFromString()/addPictureFromFile() now reject buffers larger than UINT_MAX instead of silently truncating a >4 GiB payload at libxl's unsigned size parameter.
  • ExcelSheet::writeRow()/writeCol() now reject an unwritable value (bad type, embedded NUL, unpackable AS_DATE) before writing any cell, instead of committing earlier cells and then failing mid-array.
  • Inverted ranges (first > last) are now rejected across the range methods (hyperlinks, autofilter setRef, conditional formatting, data validation, clear, insert/remove row/col) instead of being stored as garbage coordinates; equal endpoints stay valid.
  • ExcelSheet::write() with ExcelFormat::AS_DATE now fails (returns false) when no date format can be allocated (the xlsx style table is exhausted), instead of writing a bare number and reporting success.
  • ExcelSheet::autoFilter() and ExcelAutoFilter::column()/columnByIndex() now return false when libxl yields no handle, matching their documented |false return, instead of a usable-looking object that only failed on the next method call.
  • ExcelRichString::addText() now rejects a font that belongs to a different ExcelBook, closing the last cross-book handle gap (the other use-sites were already guarded).
  • ExcelSheet::write() with ExcelFormat::AS_DATE now packs float timestamps as dates; previously only integer timestamps were treated as dates.
  • ExcelBook::addPictureFromFile() now fails closed with a single warning when a plain path is denied by open_basedir, instead of emitting a duplicate warning and falling through to the stream wrapper.
  • Re-invoking a child object's __construct() (e.g. ExcelFont, ExcelFilterColumn) no longer leaks a reference to the previously bound parent.
  • docs/ API reference signatures now match the implementation: ExcelAutoFilter::setRef() argument order, the removed nonexistent third argument on ExcelSheet::insertRow()/insertCol()/removeRow()/removeCol(), and the corrected bool/int/required parameter types on the ExcelConditionalFormatting rule methods.
  • ExcelSheet::write()/writeRow()/writeCol() now reject a non-finite (NAN/INF) number, and an AS_DATE double beyond zend_long range, instead of storing a corrupt cell or casting out of range.
  • A reference cycle through a child wrapper's hidden parent (e.g. $book->prop = $sheet) is now reclaimable by the cycle collector; get_gc handlers expose the parent that previously leaked such cycles until request shutdown.
  • Zero-arg methods across all classes now throw ArgumentCountError on surplus arguments instead of triggering a debug-build arginfo/zpp mismatch fatal (the earlier pass missed the methods whose arginfo is a shared alias).
  • ExcelFormat::fillPattern()'s named argument is now $pattern (was misspelled $patern in the generated arginfo), so pattern: named calls resolve.
  • ExcelBook::loadInfo() and loadInfoRaw() now emit the libxl error message on failure, matching load()/loadFile().
  • ExcelBook::save()'s stub return type is now string|bool (was the invalid string|true|false union that broke stub linting and regeneration); the runtime signature is unchanged.

Hardening

  • ExcelBook::loadFile(), loadFilePartially(), and addPictureFromFile() reject a seekable stream whose stat size is >= UINT_MAX up front, and otherwise cap the read at UINT_MAX, so an oversized source cannot allocate ~4 GiB before rejection.
  • Module globals now install the ZTS TLS cache (ZEND_TSRMLS_CACHE_*), so EXCEL_G access on a threaded build no longer does a per-access thread-local lookup.
  • CI build and test steps now fail on a non-zero make/run-tests exit (previously a compile failure with no 'warning:' output, or a runner crash before the summary line, could pass green).