1

I have a column in a MySQL database called photo of type mediumblob and it can be NULL.

This should represent a small photo of an employee displayed in the top right corner of web application.

The new employee is inserted via a form to MySQL database.

<form action="insert" method="post" enctype="multipart/form-data">
   ...
   <label for="photo">Photo</label>
   <input type="file" name="photo">
   ...
</form>

The photo will be validated as follows:

  1. It can be unuploaded (no photo will be provided in the form)

    else if some photo is provided

  2. It should be of image type

  3. The image size should be suitable size for this purpose

  4. The dimensions of the image should be suitable for this purpose

Here is the outline of my validation code so far. I have already created some validation conditions (1 and 2). Are those OK? And don't know how to create conditions 3 and 4.

$file = $_FILES['photo']['tmp_name']
if (!isset($file))
{
    $image = ""; // 1), empty string will be inserted into the database
}
else {
    $image = addslashes(file_get_contents($_FILES['photo']['tmp_name']));
    $image_size = getimagesize($_FILES['photo']['tmp_name']);

    if ($image_size == FALSE) { 
      // 2) not an image file
      // display the form again with error message
    }

    // checking 3)
    // checking 4)
}
Community
  • 1
  • 1
xralf
  • 3,312
  • 45
  • 129
  • 200
  • 1
    I would recommend to add an extension check for safety http://nullcandy.com/php-image-upload-security-how-not-to-do-it/ – Mramaa Jan 04 '15 at 18:07
  • if I were you I'd be using mime types. Also take a look at zebra image. It is an excellent very simple php library that will make this a breeze. [Zebra Image](http://stefangabos.ro/php-libraries/zebra-image/). It's also one file that is very small. It basically leverages PHP's image functions and simplifies it. – Rafael Jan 04 '15 at 18:08
  • @Rafael mime-type checking is not secure... It is client controlled [T]his value is completely under the control of the client and not checked on the PHP side. - The link in my previous comment – Mramaa Jan 04 '15 at 18:09
  • So your check for point "It should be of image type" is certainly not complete – Mramaa Jan 04 '15 at 18:11
  • You could always check file extensions – Rafael Jan 04 '15 at 18:13
  • 1
    @Rafael see my first comment ;) – Mramaa Jan 04 '15 at 18:14
  • 2
    @Mramaa Your comments are misleading. The `['type']` sent in `$_FILES` is calculated by the client and subject to manipulation, but the author hasn't done that and can still use the PHP [Fileinfo](http://php.net/manual/en/book.fileinfo.php) extension to generate his own MIME determination. – Jacob Budin Jan 04 '15 at 18:15

6 Answers6

2

For condition 3 u can use:

$filesize = filesize($filename);

u get size of the file in bytes.


For condition 4 u can use:

list($width, $height) = getimagesize($_FILES['photo']['tmp_name']);

where $width and $height is the dimension of image.
harry
  • 1,007
  • 2
  • 10
  • 19
2

Here are some helpful tips packed into code:

$upload_error = isset( $_FILES['photo']['error'] ) ? $_FILES['photo']['error'] : UPLOAD_ERR_NO_FILE;
if ($upload_error == UPLOAD_ERR_NO_FILE) {
    // 1) No file uploaded
    $image = null; // I changed the empty string into a null, to avoid the mediumblob allocating space for the empty string
} elseif ($upload_error) {
    // 5) You forgot to check if the file upload failed
    switch ($upload_error) {
        case UPLOAD_ERR_INI_SIZE:
        case UPLOAD_ERR_FORM_SIZE:
            $message = "file_too_big";
            break;
        case UPLOAD_ERR_PARTIAL:
            $message = "upload_not_complete";
            break;
        case UPLOAD_ERR_EXTENSION:
            $message = "bad_file_extension";
            break;
        case UPLOAD_ERR_NO_TMP_DIR:
        case UPLOAD_ERR_CANT_WRITE:
            $message = "internal_upload_error";
            break;
        default:
            $message = "unknown_upload_error";
            break;
    } 
    header("Location: form.php?error=$message"); // Load form again and show error
    exit;
} else {
    $file = $_FILES['photo']['tmp_name'];
    $file_size = $_FILES['photo']['size'];
    if ($file_size > 5242880) { // 5 Megabyte for example, but always less than 16 Megabytes, because you use mediumblob
        // 3) The image size is not suitable for this purpose
        header("Location: form.php?error=file_too_big"); // Load form again and show error
        exit;
    }
    $image_size = getimagesize($file);
    if ($image_size) {
        $width = $image_size[0];
        $height = $image_size[1];
        if ($width < 100 || $width > 1000 || $height < 100 || $height > 1000) {
            // 4) Image dimensions are not suitable. Width/height are not between 100 and 1000 pixels
            header("Location: form.php?error=dimensions_not_ok"); // Load form again and show error
            exit;
        }
    } else {
        // 2) Not an image type
        header("Location: form.php?error=not_an_image"); // Load form again and show error
        exit;
    }
    $image = file_get_contents($file);
}
// now escape $image and save it to the database
// But I suggest you not use addslashes() to escape binary data
// Use parameterized queries / mysqli_real_escape_string() / mysql_real_escape_string() instead
nl-x
  • 11,762
  • 7
  • 33
  • 61
