{"record":{"id":"de887463f6b6d0ff","repo":"flarum/framework","slug":"failed-to-open-file-at-filepath","errorCode":null,"errorMessage":"Failed to open file at $filePath","messagePattern":"Failed to open file at \\$filePath","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"extensions/gdpr/src/StorageManager.php","lineNumber":37,"sourceCode":"\n    public function __construct(protected Factory $factory)\n    {\n        $this->filesystem = $this->factory->disk('gdpr-export');\n    }\n\n    /**\n     * Stores the export on the disk.\n     *\n     * @param Export $export\n     * @param string $filePath\n     *\n     * @return void\n     */\n    public function storeExport(Export $export, string $filePath): void\n    {\n        $handle = fopen($filePath, 'r');\n        if ($handle === false) {\n            throw new \\RuntimeException(\"Failed to open file at $filePath\");\n        }\n\n        $this->filesystem->writeStream($this->storageFilename($export), $handle);\n\n        fclose($handle);\n    }\n\n    /**\n     * @param Export $export\n     *\n     * @return resource|null The path resource or null on failure.\n     */\n    public function getStoredExport(Export $export)\n    {\n        return $this->filesystem->readStream($this->storageFilename($export));\n    }\n\n    /**","sourceCodeStart":19,"sourceCodeEnd":55,"githubUrl":"https://github.com/flarum/framework/blob/4b939f685389bfe8a380e9e28ddf305a1c66950c/extensions/gdpr/src/StorageManager.php#L19-L55","documentation":"The GDPR extension's storeExport() opens the generated export file with fopen(..., 'r') and throws a RuntimeException when fopen returns false — i.e. the file could not be opened for reading. The export data is then streamed into the user's storage disk via writeStream. The failing path is included in the message.","triggerScenarios":"Calling storeExport($export, $filePath) with a $filePath that doesn't exist, isn't readable by the PHP user, or whose directory denies access — any case where fopen returns false.","commonSituations":"Export generator wrote the temp file to a different tmp dir (open_basedir restrictions); permissions changed after generation; path typo or file deleted between generation and storing; safe_mode/open_basedir blocking reads on shared hosting.","solutions":["Verify the export file exists and is readable before storing: is_file() + is_readable(), and fix generation/paths accordingly","Fix filesystem permissions so the PHP process user can read the file and its directory","Check open_basedir / disable_functions restrictions in php.ini that may block fopen on the temp path","Ensure the export generation step completes and returns the correct file path"],"exampleFix":"// before\n$ext->storeExport($export, $tmpPath); // file missing\n// after\nif (!is_readable($tmpPath)) { throw new RuntimeException(\"Export missing: $tmpPath\"); }\n$ext->storeExport($export, $tmpPath);","handlingStrategy":"try-catch","validationCode":"if (!is_file($filePath) || !is_readable($filePath)) { throw new \\RuntimeException(\"Export file missing or unreadable: $filePath\"); }","typeGuard":null,"tryCatchPattern":"try { $manager->storeExport($export, $filePath); } catch (\\RuntimeException $e) { Log::error($e->getMessage()); abort(500, 'Could not store GDPR export'); }","preventionTips":["Check is_readable() on temp export files before storing","Keep export temp files in a path not blocked by open_basedir","Clean up/export promptly to avoid races deleting the file"],"tags":["file-io","gdpr","filesystem","export"],"backgroundTag":"file-open-failed","analyzedSha":"4b939f685389bfe8a380e9e28ddf305a1c66950c","analyzedAt":"2026-09-15T18:09:20.879Z","contentChangedAt":"2026-09-15T18:09:20.879Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}