0

I have a PHP script that should create a valid image file on server side. The following code runs fine:

$filename = $_GET['filename'];

// Only proceed if we got valid input
if ($filename !== null) {
    echo "$filename is not null.";
    $image = @imagecreatetruecolor(10, 10)
                or die('Cannot Initialize new GD image stream');

    if (strpos($image, '/gif') !== false) {
        $image_type = "GIF";
        header('Content-Type: image/gif');
        $successful = imagegif($image, "./$filename");
    } else if (strpos($image, '/jpeg') !== false) {
        $image_type = "JPG";
        header('Content-Type: image/jpeg');
        $successful = imagejpeg($image, "./$filename");
    } else if (strpos($image, '/png') !== false) {
        $image_type = "PNG";
        header('Content-Type: image/png');
        $successful = imagepng($image, "./$filename");
    }

    if ($successful) {
        echo "Image written to '$filename'.";
    } else {
        echo "Could not write $image_type image to '$filename'.";
    }
    imagedestroy($image);
    echo "image destroyed.";
} else {
    echo "$filename is null.";
}

This works fine & an image with the $filename is created. But actually, I have to receive not only the file name but the image also. So, the real code is

$filename = $_GET['filename'];

$image = $_GET['image'];

echo "file $filename = '$image'.";

// Only proceed if we got valid input
if ($filename !== null) {
    echo "$filename is not null.";

    if (strpos($image, '/gif') !== false) {
        $image_type = "GIF";
        header('Content-Type: image/gif');
        $successful = imagegif($image, "./$filename");
    } else if (strpos($image, '/jpeg') !== false) {
        $image_type = "JPG";
        header('Content-Type: image/jpeg');
        $successful = imagejpeg($image, "./$filename");
    } else if (strpos($image, '/png') !== false) {
        $image_type = "PNG";
        header('Content-Type: image/png');
        $successful = imagepng($image, "./$filename");
    }

    if ($successful) {
        echo "Image written to '$filename'.";
    } else {
        echo "Could not write $image_type image to '$filename'.";
    }
    imagedestroy($image);
    echo "image destroyed.";
} else {
    echo "$filename is null.";
}

This does not work, and the result is

file t.png = 'data:image/jpeg;base64,/9j/4AAQSkZJ … qA/Cz//Z'.t.png is not null.Image written to 't.png'.image destroyed.

How can I create from the 'data:image/jpeg … ' string a valid image in PHP?

EDIT 1: I added one line to the code above to see that it is not a possible duplicate of another question:

