Jump to content

Urgent help needed in php image validation


Recommended Posts

the code works very well, but allows files like .exe, mp4 to be uploaded thanks

<?php

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

 $gfileSize = "1048576";

$gfileExt = array("png","jpg","jpeg");

 if(isset($_FILES["thumbnail"])) {

    $gfileSize = "1048576";

    $gfileExt = array("png","jpg","jpeg");

    $ppf  = $_FILES["thumbnail"]["name"];

    $temporary_file_pp = $_FILES["thumbnail"]['tmp_name']; // temporary path

    $str_to_a_pp = explode('.',$ppf);

    $extension_pp = end($str_to_a_pp); // get extension of the file.

    $upload_location_pp = "../../ESS/ACCT/PIMG/"; // targeted location

    $new_name_pp = "PP-".time().".".$extension_pp; // new name

    $location_with_name_pp = $upload_location_pp.$new_name_pp; // finel new file

    $file_extension_pp = pathinfo($_FILES["thumbnail"]["name"], PATHINFO_EXTENSION);

    if(!file_exists($_FILES["thumbnail"]["tmp_name"])) {

      $thumbnail_err = "Upload Passport.";

    }else{

        //$passport = file_exists($_FILES["passport"]["tmp_name"]);

        if($_FILES["thumbnail"]["size"] > $gfileSize){

        $thumbnail_err = "Passport size must not exceed 1MB";

        }else if(!in_array($file_extension_pp, $gfileExt)){

        $thumbnail_err = "Passport type is not valid";

      }else{

        $thumbnail = $new_name_pp;

      }

    }

  }

} ?>

 

Link to comment
Share on other sites

when the size of the post method form data exceeds the post_max_size setting, both the $_POST and $_FILES arrays will be empty, because the web server discards the form data before causing your php script to be executed. your code trying to test $_POST or $_FILES will fail because there is nothing to test. after you have detected if a post method form has been submitted, assuming there's at least one correctly coded post or file field (and uploads are enabled on the server), your code should test if both $_POST and $_FILES are empty, and setup a message for the user letting them know that the form data was too large and was not processed.

Link to comment
Share on other sites

no matter how large you set the max_post_size setting, someone can upload a file that is larger. the size of the file someone tries to upload is out of your control. your code must test for this condition and handle it. also, by increasing the setting beyond a reasonable size, it will allow hackers to flood your  server with huge uploaded files, consuming all the available processing and memory on the server, allowing a denial of service (DoS) attack.

Link to comment
Share on other sites

I would suggest using Intervention Library as it makes handling images so much easier.

I use the following for my own website ->

<?php
// Include the configuration file and autoload file from the composer.
require_once __DIR__ . '/../config/clearwebconfig.php';
require_once "vendor/autoload.php";
use Intervention\Image\ImageManagerStatic as Image;
// Import the ErrorHandler and Database classes from the clearwebconcepts namespace.
use clearwebconcepts\{
    ErrorHandler,
    Database,
    ImageContentManager,
    LoginRepository as Login
};

$errorHandler = new ErrorHandler();

// Register the exception handler method
set_exception_handler([$errorHandler, 'handleException']);

$database = new Database();
$pdo = $database->createPDO();
$checkStatus = new Login($pdo);

// To check for either 'member' or 'sysop'
if ($checkStatus->check_security_level(['sysop'])) {
    // Grant access
} else {
    // Access denied
    header('location: dashboard.php');
    exit();
}

function is_ajax_request(): bool
{
    return isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] === 'XMLHttpRequest';
}


$save_result = false;

