Skip to content

Releases: iliaal/php_excel

2.0.1

03 May 14:31
2.0.1
d0d6cc0

Choose a tag to compare

Changed (semantics)

  • Optional getter/setter methods on ExcelFormat and ExcelFont now treat explicit null as "getter mode" instead of silently mutating state. Previously the |l ZPP weak-coerced null to 0, fired the setter, and reset the underlying slot — $F->numberFormat(null) reset format 7 to 0 on a Format already pointed at format 7, and $f->name(null) reset "Arial" to "" because |S weak-coerced null to "". The new semantics: argument omitted or null → getter; any non-null value → setter (range-checked against the libxl int boundary). Affects ExcelFormat::numberFormat, horizontalAlign, verticalAlign, wrap, rotate, indent, shrinkToFit, borderStyle, borderColor, borderLeftStyle/ Color, borderRightStyle/Color, borderTopStyle/Color, borderBottomStyle/Color, borderDiagonalStyle/Color, fillPattern, patternForegroundColor, patternBackgroundColor, locked, hidden, ExcelFont::size, italics, strike, bold, color, mode, underline, name. Stubs and IDE reference docs are updated accordingly (?int $foo = null, ?bool $foo = null, ?string $name = null).

Added

  • Comprehensive test coverage for FormControl (all 7 control types)
  • Tests for previously untested methods: Book::addPictureAsLink, Book::conditionalFormat, Sheet::removeComment
  • Tests for untested optional parameters across ExcelBook, ExcelSheet, ExcelFormat, ExcelFilterColumn, ExcelRichString, ExcelConditionalFormatting, and ExcelTable classes
  • Licensed-only test for row 0 access and large cell counts

Changed

  • Tag convention: 2.0.1+ uses bare semver tags (e.g. 2.0.1). 2.0.0 was tagged as v2.0.0.
  • Migrated to stub-driven arginfo (excel.stub.php + generated excel_arginfo.h). Method parameter and return types are now declared and visible to Reflection / IDEs / static analyzers; previously they were untyped at the engine boundary on most methods. Behavior is unchanged. excel.c shrinks by 2010 lines (the inline arginfo blocks and per-class function-entry tables now come from the generated header). libxl-version-conditional methods (addConditionalFormatting, loadInfoRaw, setPassword, etc.) use #if LIBXL_VERSION >= ... blocks in the stub; gen_stub passes them through to the generated header.
  • php_excel.h carries a polyfill for zend_register_internal_class_with_flags (added in PHP 8.4) so the generated arginfo header compiles cleanly against the project's PHP 8.3 minimum.

