{"record":{"id":"d8410b56a7503f47","repo":"Intervention/image","slug":"unable-to-read-exif-data","errorCode":null,"errorMessage":"Unable to read exif data","messagePattern":"Unable to read exif data","errorType":"exception","errorClass":"MissingDependencyException","httpStatus":null,"severity":"warning","filePath":"src/Drivers/Gd/Analyzers/ResolutionAnalyzer.php","lineNumber":139,"sourceCode":"        $y = unpack('n', substr($header, $offset + 10, 2))[1];\n\n        if ($units === 2) { // unit is dots per cm → convert to DPI\n            return [round($x * 2.54), round($y * 2.54)];\n        }\n\n        return [$x, $y]; // unit is DPI or no unit\n    }\n\n    /**\n     * @param resource $handle\n     * @throws MissingDependencyException\n     * @throws AnalyzerException\n     * @return array<float>\n     */\n    private function resolutionFromExifHeader($handle): array\n    {\n        if (!function_exists('exif_read_data')) {\n            throw new MissingDependencyException('Unable to read exif data');\n        }\n\n        rewind($handle);\n        $data = @exif_read_data($handle, null, true);\n\n        if ($data === false) {\n            throw new AnalyzerException('Unable to read exif data');\n        }\n\n        if (isset($data['XResolution']) && isset($data['YResolution'])) {\n            $resolution = [$data['XResolution'], $data['YResolution']];\n        }\n\n        if (isset($data['IFD0']) && isset($data['IFD0']['XResolution']) && isset($data['IFD0']['YResolution'])) {\n            $resolution = [$data['IFD0']['XResolution'], $data['IFD0']['YResolution']];\n        }\n\n        if (!isset($resolution)) {","sourceCodeStart":121,"sourceCodeEnd":157,"githubUrl":"https://github.com/Intervention/image/blob/5598b9e39751c34afc5cdee84abef77f92c26f68/src/Drivers/Gd/Analyzers/ResolutionAnalyzer.php#L121-L157","documentation":"The second resolution-recovery strategy needs PHP's exif_read_data() function; if function_exists('exif_read_data') is false, this MissingDependencyException is thrown instead of a fatal call to an undefined function. It indicates the ext-exif PHP extension is not loaded in the runtime. Like the other recovery failures it is caught by readResolutionFromOrigin()'s chain and analyze()'s catch (Throwable), so it does not escape the public API — it just means EXIF-based DPI recovery is unavailable.","triggerScenarios":"Running the GD driver on a PHP build without ext-exif (minimal Docker images, default php:8.x-alpine) and calling resolution() on an image where GD returned its default 96 DPI.","commonSituations":"Alpine/slim Docker PHP images that ship neither exif nor fileinfo by default; shared hosts with a fixed extension list; CI environments differing from production.","solutions":["Enable the exif extension: docker-php-ext-install exif (then rebuild the image), or apt install php8.x-exif","Verify with php -m | grep exif or var_dump(function_exists('exif_read_data')) in the failing environment","If you cannot change the runtime, accept the 96 DPI fallback or set resolution explicitly with setResolution()"],"exampleFix":"# before: Dockerfile\nFROM php:8.3-cli\n\n# after\nFROM php:8.3-cli\nRUN docker-php-ext-install exif","handlingStrategy":"validation","validationCode":"if (!extension_loaded('exif') || !function_exists('exif_read_data')) {\n    // EXIF-based DPI recovery unavailable; plan for 96 DPI fallback or setResolution() explicitly\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Enable ext-exif in every environment that reads image resolution (dev, CI, prod parity)","Verify with php -m | grep exif in Dockerfiles as a build-time check","Document that GD resolution recovery degrades to 96 DPI without exif"],"tags":["gd","resolution","exif","php-extension","environment"],"backgroundTag":"missing-php-extension","analyzedSha":"5598b9e39751c34afc5cdee84abef77f92c26f68","analyzedAt":"2026-08-23T02:17:31.068Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}