phpimageimage-processingjpegimage-rendering

Download PHP rendered image - not able to open on Android phone


I am using a script to: 1. render/save a image on my sserver. 2. provide the saved image as a download to the browser.

So the image is not opened, but downloaded by the browser. Works perfect.

But when i download the image on a android phone, after the download i cannot open the image from the browser/file viewer. However, in my gallery the image is present and i can open it. Looks that the browser (chrome) does not recognizes the downloaded file as a image.

Hope anyone has an idea. Maybe something with the file headers?

I call the script with a submit form button, and then the file gets downloaden, while you stay on the same page.

<?php

// #######################  Part 1, Render the image #######################

//content type
 header('Content-type: image/jpeg'); 
//font
$font = 'assets/medium.otf';
//font size
$font_size = 16;
//image width
$width = 400;
//text margin
$margin = 15;

//text
 $text = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.';

//explode text by words
$text_a = explode(' ', $text);
$text_new = '';
foreach($text_a as $word){
    //Create a new text, add the word, and calculate the parameters of the text
    $box = imagettfbbox($font_size, 0, $font, $text_new.' '.$word);
    //if the line fits to the specified width, then add the word with a space, if not then add word with new line
    if($box[2] > $width - $margin*2){
        $text_new .= "\n".$word;
    } else {
        $text_new .= " ".$word;
    }
}
//trip spaces
$text_new = trim($text_new);
//new text box parameters
$box = imagettfbbox($font_size, 0, $font, $text_new);
//new text height
$height = $box[1] + $font_size + $margin * 2;

//create image
$im = imagecreatetruecolor($width, $height);

//create colors
$white = imagecolorallocate($im, 255, 255, 255);
$black = imagecolorallocate($im, 0, 0, 0);
//color image
imagefilledrectangle($im, 0, 0, $width, $height, $white);

//add text to image
imagettftext($im, $font_size, 0, $margin, $font_size+$margin, $black, $font, $text_new);

//return image
//imagejpeg($im);
  imagejpeg($im,'images/text/name.jpg');
//frees any memory associated with image
imagedestroy($im);



// #######################  Part 2, download the image #######################

$file = 'images/text/name.jpg';

header("Expires: 0");
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
header("Cache-Control: no-store, no-cache, must-revalidate");
header("Cache-Control: post-check=0, pre-check=0", false);
header("Pragma: no-cache");

$ext = pathinfo($file, PATHINFO_EXTENSION);
$basename = pathinfo($file, PATHINFO_BASENAME);

header("Content-type: application/".$ext);
// tell file size
header('Content-length: '.filesize($file));
// set file name
header("Content-Disposition: attachment; filename=\"$basename\"");
readfile($file);

?>

EDIT: Somehow, when I remove this line then it works:

header("Content-type: application/".$ext);

Solution

  • At the beginning of your script you're saying that the content type is image/jpeg and then at the end you're saying that the content type is application/".$ext.

    For your purpose you're going to want to set the Content-Type to image/$etc for it to be interpreted by the browser as the correct MIME type. Here's a list of common MIME types.

    Also, depending on where you're getting this image files from I would be more careful than just checking the extension. At least cross check the magic numbers inside the file and cross reference this with the extension. It's probably a good idea to use Image Magick to copy the image you get from the user into a blank image. You can use this to remove extraneous meta-data and prevent some types of exploits.

    Some more information on the Content-Type header