PHPOffice/PhpSpreadsheet · error · ReaderException

Could not open file $filename for reading.

Error message

Could not open file $filename for reading.

What it means

Csv::loadSpreadsheetFromString() funnels the string into a data://text/plain URI and fopen()s it. If fopen of the data:// wrapper fails, the reader throws this. The dominant cause is allow_url_fopen=Off (a common hardening setting), which disables the URL-style stream wrappers including data://.

Source

Thrown at src/PhpSpreadsheet/Reader/Csv.php:361

    }

    public function castFormattedNumberToNumeric(
        bool $castFormattedNumberToNumeric,
        bool $preserveNumericFormatting = false
    ): void {
        $this->castFormattedNumberToNumeric = $castFormattedNumberToNumeric;
        $this->preserveNumericFormatting = $preserveNumericFormatting;
    }

    /**
     * Open data uri for reading.
     */
    private function openDataUri(string $filename): void
    {
        $fileHandle = fopen($filename, 'rb');
        if ($fileHandle === false) {
            // @codeCoverageIgnoreStart
            throw new ReaderException('Could not open file ' . $filename . ' for reading.');
            // @codeCoverageIgnoreEnd
        }

        $this->fileHandle = $fileHandle;
    }

    /**
     * Loads PhpSpreadsheet from file into PhpSpreadsheet instance.
     */
    public function loadIntoExisting(string $filename, Spreadsheet $spreadsheet): Spreadsheet
    {
        return $this->loadStringOrFile($filename, $spreadsheet, false);
    }

    /**
     * Loads PhpSpreadsheet from file into PhpSpreadsheet instance.
     */
    private function loadStringOrFile(string $filename, Spreadsheet $spreadsheet, bool $dataUri): Spreadsheet

View on GitHub (pinned to 65b080eef4)

Solutions

  1. Enable allow_url_fopen (php.ini, or ini_set('allow_url_fopen', '1') at runtime where the host permits it)
  2. If you cannot change ini settings, bypass the string API: write the content to a temporary file and call load() instead
  3. Check the setting in deployment smoke tests wherever string loading is used

Example fix

// before
$spreadsheet = (new Csv())->loadSpreadsheetFromString($csvText); // allow_url_fopen=Off -> throws

// after
if (filter_var(ini_get('allow_url_fopen'), FILTER_VALIDATE_BOOL)) {
    $spreadsheet = (new Csv())->loadSpreadsheetFromString($csvText);
} else {
    $tmp = tempnam(sys_get_temp_dir(), 'csv');
    file_put_contents($tmp, $csvText);
    $spreadsheet = (new Csv())->load($tmp);
    unlink($tmp);
}
Defensive patterns

Strategy: fallback

Validate before calling

if (!filter_var(ini_get('allow_url_fopen'), FILTER_VALIDATE_BOOL)) {
    // string API unavailable — use the temp-file route below instead of calling it
}

Try / catch

try {
    $spreadsheet = (new Csv())->loadSpreadsheetFromString($text);
} catch (ReaderException $e) {
    $tmp = tempnam(sys_get_temp_dir(), 'csv');
    file_put_contents($tmp, $text);
    $spreadsheet = (new Csv())->load($tmp); // fallback path
    unlink($tmp);
}

Prevention

When it happens

Trigger: Calling $reader->loadSpreadsheetFromString($csv) on any server where allow_url_fopen is disabled (php.ini hardening, managed hosting, strict container defaults); the string API works locally but explodes only in production.

Common situations: Code that loads CSV/HTML from strings (API payloads, DB blobs, scraped content) moving from a dev machine to a hardened production host.

Related errors


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