PHPOffice/PhpSpreadsheet · error · PhpOffice\PhpSpreadsheet\Reader\Exception

Expecting 8 byte string

Error message

Expecting 8 byte string

What it means

Thrown by OLE::OLE2LocalDate() when the binary timestamp it was handed is not exactly 8 bytes. OLE property timestamps are 64-bit values (100ns ticks since 1601) stored as 8 raw bytes; a different length means the caller sliced the property block incorrectly or the stream is truncated.

Source

Thrown at src/PhpSpreadsheet/Shared/OLE.php:540

            $res = pack('c', $hex) . $res;
            $big_date = fmod($big_date, $factor);
            $factor /= 256;
        }

        return $res;
    }

    /**
     * Returns a timestamp from an OLE container's date.
     *
     * @param string $oleTimestamp A binary string with the encoded date
     *
     * @return float|int The Unix timestamp corresponding to the string
     */
    public static function OLE2LocalDate(string $oleTimestamp)
    {
        if (strlen($oleTimestamp) != 8) {
            throw new ReaderException('Expecting 8 byte string');
        }

        // convert to units of 100 ns since 1601:
        /** @var int[] */
        $unpackedTimestamp = unpack('v4', $oleTimestamp) ?: [];
        $timestampHigh = (float) $unpackedTimestamp[4] * 65536 + (float) $unpackedTimestamp[3];
        $timestampLow = (float) $unpackedTimestamp[2] * 65536 + (float) $unpackedTimestamp[1];

        // translate to seconds since 1601:
        $timestampHigh /= 10000000;
        $timestampLow /= 10000000;

        // days from 1601 to 1970:
        $days = 134774;

        // translate to seconds since 1970:
        $unixTimestamp = floor(65536.0 * 65536.0 * $timestampHigh + $timestampLow - $days * 24 * 3600 + 0.5);

View on GitHub (pinned to 65b080eef4)

Solutions

  1. Retry with a freshly exported copy of the workbook; confirm the file opens in Excel/LibreOffice.
  2. Wrap property-heavy loads in try/catch and, if only metadata is affected, fall back to loading with readDocumentProperties disabled (the Xls reader option) so the damaged summary stream is not parsed.
  3. Reject or quarantine uploads that fail structural checks (size, signature) to keep malformed files out of the parser.
  4. Keep PhpSpreadsheet updated, since robustness fixes for truncated property streams land in releases.

Example fix

// before
$reader = new \PhpOffice\PhpSpreadsheet\Reader\Xls();
$spreadsheet = $reader->load('legacy.xls'); // Expecting 8 byte string

// after
$reader = new \PhpOffice\PhpSpreadsheet\Reader\Xls();
$reader->setReadDocumentProperties(false); // skip damaged summary stream
$spreadsheet = $reader->load('legacy.xls');
Defensive patterns

Strategy: fallback

Validate before calling

// No reliable pre-check for damaged summary streams; disable property parsing when
// a file is known to come from a flaky source:
$reader = new \PhpOffice\PhpSpreadsheet\Reader\Xls();
$reader->setReadDocumentProperties(false);

Try / catch

try { $spreadsheet = $reader->load($file); }
catch (\PhpOffice\PhpSpreadsheet\Reader\Exception $e) {
    if (str_contains($e->getMessage(), 'Expecting 8 byte string')) {
        $reader->setReadDocumentProperties(false);
        $spreadsheet = $reader->load($file); // retry without metadata
    } else { throw $e; }
}

Prevention

When it happens

Trigger: Reader\Xls calls OLE::OLE2LocalDate(substr($this->summaryInformation, $offset, 8)) when parsing document properties; a summary-information sector shorter than expected (truncated file) yields fewer than 8 bytes and the strlen() != 8 check throws. Direct calls with a hand-built string of the wrong length also trigger it.

Common situations: .xls files with missing/incomplete SummaryInformation streams (common in files from old ERP exports or files cut off mid-write); corrupted uploads; tools that rewrite summary streams incorrectly.

Related errors


AI-assisted analysis of PHPOffice/PhpSpreadsheet@65b080eef4 (2026-08-17). Data as JSON: /api/errors/4c985b94f1e30a9a. Report an issue: GitHub.