// Only proceed if we got valid input
if ($filename !== null) {
    echo "$filename is not null.";
    $image = base64_decode($image); // <<<<

EDIT 2: I modified the code so that the file is deleted:

$filename = $_GET['filename'];

$image = $_GET['image'];

// Only proceed if we got valid input
if ($filename !== null) {
    echo "$filename is not null.";
    $image = base64_decode($image);
    $slash1 = strpos($image, '/');

    $image_type = substr($image, $slash1, strpos($image, ';') - $slash1);

    if (file_exists($filename)) unlink($filename);

    header('Content-Type: image/' . $image_type);

    switch ($image_type) {
        case "gif":
            $successful = imagegif($image, "./$filename");
            break;
        case "jpeg":
        case "jpg":
            $successful = imagejpeg($image, "./$filename");
            break;
        case "png":
            $successful = imagepng($image, "./$filename");
            break;
    }

    if ($successful) {
        echo "Image written to '$filename'.";
    } else {
        echo "Could not write $image_type image to '$filename'.";
    }
    imagedestroy($image);
    echo "image destroyed.";
} else {
    echo "$filename is null.";
}

But still, I get the reply Could not write image to 't.jpg'.

EDIT 3: This is what I pass to the two parameters:

?filename=t.jpg&image=data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD/4QAiRXhpZgAATU0AKgAAAAgAAQESAAMAAAABAAEAAAAAAAD/7AARRHVja3kAAQAEAAAAPAAA/+0ALFBob3Rvc2hvcCAzLjAAOEJJTQQlAAAAAAAQAAAAAAAAAAAAAAAAAAAAAP/bAEMAAgEBAgEBAgICAgICAgIDBQMDAwMDBgQEAwUHBgcHBwYHBwgJCwkICAoIBwcKDQoKCwwMDAwHCQ4PDQwOCwwMDP/bAEMBAgICAwMDBgMDBgwIBwgMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDP/AABEIAAEAAQMBIgACEQEDEQH/xAAfAAABBQEBAQEBAQAAAAAAAAAAAQIDBAUGBwgJCgv/xAC1EAACAQMDAgQDBQUEBAAAAX0BAgMABBEFEiExQQYTUWEHInEUMoGRoQgjQrHBFVLR8CQzYnKCCQoWFxgZGiUmJygpKjQ1Njc4OTpDREVGR0hJSlNUVVZXWFlaY2RlZmdoaWpzdHV2d3h5eoOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4eLj5OXm5+jp6vHy8/T19vf4+fr/xAAfAQADAQEBAQEBAQEBAAAAAAAAAQIDBAUGBwgJCgv/xAC1EQACAQIEBAMEBwUEBAABAncAAQIDEQQFITEGEkFRB2FxEyIygQgUQpGhscEJIzNS8BVictEKFiQ04SXxFxgZGiYnKCkqNTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqCg4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2dri4+Tl5ufo6ery8/T19vf4+fr/2gAMAwEAAhEDEQA/APA6KKK/qA/Cz//Z

EDIT 4: Modified the code according to suggestions of @delboy1978uk. Also, it is not correct that the passed filename includes the image file extension, as this should always correspond to the image type:

$filename = $_GET['filename'];

$image = $_GET['image'];

echo "file $filename = '$image'.";

// Only proceed if we got valid input
if ($filename !== null) {
    $slash = strpos($image, '/') + 1;

    $image_type = substr($image, $slash, strpos($image, ';') - $slash);
    $comma = strpos($image, ',') + 1;

    $image = substr($image, $comma);

    $decoded_image = base64_decode($image);

    $image = imagecreatefromstring($decoded_image);

    echo "The image type is '$image_type'.";

    if (file_exists($filename)) {
        unlink($filename);
        echo "Deleted file '$filename'.";
    }

    header('Content-Type: image/' . $image_type);
    $filename .= '.' . $image_type;

    switch ($image_type) {
        case "gif":
            $successful = imagegif($image, "./$filename");
            break;
        case "jpeg":
        case "jpg":
            $successful = imagejpeg($image, "./$filename");
            break;
        case "png":
            $successful = imagepng($image, "./$filename");
            break;
    }

    if ($successful) {
        echo "Image written to '$filename'.";
    } else {
        echo "Could not write $image_type image to '$filename'.";
    }

    if (imagedestroy($image) === true) {
        echo "Image destroyed.";
    }
} else {
    echo "$filename is null.";
}
1

2 Answers 2

2

You are trying to send headers on a page you have already sent output to.

If you are loading from a file, You need to use imagecreatefromjpeg() and the GIF and PNG equivalents. http://php.net/manual/en/function.imagecreatefromjpeg.php

$img = imagecreatefromjpeg($file);

To get the actual string data to literally echo in your <image> tag, use output buffering:

ob_start();
imagejpeg($img)
$image = ob_get_clean();
echo '<img src="data:image/jpeg;base64,' . base64_encode( $i ).'" />';

If you are interested, I made an Image class a few years ago that handles this stuff, see here https://github.com/delboy1978uk/image/blob/master/src/Image.php and a blog about it https://delboy1978uk.wordpress.com/2014/12/01/outputting-images-as-base64-encoded-strings/

Sign up to request clarification or add additional context in comments.

8 Comments

Oh, thank you! But imagecreatefromjpeg needs a file name (of an image file) to run, and I am sending text data with a GET request from which I am supposed to create a file on the server disk. I.e. I want to duplicate the file created on the client side on the server side.
Ah ok, I thought in the second part they were sending a filename for you to open! In that case, it sounds like it is failing when the file already exists? try file_exists() and maybe remove it if it does?
Modified the code, but there is something wrong, as no file is created.
$image = $_GET['image']; - What is this then? Your working code doesn't use it, but your broken code does. Remember everything in a GET query will be url encoded? Maybe switch to post?
Ehmm. Good point, but I already switched to GET with a tiny, tiny image so that I can debug the whole issue. Actually, in this example, a GET is the only option, as I do not use any client side. The real code will have to use POST for sure, but then, I cannot see what really is the matter. But my code uses $image a lot of times, doesn't it?
|
0

The problem is solved!! Here is the code that gets the browser-cached image & sends it to a requested server location. Getting back the image from the server, it turns out to be the same image. First the JavaScript code:

[…]
var parameters = {
    […],
    headerImageLocation: '',
    image: new Image(),
    […],
};

if (strings.hasMinimalLength(blobURL, 9)) {
    this.getBlobFromURL(blobURL).then(this.fromBlobToBase64).then(function(result) {
        parameters['image'].src = result;
        parameters['headerImageLocation'] = './' + strings.generateID();

        server.continueWithNewsTicker(parameters);
    });
} else {
    this.continueWithNewsTicker(parameters);
}

// Prototype "MainServer":
MainServer.method('continueWithNewsTicker', function(parameters) {
    var url = server.ServiceTest + 'saveHeaderImage.php';

    if (strings.hasMinimalLength(parameters['headerImageLocation'], 1)) {
        var formData = new FormData();

        formData.append('filename', parameters['headerImageLocation']);
        formData.append('image', parameters['image'].src);

        this.uploadFile(formData, url);
    }
    […]
});

// Prototype "Server":
Server.method('uploadFile', function (data, url) {
    var xhr = new XMLHttpRequest();    // AJAX request

    xhr.open('POST', url);
    xhr.send(data);
});

// Prototype "Strings":
Strings.method('generateID', function () {
    function s4() {
        return Math.floor((1 + Math.random())*0x10000)
            .toString(16)
            .substring(1);
    }
    return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
        s4() + '-' + s4() + s4() + s4();
});

For those interested, the PHP code follows:

ini_set('display_errors', 1);
error_reporting(E_ALL);

// Get the input data safely
$filename = $_POST['filename'];
$image = $_POST['image'];

// Only proceed if we got valid input
if ($filename !== null) {
    // Prepare to remove "header" information:
    $comma = strpos($image, ',') + 1;
    $slash = strpos($image, '/') + 1;
    // The image type will also determine the file extension
    $image_type = substr($image, $slash, strpos($image, ';') - $slash);
    // Remove "header" information from rest of image:
    $image = substr($image, $comma);

    $decoded_image = base64_decode($image);
    $filename .= '.' . $image_type;

    if (file_exists($filename)) unlink($filename);

    $successful = file_put_contents($filename, $decoded_image);

    if ($successful) {
        echo "Image written to '$filename'.";
    } else {
        echo "Could not write $image_type image to '$filename'.";
    }
} else {
    echo "$filename is null.";
}

1 Comment

Little tip for you, displaying errors kills any header calls and ajax functionality if there is any output. For the best error logging experience, set error_reporting to -1, turn display_errors off, and set a custom error_log. Then in the terminal, type 'tail -f /path/to/error_log'. Your notices, warnings and errors will now scroll past in real time, without distorting your web page's display.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.