Fixed (correctness)

  • Book::getSheet(), Book::deleteSheet(), Book::getSheetName(), Book::sheetType(), Book::copySheet(), Book::setActiveSheet(), Book::activeSheet(), Book::conditionalFormat(), Book::getPicture(), Book::moveSheet(), Sheet::delHyperlink(), Sheet::merge(), Sheet::delMergeByIndex(), Sheet::getNamedRange(), Sheet::getVerPageBreak(), Sheet::getHorPageBreak(), Sheet::getPictureInfo(), Sheet::hyperlink(), Sheet::table(), Sheet::removePictureByIndex(), Sheet::formControl(), Sheet::getTableByIndex(), Sheet::conditionalFormatting(), Sheet::removeConditionalFormatting(), Sheet::addPictureScaled(), Sheet::addPictureDim(), AutoFilter::column(), AutoFilter::columnByIndex(), AutoFilter::setSort(), AutoFilter::addSort(), FilterColumn::__construct(), FilterColumn::filter(), RichString::getText(), FormControl::__construct(), FormControl::item(), and Table::columnName() now reject sheet/index values that exceed INT_MAX instead of silently wrapping when libxl narrows to int. Previously getSheet(2**32) aliased to index 0 and deleteSheet(2**32) deleted sheet 0; the same narrowing applied to every other zend_long-to-libxl-int boundary, including addPictureScaled / addPictureDim where pic_id and the dimensional / offset / pos arguments wrapped — a pic_id = 2**32 call used to alias to picture index 0 and silently embed the wrong picture into the sheet.
  • Non-index integer setters on ExcelFormat and ExcelFont (numberFormat, all border*Style / border*Color, fillPattern, pattern*Color, Font::size, Font::color, Font::mode, Font::underline, rotate, indent) now reject values outside [0, INT_MAX] instead of silently truncating on the implicit int cast — numberFormat(2**32 + 1) and Font::color(2**32 + 1) previously both became 1.
  • Stub argument types and runtime ZPP signatures for Sheet::groupRows(), Sheet::groupCols(), Sheet::setPrintHeaders(), and ExcelFormat::wrap() / shrinkToFit() / locked() / hidden() are now consistent. The stubs declared int/string/mixed for parameters the C parsed as bool, fataling under debug PHP's arginfo / ZPP checker on calls like setPrintHeaders(true). The IDE reference files in docs/ (ExcelSheet.php, ExcelFormat.php, ExcelAutoFilter.php) were also updated so their published signatures match runtime reflection — groupRows/groupCols now publish bool $collapse = false, setPrintHeaders publishes bool $value, wrap/shrinkToFit/locked/hidden publish bool ... = false, and ExcelAutoFilter::setRef publishes the required four int arguments instead of optional defaults.
  • ExcelAutoFilter::__construct() stub now requires the ExcelSheet argument (was advertised as optional nullable). The C had always required it; reflection-driven callers replaying the documented default null got TypeError.
  • Sheet::addDataValidationDouble() left the optional $val_2 parameter uninitialized when the caller used a non-(NOT)BETWEEN operator. The C declared double val_1, val_2; without a default, so the unused slot forwarded a stack-garbage value to xlSheetAddDataValidationDoubleEx. Initialized to 0.0 so the unused slot is deterministic.
  • Stub defaults for Sheet::addDataValidation() and Sheet::addDataValidationDouble() now match the C implementation: allow_blank=true, show_inputmessage=true, show_errormessage=true, error_style=1. The previous stub said false/0, so reflection-driven callers using getDefaultValue() got opposite behavior from the documented defaults.
  • Sheet::addDataValidation() and Sheet::addDataValidationDouble() now treat null (and, for the string variant, an empty string) as "second value not supplied". The check that BETWEEN/NOT-BETWEEN operators require a second endpoint previously only looked at ZEND_NUM_ARGS(), so a reflection-driven caller replaying getDefaultValue() ("" for string, 0.0 for double) sneaked past the guard and produced a one-sided rule. Stub $val_2 is now ?string $val_2 = null / ?float $val_2 = null. The double variant uses FAST_ZPP Z_PARAM_DOUBLE_OR_NULL so PHP's standard d coercion (numeric strings, bool, int) still applies to $val_2, matching $val_1. Only explicit null (or omission) trips the BETWEEN guard.
  • Book::activeSheet()'s stub default is now -1 (the C "getter mode" sentinel). The previous default of 0 caused reflection-driven calls to silently switch the workbook back to sheet index 0 instead of just returning the current active sheet.
  • Stale ZPP comments in excel.stub.php for insertSheet, setCellFormat, and writeError now reflect the typed-object signatures actually parsed by the C (O/O!).