1

Use Best way to determine if a file is empty (php)? for point 1
Point two is not complete at all (not secure):
E.g. add an extension check: PHP check file extension
More security tips for point 2: http://nullcandy.com/php-image-upload-security-how-not-to-do-it/
Point 3 and 4 can be covered with getimagesize() and filesize()
Get image dimensions
http://php.net/manual/en/function.filesize.php

Community
  • 1
  • 1
Mramaa
  • 400
  • 2
  • 13
1

Your code is ok, you just need to add following lines to fulfil all your requirements:

$image="";
if (isset($_FILES["photo"]) && $_FILES["photo"]["error"] < 1){
    $file = $_FILES['photo']['tmp_name'];
    $imageInfo = getimagesize($file);
    if(is_array($imageInfo)){
         if($imageInfo[0]>30 && $imageInfo[0]<257 && $imageInfo[1]>30 && $imageInfo[1]<257){
           //$imageInfo[0] is width and $imageInfo[1] is height, you can set limit according to your need. I set it to MIN: 31*31 AND MAX 256*256
           // if you want square image then add " && $imageInfo[0]=$imageInfo[1]" in above-if-clause

              $imageSize=filesize($file); //returns bytes in integer
              if($imageSize> 250 && $imageSize<20481) // image size should be less then 20kb
                  $image = addslashes(file_get_contents($file));
              else echo "Image file should not grater then 20 KB.";
         }
         else echo "Image dimension(width*height) should be 31*31 to 256*256.";
    }
    else echo "Wrong file. Upload a Image file.";
}
else echo "No file uploaded or Error in file uploaded.";

if(trim($image)==""){
   //display form again
}
Adarsh Rajput
  • 1,246
  • 14
  • 24
1
      $userfile_name = $_FILES['image']['name'];
         $userfile_tmp = $_FILES['image']['tmp_name'];
         $userfile_size = $_FILES['image']['size'];
         $filename = basename($_FILES['image']['name']);
         $allowedExts = array("gif", "jpeg", "jpg", "png");
         $extension = end(explode(".", $_FILES["image"]["name"]));
         if(($userfile_size / 1024) < 4096){
             if (isset($_FILES['image']['name']) && !empty($_FILES["image"]) && ($_FILES['image'] ['error'] == 0) && ($userfile_size / 1024 < 4096 ) && (($_FILES["image"]["type"] == "image/gif")
        || ($_FILES["image"]["type"] == "image/jpeg")
        || ($_FILES["image"]["type"] == "image/jpg")
        || ($_FILES["image"]["type"] == "image/pjpeg")
        || ($_FILES["image"]["type"] == "image/x-png")
        || ($_FILES["image"]["type"] == "image/png")) && in_array($extension, $allowedExts)) {
                        //Everything is ok, so we can upload the image.
        }else{
echo "Error in file Upload";
}
        }else{
    echo 'Oops!  Your file\'s size is to large.';
    }

For point 4, You need something that is executed on the client before the actual upload happens. With (server-side) php you can check the dimension only after the file has been uploaded

Needhi Agrawal
  • 1,326
  • 8
  • 14
1

You can use the following PHP library: https://github.com/codeguy/Upload

Wissam El-Kik
  • 2,469
  • 1
  • 17
  • 21