if (($_SERVER['REQUEST_METHOD'] === 'POST') && isset($_FILES['image'])) {
    $data = $_POST['cms'];
    $data['content'] = trim($data['content']);
    $errors = array();
    $exif_data = [];
    $file_name = $_FILES['image']['name']; // Temporary file:
    $file_size = $_FILES['image']['size'];
    $file_tmp = $_FILES['image']['tmp_name'];
    $thumb_tmp = $_FILES['image']['tmp_name'];
    $file_type = $_FILES['image']['type'];
    $file_ext = strtolower(pathinfo($_FILES['image']['name'], PATHINFO_EXTENSION));


    /*
     * Set EXIF data info of image for database table that is
     * if it contains the info otherwise set to null.
     */
    if ($file_ext === 'jpeg' || $file_ext === 'jpg') {

        $exif_data = exif_read_data($file_tmp);


        if (array_key_exists('Make', $exif_data) && array_key_exists('Model', $exif_data)) {
            $data['Model'] = $exif_data['Make'] . ' ' . $exif_data['Model'];
        }

        if (array_key_exists('ExposureTime', $exif_data)) {
            $data['ExposureTime'] = $exif_data['ExposureTime'] . "s";
        }

        if (array_key_exists('ApertureFNumber', $exif_data['COMPUTED'])) {
            $data['Aperture'] = $exif_data['COMPUTED']['ApertureFNumber'];
        }

        if (array_key_exists('ISOSpeedRatings', $exif_data)) {
            $data['ISO'] = "ISO " . $exif_data['ISOSpeedRatings'];
        }

        if (array_key_exists('FocalLengthIn35mmFilm', $exif_data)) {
            $data['FocalLength'] = $exif_data['FocalLengthIn35mmFilm'] . "mm";
        }

    } else {
        $data['Model'] = null;
        $data['ExposureTime'] = null;
        $data['Aperture'] = null;
        $data['ISO'] = null;
        $data['FocalLength'] = null;
    }

    $data['content'] = trim($data['content']);

    $extensions = array("jpeg", "jpg", "png");

    if (in_array($file_ext, $extensions, true) === false) {
        $errors[] = "extension not allowed, please choose a JPEG or PNG file.";
    }

    if ($file_size >= 58720256) {
        $errors[] = 'File size must be less than or equal to 42 MB';
    }

    /*
     * Create unique name for image.
     */
    $image_random_string = bin2hex(random_bytes(16));
    $image_path = 'assets/image_path/img-entry-' . $image_random_string . '-2048x1365' . '.' . $file_ext;
    $thumb_path = 'assets/thumb_path/thumb-entry-' . $image_random_string . '-600x400' . '.' . $file_ext;


    move_uploaded_file($file_tmp, $image_path);
    move_uploaded_file($thumb_tmp, $thumb_path);


    // Load the image
    $image = Image::make($image_path);

    // Resize the image
    $image->resize(2048, 1365, function ($constraint) {
        $constraint->aspectRatio();
        $constraint->upsize();
    });

    // Save the new image
    $image->save($image_path, 100);

    // Load the image with Intervention Image
    $image = Image::make($image_path);

    // Resize the image while maintaining the aspect ratio
    $image->resize(600, 400, function ($constraint) {
        $constraint->aspectRatio();
        $constraint->upsize();
    });

    // Save the thumbnail
    $image->save($thumb_path, 100);


    $data['image_path'] = $image_path;
    $data['thumb_path'] = $thumb_path;


    /*
     * If no errors save ALL the information to the
     * database table.
     */
    if (empty($errors) === true) {
        // Save to Database Table CMS
        $timezone = new DateTimeZone('America/Detroit'); // Use your timezone here
        $today = new DateTime('now', $timezone);
        $data['date_updated'] = $data['date_added'] = $today->format("Y-m-d H:i:s");
        $cms = new ImageContentManager($pdo, $data);
        $result = $cms->create();

        if ($result) {
            header('Content-Type: application/json');
            echo json_encode(['status' => 'success']);
            exit();
        }
    } else {
        if (is_ajax_request()) {
            // Send a JSON response with errors for AJAX requests
            header('Content-Type: application/json');
            echo json_encode(['status' => 'error', 'errors' => $errors]);
        }
    }

}

I log my errors to a log file that I can only see and a person needs to be login to my website even to upload a file.

Maybe the above can you help you out a little. Just remember nothing is full proof, but you should make the code as tight as possible.

Link to comment
Share on other sites

