You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
ExcelBook::colorUnpack() now warns and returns false for colors that have no RGB value in an XLS book, such as the automatic colors COLOR_DEFAULT_FOREGROUND, COLOR_DEFAULT_BACKGROUND, and 0x7FFF, or codes 0 to 7. Previously it returned uninitialized memory as the color components. Palette colors 8 to 63 and XLSX colors are unchanged.
ExcelBook::save() no longer uses a freed workbook when a user stream wrapper reachable without :// (a data: name, or any path while the file wrapper is replaced) reloads or reinitializes the book from a callback. Such names now go through PHP streams, as fopen() resolves them, and save the workbook as it was when save() was called. loadFile(), loadFilePartially(), loadInfo(), and addPictureFromFile() follow the same resolution, and loadFileWithoutEmptyCells() rejects these names. A save whose destination stops resolving to a local file, or whose book is replaced, during the save returns false and leaves the destination unchanged.
ExcelRichString::addText() now warns and returns false when LibXL cannot decode the text: invalid UTF-8 after setLocale('UTF-8'), or otherwise bytes that the current LC_CTYPE locale cannot convert (under the C locale, any non-ASCII text). Previously it returned true while LibXL dropped the text, and the next save() of an XLS book crashed inside LibXL. If LibXL still drops text from an XLS book, save() refuses until the book is reloaded, cleared, or reconstructed.
ExcelBook::loadInfo() and loadInfoRaw() now put the book in info-only mode. Until a full load*(), clear(), or __construct(), every method except sheetCount(), getSheetName(), and the version getters warns and returns false, and the ExcelFont, ExcelFormat, ExcelSheet, ExcelRichString, ExcelConditionalFormat, and ExcelCoreProperties constructors throw. Previously the font, format, rich-string, and conditional-format APIs crashed the process on XLSX books loaded this way; XLS books in info-only mode are refused the same way.
ExcelBook::getPicture() no longer passes a NULL buffer to memcpy() for XLSX pictures added with addPictureAsLink() without embedding. It returns "data" => "" with the picture type.
ExcelFilterColumn::getCustomFilter() now reports OPERATOR_EQUAL for an operator outside the OPERATOR_* range. With LibXL 4.6.0, a one-condition filter returned an arbitrary value as operator_2. Other getters with output parameters now start them at zero, so a partial write from LibXL never returns stack contents.
Changed
Timestamp packing, date-cell writes and reads, and ExcelBook::unpackDate() now use PHP's configured timezone instead of the operating system timezone. Time-only Excel serials return seconds since midnight, rather than a timestamp derived from an all-zero calendar date.
Fixed
Floating-point AS_DATE writes now respect PHP's integer width, rejecting out-of-range timestamps on 32-bit builds before an unsafe integer conversion.
ExcelConditionalFormatting::addTimePeriodRule() now rejects unsupported time periods instead of saving an XLSX rule with an empty timePeriod value.
Blank formula writes, such as '' with ExcelFormat::AS_FORMULA or a bare '=', store an empty string instead of a formula that LibXL cannot read back from XLS files, and excel.skip_empty=2 skips them.
Date conversion now accepts pre-epoch timestamps on Windows and rejects calendar dates outside PHP's integer range instead of truncating them.
Failed saves to a read-only directory no longer leave a read-only staging file behind on Windows.
ExcelSheet::writeError() now accepts only the seven writable ERRORTYPE_* values (ERRORTYPE_NULL, ERRORTYPE_DIV_0, ERRORTYPE_VALUE, ERRORTYPE_REF, ERRORTYPE_NAME, ERRORTYPE_NUM, ERRORTYPE_NA). Every other value, including the registered ExcelSheet::ERRORTYPE_NOERROR sentinel, now warns and returns false instead of silently writing a non-error cell.
ExcelBook::save() through a user stream wrapper without rename() or __call() now always stages the workbook first, whatever other methods the wrapper implements. A short or failed staged write leaves the destination unchanged. Only a completed staged write falls back to the warned non-atomic direct write. Explicit and magic rename() handlers that fail or throw leave the destination unchanged. Wrappers that also lack unlink() keep the documented leftover sibling.
Validate write data types, filters, form controls, calculation modes, and table styles before mutating workbook state. Table styles accept the full LibXL range, including styles without a registered PHP constant. Save reservations fail closed when closing or renaming fails.