{"record":{"id":"89892b5cde478740","repo":"PHPOffice/PhpSpreadsheet","slug":"bitmap-doesn-t-appear-to-be-a-valid-bitmap-image","errorCode":null,"errorMessage":"$bitmap doesn't appear to be a valid bitmap image.\\n","messagePattern":"\\$bitmap doesn't appear to be a valid bitmap image\\.\\\\n","errorType":"exception","errorClass":"PhpOffice\\PhpSpreadsheet\\Writer\\Exception","httpStatus":null,"severity":"error","filePath":"src/PhpSpreadsheet/Writer/Xls/Worksheet.php","lineNumber":2480,"sourceCode":"        // Open file.\n        $bmp_fd = @fopen($bitmap, 'rb');\n        if ($bmp_fd === false || 0 === (int) filesize($bitmap)) {\n            throw new WriterException(\"Couldn't import $bitmap\");\n        }\n\n        // Slurp the file into a string.\n        $data = (string) fread($bmp_fd, (int) filesize($bitmap));\n\n        // Check that the file is big enough to be a bitmap.\n        if (strlen($data) <= 0x36) {\n            throw new WriterException(\"$bitmap doesn't contain enough data.\\n\");\n        }\n\n        // The first 2 bytes are used to identify the bitmap.\n\n        $identity = unpack('A2ident', $data);\n        if ($identity === false || $identity['ident'] != 'BM') {\n            throw new WriterException(\"$bitmap doesn't appear to be a valid bitmap image.\\n\");\n        }\n\n        // Remove bitmap data: ID.\n        $data = substr($data, 2);\n\n        // Read and remove the bitmap size. This is more reliable than reading\n        // the data size at offset 0x22.\n        //\n        $size_array = unpack('Vsa', substr($data, 0, 4)) ?: [];\n        /** @var int */\n        $size = $size_array['sa'];\n        $data = substr($data, 4);\n        $size -= 0x36; // Subtract size of bitmap header.\n        $size += 0x0C; // Add size of BIFF header.\n\n        // Remove bitmap data: reserved, offset, header length.\n        $data = substr($data, 12);\n","sourceCodeStart":2462,"sourceCodeEnd":2498,"githubUrl":"https://github.com/PHPOffice/PhpSpreadsheet/blob/65b080eef4d9fd11a5796135ab145883e5c3d6a6/src/PhpSpreadsheet/Writer/Xls/Worksheet.php#L2462-L2498","documentation":"BMP files must begin with the 2-byte ASCII signature 'BM'. processBitmap() unpacks the first two bytes and throws when they differ, so PNG/JPEG/GIF/WEBP content is rejected even if the filename ends in .bmp. The file was opened and is large enough - it is simply not a bitmap.","triggerScenarios":"Passing a PNG or JPEG renamed to .bmp to insertBitmap(); passing a data-stream or non-image file that survived the size check.","commonSituations":"Assuming the file extension equals the real format; pipelines that 'convert' images by renaming; files served with the wrong content by an upstream system.","solutions":["Convert the image to an actual BMP (e.g. imagebmp() from GD) before inserting","Detect the real format with getimagesize() and route accordingly","Use the Drawing API with PNG/JPEG, which handles modern formats natively"],"exampleFix":"// before\n$worksheetWriter->insertBitmap(1, 1, 'photo.png.bmphack'); // PNG data\n\n// after\n$im = imagecreatefrompng('photo.png');\nimagebmp($im, 'photo.bmp');\n$worksheetWriter->insertBitmap(1, 1, 'photo.bmp');","handlingStrategy":"validation","validationCode":"function isWindowsBmp(string $path): bool\n{\n    $fh = fopen($path, 'rb');\n    if ($fh === false) {\n        return false;\n    }\n    $magic = fread($fh, 2);\n    fclose($fh);\n\n    return $magic === 'BM';\n}\n\nif (!isWindowsBmp($path)) {\n    $info = getimagesize($path) ?: [];\n    throw new InvalidArgumentException(\n        'Not a BMP (detected ' . ($info[2] ?? 'unknown') . '); convert before insertBitmap()'\n    );\n}\n$worksheetWriter->insertBitmap($row, $col, $path);","typeGuard":null,"tryCatchPattern":"try {\n    $worksheetWriter->insertBitmap($row, $col, $path);\n} catch (\\PhpOffice\\PhpSpreadsheet\\Writer\\Exception $e) {\n    if (str_contains($e->getMessage(), 'valid bitmap')) {\n        // route through GD to convert whatever it is into a 24-bit BMP, then retry once\n    }\n}","preventionTips":["Never trust extensions: sniff magic bytes or use getimagesize() before embedding","Standardize on PNG/JPEG + Drawing API; only fall back to BMP for legacy .xls requirements"],"tags":["phpspreadsheet","xls","bitmap","image-format","magic-bytes"],"backgroundTag":"unsupported-image-format","analyzedSha":"65b080eef4d9fd11a5796135ab145883e5c3d6a6","analyzedAt":"2026-08-17T05:40:41.646Z","schemaVersion":2},"datasetVersion":"2026-08-17T09:17:11.063Z"}