Post/Redirect/Get (PRG) is effective against Content-Length warnings (not visible due to the redirect)

Which version of php are you using? i've tried the script on my xampp with php version 8 and only images are accepted. However, you have the acceptable image array typed twice in your script, as well as the size variable. Why even use a variable (memory consumption)?

!in_array($file_extension_pp, ["png","jpg","jpeg"])

Link to comment
Share on other sites

as already stated -

On 7/31/2024 at 6:29 AM, mac_gyver said:

after you have detected if a post method form has been submitted, assuming there's at least one correctly coded post or file field (and uploads are enabled on the server), your code should test if both $_POST and $_FILES are empty, and setup a message for the user letting them know that the form data was too large and was not processed.

 

Link to comment
Share on other sites

// Define constants and variables for file upload
$upload_location = "../../ESS/ACCT/PIMG/"; // Targeted location
$allowed_extensions = ['png', 'jpg', 'jpeg', 'gif']; // Allowed file extensions
$max_file_size = 2097152; // Maximum file size (2MB)
$file_prefix = "PP-"; // Prefix for the new file name

// Initialize variables
$thumbnail_err = '';
$thumbnail = '';

// Check if the form was submitted and the file input was set
if (isset($_POST['submit_button_name']) && isset($_FILES["thumbnail"]) && $_FILES["thumbnail"]["error"] === UPLOAD_ERR_OK) {
    $p_name = $_FILES["thumbnail"]["name"];
    $p_str_to_a = explode('.', $p_name);
    $p_extension = strtolower(end($p_str_to_a)); // Get extension of the file

    $unique_id = bin2hex(random_bytes(16)); // Generate a unique 32-character hexadecimal/bin2hex and random_bytes
    $new_p_name = $file_prefix . $unique_id . "." . $p_extension; // New name with extension

    // For MOVING TO SERVER
    $temporary_p_path = $_FILES["thumbnail"]['tmp_name']; // Temporary path
    $upload_location_with_new_p_name = $upload_location . $new_p_name; // Final new file location

    if (!file_exists($temporary_p_path)) {
        $thumbnail_err = "Upload a Thumbnail.";
    } elseif (!getimagesize($temporary_p_path)) {
        // Check if the file is an image
        $thumbnail_err = "Sorry, file is not an image.";
    } elseif (!in_array($p_extension, $allowed_extensions)) {
        $thumbnail_err = "Sorry, only JPG, JPEG, PNG & GIF files are allowed.";
    } elseif ($_FILES["thumbnail"]["size"] > $max_file_size) {
        $thumbnail_err = "Sorry, your file is too large. 2MB.";
    } elseif (!is_dir($upload_location)) {
        $thumbnail_err = "Upload directory does not exist.";
    } elseif (file_exists($upload_location_with_new_p_name)) {
        // Check if file with the same name already exists
        $thumbnail_err = "File already exists.";
    } else {
        // Directory exists, file can be moved
        $thumbnail = $new_p_name; // Set thumbnail name if needed
    }
} elseif (isset($_FILES["thumbnail"]) && $_FILES["thumbnail"]["error"] !== UPLOAD_ERR_OK) {
    // Handle file upload error
    $thumbnail_err = "File upload error.";
}

How about this?

Link to comment
Share on other sites

servers (like apache) and php have max size limits. You are trying to set a max size variable in addition to these restrictions. You will get content-length warnings regardless and POST should be empty or someone is just sending post requests to your script not using your image upload form. You are making it complicated.

if (empty($_FILES['Upload']) || !empty($_FILES['Upload']['error']) && $_FILES['Upload']['error'] === 4) {
  //content-length warning. redirect to get
}

if (!is_string($_FILES['Upload']['tmp_name']) || count($_FILES) > 1) {
  //more than one file has been sent
}

if (!in_array(strtolower(pathinfo($_FILES['Upload']['name'], PATHINFO_EXTENSION)), ['jpe','jpeg','jpg','png'], true)) {
  //not 'jpe','jpeg','jpg','png'
}

 

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.