0

I’m learning PHP & I’m working on a simple upload and display image exercise out of a Apress PHP book. I’m using the latest Eclipse program, XAMPP, Apache, etc…

The problem I’m having is that the image being uploaded is a JPEG but it is being read as type PJPEG. It pushes my IF statement to the FALSE section with my error messages.

If I change the all the criteria to pjpeg, then for some reason I get weird raw code instead of a picture.

How do I ensure that my image being loaded stays a jpeg or how can I rewrite my code to upload and output a pjpeg and actually display in browser.

UPDATE: the code provided by Jake is working but the image itself is not displaying in browsers. Tested in Chrome, Firefox and IE.

<?php 

error_reporting(E_ALL);

if ($_SERVER['REQUEST_METHOD'] == 'POST') {

    if ( isset($_FILES['photo']) && 
        is_uploaded_file($_FILES['photo']['tmp_name']) && 
        $_FILES['photo']['error']==UPLOAD_ERR_OK ){

            if ($_FILES['photo']['type'] == 'image/jpeg'){

                $j = imagecreatefromjpeg($_FILES['photo']['tmp_name']);

                header('Content-Type: image/jpeg'); 

                imagejpeg($j);

                imagedestroy($j);

            } else {
                echo "Uploaded file was not a jpeg. <br />";
                echo "The file ", $_FILES['photo']['name'], " uploaded was a ", $_FILES['photo']['type'];
            }
    } else {
        echo "No photo upload"; 
    }
} else {

?>

<form action="test.php" method="post" enctype="multipart/form-data">
    <label for="photo">User Photo:</label>
    <input type="file" name="photo" />
    <input type="submit" name="submit" value = "Upload a JPEG" />
</form>

<?php } ?>
Ricco
  • 1
  • 4
  • Show the results of `var_dump($_FILES['photo'])` – John Conde May 15 '14 at 01:11
  • this is what i got array(5) { ["name"]=> string(10) "sample.jpg" ["type"]=> string(11) "image/pjpeg" ["tmp_name"]=> string(24) "C:\xampp\tmp\php1A4D.tmp" ["error"]=> int(0) ["size"]=> int(7048) } – Ricco May 15 '14 at 01:22
  • @Ricco I provided a full answer, but just so you know `image/pjpeg` is an Internet Explorer specific mime type. Try using another browser like Chrome, FireFox, Safari or even Opera. – Giacomo1968 May 15 '14 at 01:30
  • 1
    I have eclipse setup to use Chrome as my default internal and external browser. i even tested the code in firefox and got the same thing. i read online that there are funky things about pjpeg in internet explorer; i'm advoiding IE until it the basic problem solved. @Jake, THANKS! – Ricco May 15 '14 at 01:36

2 Answers2

2

Change the code from this:

if ($_FILES['photo']['type'] == 'image/jpeg'){
    $j = imagecreatefromjpeg($_FILES['photo']['tmp_name']);
    header('Content-Type: image/jpeg'); 
    imagejpeg($j);
    imagedestroy($j);
}

To this:

// Set an array of mime types that you accept as valid.
$valid_photo_mime_types = array('image/jpeg', 'image/pjpeg');

// Now check if the mime type of the uploaded file matches your array values of valid photo mime types.
if (in_array($_FILES['photo']['type'], $valid_photo_mime_types)){

    // Now let’s ingest the file that was uploaded & assign it to $j using the GD graphics library.
    $j = imagecreatefromjpeg($_FILES['photo']['tmp_name']);

    // Set the header to be whatever the uploaded file mime-type is.
    header('Content-Type: ' . $_FILES['photo']['type']); 

    // Now send the image to the browser.
    imagejpeg($j);

    // And finally 'destroy' the stored image to free up memory.
    imagedestroy($j);

}

Note that I git rid of the double-spacing of lines in your original example for space. And in my rewrite I am setting an array named $photo_mime_types and then using in_array to check if $_FILES['photo']['type']matches a value in $photo_mime_types. Then for header('Content-Type: '… I am setting that to whatever the value of $_FILES['photo']['type'] since at that point that value is valid, correct? Well programming is about avoiding repetition so let’s just pass what is valid when we know it is valid.

EDIT: This still seems to not be working for the original poster, so another debugging idea is to check the headers sent via curl -I from the command line. Unsure if you can do this on Windows, but if not you should figure out how to since curl is a great debugging tool for things like this. On a Mac OS X machine or a Unix/Linux box just run this command. For example, a call to the image logo on Google right now:

curl -I https://www.google.com/images/srpr/logo11w.png

The output I get is as follows:

HTTP/1.1 200 OK
Content-Type: image/png
Content-Length: 14022
Last-Modified: Wed, 09 Oct 2013 01:35:39 GMT
Date: Thu, 15 May 2014 01:47:25 GMT
Expires: Thu, 15 May 2014 01:47:25 GMT
Cache-Control: private, max-age=31536000
X-Content-Type-Options: nosniff
Server: sffe
X-XSS-Protection: 1; mode=block
Alternate-Protocol: 443:quic

Those are all of the headers that are sent with that image that tells the browser what to do with the image. Note the Content-Type: image/png. Now just substitute the URL to your local PHP code instead of the Google URL & check the output. Also look at this answer on Stack Overflow. As well as this one that explains how to use getimagesize to get data about the image within your PHP code. getimagesize is useful as well to show you what PHP is seeing the data to be.

Community
  • 1
  • 1
Giacomo1968
  • 25,759
  • 11
  • 71
  • 103
  • I used your code and I understand how it works. the problem is that the output to my browser is a bunch of raw code (no image to display). is that normal in PHP? – Ricco May 15 '14 at 01:34
  • @Ricco Okay, I have edited my answer to provide some more debugging tips. As much of a headache as this is, part of programming is dealing with things like this. Hopefully I gave you enough debugging tips to help iron this out. – Giacomo1968 May 15 '14 at 01:52
0

change

if ($_FILES['photo']['type'] == 'image/jpeg'){

to

if (preg_match('@^image/[a-z\-]jpeg@',$_FILES['photo']['type']) === true) {

this will match any type starting with 'image/' and ending with 'jpeg' and containing only lowercase letter and - characters

  • an elaboration of the regex and what you've changed would be good if our peer is a beginner – ThorSummoner May 15 '14 at 01:17
  • So basically this code would allow me to upload a malicious file with a mime type of `image/xjpeg` and shove a payload into the file as well. I mean that is an edge-case, but opening up validation to invalid mime types is basically opening up a hole that we don’t need. – Giacomo1968 May 15 '14 at 01:26