Security

  • ExcelSheet::setColWidth() and setRowHeight() now reject non-ExcelFormat objects with TypeError instead of crashing. ZPP previously parsed the optional format as a generic zval, so passing a scalar would feed garbage to FORMAT_FROM_OBJECT() and segfault.

  • Sheet::applyFilter2(), ConditionalFormatting::addRule() / addTopRule() / addOpNumRule() / addOpStrRule() / addAboveAverageRule() / addTimePeriodRule(), and Sheet::writeRichStr() now route their object arguments through the standard *_FROM_OBJECT macros so a stale ExcelAutoFilter/ExcelConditionalFormat/ ExcelRichString (after Book::load() etc.) raises a warning and returns false instead of dereferencing a freed libxl handle.

  • ZPP signatures for Sheet::setCellFormat(), Sheet::writeError(), and Book::insertSheet() were tightened from generic o to O/O! with the expected class entry. Previously the methods accepted any object, reaching the *_FROM_OBJECT macros with a stdClass and producing an arginfo/ZPP fatal under debug PHP and undefined behaviour otherwise. Calls now raise TypeError at the boundary as the stub advertises.

  • Book::loadInfo() and Book::addPictureAsLink() now run php_check_open_basedir() before handing the path to libxl. The two methods talked to libxl directly without a stream wrapper, so paths outside open_basedir were readable / linkable into otherwise permitted output workbooks.

  • ExcelFormat::__construct(), ExcelFont::__construct(), ExcelSheet::__construct(), ExcelRichString::__construct(), ExcelConditionalFormat::__construct(), and ExcelCoreProperties::__construct() now throw when handed an uninitialized ExcelBook (e.g. one obtained via ReflectionClass::newInstanceWithoutConstructor()). Previously BOOK_FROM_OBJECT warned and returned false, but PHP ignores constructor return values, so the caller received an unusable child wrapper that crashed only on first use.

  • Sheet::writeRow() and Sheet::writeCol() pre-validate the full target range before mutating any cell. An overflowing run (e.g. XLS writeRow(1, [a, b], 255) where col 255+1=256 is past the limit) used to write the first cells and only fail on the overflowing one, leaving partial data behind. Now it fails before any write. The start coordinate is validated before any signed arithmetic on it, so extreme inputs (PHP_INT_MIN / PHP_INT_MAX) don't trip UBSan.

  • Book::moveSheet() bumps the book generation on success. Previously existing ExcelSheet wrappers silently retargeted to the wrong sheet when indices shifted under them.

  • Stale child wrapper crashes: an ExcelSheet/ExcelFormat/ExcelFont/etc. retained from before `Book::loa...

Read more

v2.0.0

05 Apr 18:43
e92dba8

Choose a tag to compare

[2026-04-05] - Version 2.0.0
* Added PHP 8.3, 8.4, 8.5 and master support
* Minimum PHP version is now 8.3
* Minimum LibXL version is now 4.6.0
* Added PIE (PHP Installer for Extensions) support via composer.json
* Fixed crash when trying to read an empty file (from unreleased 1.0.3)
* Fixed bug with writing references (see issue #234, from unreleased 1.0.3)
* Fixed memory leaks in setProtect(), addDataValidation(), addDataValidationDouble()
* Fixed use-after-free when parent object is GC'd before child
* Fixed memory corruption in getIndexRange() on 64-bit (int/zend_long aliasing)
* Fixed NULL pointer dereferences in FilterColumn::filter(), getCustomFilter(),
addPicture(), Sheet::writeError()
* Fixed Sheet::autoFilter() returning true instead of ExcelAutoFilter object
* Fixed AutoFilter::column()/columnByIndex() returning true instead of FilterColumn
* Fixed AutoFilter::getRef()/getSortRange() writing wrong value to col_last key
* Fixed FilterColumn::__construct() arginfo/parameter mismatch
* Fixed Book::getSheetName() rejecting 0-based index
* Fixed Sheet::cellFormat() not setting book handle on returned format
* Fixed constructors returning false on error (now throw exceptions)
* Replaced all zend_bool with bool, long with zend_long
* Replaced getThis() with ZEND_THIS, ZEND_NUM_ARGS() checks with
ZEND_PARSE_PARAMETERS_NONE()
* All classes marked ZEND_ACC_NOT_SERIALIZABLE
* Added typed parameter arginfo (399 parameters) and return type arginfo
(277 methods)
* Added new classes:
- ExcelRichString (rich text with mixed fonts in a single cell)
- ExcelFormControl (checkboxes, dropdowns, buttons, spinners, etc.)
- ExcelConditionalFormat (conditional formatting style rules)
- ExcelConditionalFormatting (conditional formatting ranges and rules)
- ExcelCoreProperties (workbook metadata: title, author, dates, etc.)
- ExcelTable (structured table support for xlsx)
* Added new ExcelBook methods:
- addRichString(), calcMode(), setCalcMode()
- addConditionalFormat(), addFormatFromStyle()
- removeVBA(), removePrinterSettings()
- dpiAwareness(), setDpiAwareness()
- coreProperties(), removeAllPhonetics()
- getLibXlVersion(), getPhpExcelVersion()
- addPictureAsLink(), moveSheet()
* Added new ExcelBook methods (requires LibXL 5.0.0+):
- setPassword(), dpiAwareness(), setDpiAwareness()
* Added new ExcelBook methods (requires LibXL 5.0.1+):
- loadInfoRaw()
* Added new ExcelBook methods (requires LibXL 5.1.0+):
- errorCode(), conditionalFormat(), conditionalFormatSize(), clear()
* Added new ExcelSheet methods:
- firstFilledRow(), lastFilledRow(), firstFilledCol(), lastFilledCol()
- removePicture(), removePictureByIndex()
- isRichStr(), readRichStr(), writeRichStr()
- formControlSize(), formControl()
- getActiveCell(), setActiveCell()
- selectionRange(), addSelectionRange(), removeSelection()
- tabColor(), getTabRgbColor(), setTabRgbColor()
- hyperlinkIndex()
- colWidthPx(), rowHeightPx(), colFormat(), rowFormat()
- setColPx(), setRowPx(), setBorder()
- addTable(), getTableByName(), getTableByIndex()
- applyFilter2()
- addConditionalFormatting()
- addDataValidation(), addDataValidationDouble(), removeDataValidations()
* Added new ExcelSheet methods (requires LibXL 5.1.0+):
- conditionalFormatting(), removeConditionalFormatting()
- conditionalFormattingSize()
* Added ExcelAutoFilter::addSort()
* Added ExcelSheet::AS_STRING const (from unreleased 1.0.3, PR 183 by ederuiter)
* Added constants for CalcMode, CellStyle, TableStyle, FormControl types,
ConditionalFormat types/operators/time periods, and CFVOType

PHP Excel 1.0.2 for PHP7

23 Jun 14:17

Choose a tag to compare

* Fixed bug in ExcelSheet::addPictureDim() (see issue #120)
* Fixed bug in ExcelSheet::isLicensed() (see issue #122)
* Added new methods (requires LibXL 3.6.2)
    - ExcelBook::setAutoFitArea()
    - ExcelBook::printArea()
    - ExcelBook::printRepeatCols()
    - ExcelBook::printRepeatRows()
* Added support for LibXL 3.6.3
* ExcelSheet::addPictureDim() & ExcelSheet::addPictureScaled() now support position parameters
* Includes official PHP7 release
* Added support for libxl compiled from source

PHP Excel 1.0.2 for PHP5

23 Jun 14:41

Choose a tag to compare

  • Fixed bug in ExcelSheet::addPictureDim() (see issue #120)
  • Fixed bug in ExcelSheet::isLicensed() (see issue #122)
  • Added new methods (requires LibXL 3.6.2)
    • ExcelBook::setAutoFitArea()
    • ExcelBook::printArea()
    • ExcelBook::printRepeatCols()
    • ExcelBook::printRepeatRows()
  • Added support for LibXL 3.6.3
  • ExcelSheet::addPictureDim() & ExcelSheet::addPictureScaled() now support position parameters
  • Added support for libxl compiled from source

PHP Excel 1.0.1

26 Feb 16:11

Choose a tag to compare

* Added methods
    - ExcelBook::sheetType()
    - ExcelSheet::colHidden()
    - ExcelSheet::rowHidden()
    - ExcelSheet::setColHidden()
    - ExcelSheet::setRowHidden()
    - ExcelSheet::isLicensed()
* Added new methods (requires LibXL 3.6.0)
    - ExcelSheet::hyperlinkSize()
    - ExcelSheet::hyperlink()
    - ExcelSheet::delHyperlink()
    - ExcelSheet::addHyperlink()
    - ExcelSheet::mergeSize()
    - ExcelSheet::merge()
    - ExcelSheet::delMergeByIndex()
    - ExcelSheet::splitInfo()
* Added data type argument for ExcelSheet::writeCol() (see issue #29)
* Fixed bug in ExcelSheet::read() (see issue #86)
* Fixed bug in ExcelBook::setDefaultFont() (see issue #66)
* Added autofit support for ExcelBook::setColWidth()
* Added implicit formula recognition on ExcelSheet::write() operations (prefix formula with '=')
* Added multibyte support for license name and license key (see issue #60 and README)
* Added default date format when writing dates
* Added ExcelSheet::__construct(ExcelBook $book, $name) for customized ExcelSheets
* Added warnings on read/write errors
* Removed final keyword for ExcelFormat::__construct(ExcelBook $book)
* Removed invalid PAPER_* constants in ExcelSheet
* Removed invalid COLOR_* constants in ExcelFormat
* Updated documentation and README
* Changed php.ini variable name: excel.ini_skip_empty --> excel.skip_emtpy

PHP-Excel v1.0

03 Jun 11:05

Choose a tag to compare

* Fixed issue #63 writing for NULL values using writeRow()
* Added excel.skip_empty INI setting that allows null values to be skipped, if set to 2 the empty strings will be skipped as well
* Added Sheet::setRightToLeft() and Sheet::setRightToLeft() methods that specifies whether the sheet in is "right to left" display mode
* Added Book::isTemplate() and Book::setTemplate() methods for detecting xltx files and converting from xlsx to xltx and vice versa
* Fixed compilation with LibXL 3.5.4
* Added optional scope parameter to setNamedRange()/delNamedRange()/getNamedRange() methods
* Updated getNamedRange()/getIndexRange() methods to retrieve hidden state
* Added parameter to readRow/readCol/read methods that specifiy whether to parse formula or its value.
* Added ExcelBook::packDateValues() method for generating Excel date value
* Added ExcelBook::setPrintArea() method for setting print area
* Fixed parsing of non-numeric formulas inside read() method
* Fixed parameter processing inside ExcelSheet::getVerPageBreak()/getHorPageBreak() methods
* Fixed parameter order inside ExcelSheet::getNamedRange()/getIndexRange() methods
* Fixed return value processing inside ExcelBook::setActiveSheet() method

PHP Excel v0.9.9

19 Nov 00:21

Choose a tag to compare

  • Added ExcelBook::IsDate1904/ExcelBook::ISetDate1904 methods to set/retrieve base date format
  • Allow compilation against LibXL 3.5.3
  • Fixed bug with parameter order inside setNamedRange method (jacksonja)