{"record":{"id":"ebc1746d0a1dc2cc","repo":"Intervention/image","slug":"unable-to-read-exif-data-division-by-zero","errorCode":null,"errorMessage":"Unable to read exif data, division by zero","messagePattern":"Unable to read exif data, division by zero","errorType":"exception","errorClass":"AnalyzerException","httpStatus":null,"severity":"warning","filePath":"src/Drivers/Gd/Analyzers/ResolutionAnalyzer.php","lineNumber":169,"sourceCode":"        }\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)) {\n            throw new AnalyzerException('Unable to read exif data');\n        }\n\n        return array_map(function (mixed $value): int|float {\n            if (strpos($value, '/') === false) {\n                return $value;\n            }\n\n            $values = array_map(fn(string $value): int => intval($value), explode('/', $value));\n\n            if ($values[1] === 0) {\n                throw new AnalyzerException('Unable to read exif data, division by zero');\n            }\n\n            return $values[0] / $values[1];\n        }, $resolution);\n    }\n\n    /**\n     * @param resource $handle\n     * @throws AnalyzerException\n     * @return array<float>\n     */\n    private function resolutionFromPngPhys($handle): array\n    {\n        rewind($handle);\n        $signature = fread($handle, 8);\n\n        // no PNG content\n        if ($signature !== \"\\x89PNG\\x0D\\x0A\\x1A\\x0A\") {","sourceCodeStart":151,"sourceCodeEnd":187,"githubUrl":"https://github.com/Intervention/image/blob/5598b9e39751c34afc5cdee84abef77f92c26f68/src/Drivers/Gd/Analyzers/ResolutionAnalyzer.php#L151-L187","documentation":"EXIF stores resolutions as rationals like \"72/1\". The parser splits on '/', intval()s both parts, and if the denominator is 0 it refuses to divide and throws instead of producing INF/NAN. This indicates a corrupt or hostile EXIF block. The exception is caught by the recovery chain and never surfaces through the public resolution() API.","triggerScenarios":"A crafted or damaged JPEG/TIFF whose XResolution is e.g. \"300/0\"; files edited by tools that write zero denominators into rational tags.","commonSituations":"Fuzzed or truncated uploads; images processed by buggy metadata writers; penetration-test fixtures.","solutions":["Nothing to fix at call time — the analyzer falls back to 96 DPI","Sanitize at ingest: reject or re-encode uploads whose exif_read_data() rationals contain zero denominators","Repair the file with exiftool -xresolution=72/1 -yresolution=72/1 if it must be kept"],"exampleFix":"// ingest-time guard\n$exif = @exif_read_data($path) ?: [];\nforeach (['XResolution', 'YResolution'] as $tag) {\n    $v = $exif['IFD0'][$tag] ?? $exif[$tag] ?? null;\n    if (is_string($v) && preg_match('#/(\\d+)$#', $v, $m) && (int) $m[1] === 0) {\n        // reject or re-encode: zero denominator in EXIF rational\n    }\n}","handlingStrategy":"fallback","validationCode":"foreach (['XResolution', 'YResolution'] as $tag) {\n    $v = $exif['IFD0'][$tag] ?? $exif[$tag] ?? null;\n    if (is_string($v) && str_contains($v, '/') && (int) substr($v, strpos($v, '/') + 1) === 0) {\n        // zero denominator: file will fail EXIF recovery\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Treat zero-denominator EXIF rationals as corrupt input at ingest","Repair with exiftool before processing when the file must be preserved"],"tags":["gd","resolution","exif","division-by-zero","corrupt-metadata"],"backgroundTag":"division-by-zero","analyzedSha":"5598b9e39751c34afc5cdee84abef77f92c26f68","analyzedAt":"2026-08-23T02:17:31.068Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}