Domanda

What are best practices for uploading files using PHP to ensure that a database is also updated?

Current approach

1) Form validation confirms all fields are of valid types, lengths and clean of xss attacks.

2) File uploaded to server with user submitted filename

3) Database updated with user submitted details including filename

Is that a safe way? Would it be better to update the database first, then query the database for the filename and then upload the file using the database-retrieved filename?

Not looking for code necessarily but rather the philosophy. Thanks!

È stato utile?

Soluzione

I would use this order:

First method: operation order dependent

  • Form validation
  • Check if file was uploaded (don't move it from temp, yet)
  • Generate new filename based on your free choice
  • Insert data about the file to database using newly generated filename
  • Only then, if there's not exception thrown, move the file from temp using filename above. Otherwise, file will be deleted automatically on request end
  • If file moving failed for some reason you should remove record from database.

I strongly suggest using some PDO-like library to "talk" to database as these throw exceptions, instead of raising errors (like mysql_** function). That way you will know for sure if your query succeeded without constantly checking result of database functions...

Second method: Transactions

  • Form validation
  • Check if file was uploaded (don't move it from temp, yet)
  • Generate new filename based on your free choice
  • Start transaction
  • "Insert" data about the file to database using newly generated filename.
  • Move the file from temp using filename above. If for some reason file move fails, throw an execption.
  • Commit transaction
  • At this point you're sure that both file is moved and data persisted properly.

Altri suggerimenti

Form validation is an essential part of any web application so it's good to see that on the list. You're combining two of the most risky elements of web applications here, file uploads and database interaction so you obviously need to tread carefully. I guess that's why you're asking!

My suggestion in terms of approach is firstly not to use user submitted filenames, that opens up a whole area of risk you don't need. Unless this is a required feature of your app, generate a new random filename in PHP and use move_uploaded_file to copy from the PHP assigned tmp_name to your new random filename.

Once you've performed this move you can update the database with the location of the file.

My approach would therefore be:

  1. Strict validation of any user supplied input based on a whitelist ([a-z][A-Z][0-9] as a suggestion).
  2. Avoid echoing user supplied data back to screen, if you do, output encode to HTML entities.
  3. Avoid using user supplied data for input to the database or filename, generate a new filename which you control.
  4. Handle the upload itself and, after performing some validation checks move the image to its new location as per your generated filename.
  5. Update the database with the new filename.

I know you weren't after code but here are a couple of little snippets from a working file upload I have, it doesn't do the database part but that would be straightforward to add.

function generate_filename() {
    // could be improved upon really
    $random_string = random_string(8);
    $filename = $random_string . time() . ".jpg";
    return $filename;    
}



if ($_FILES["file_upload"]["size"] != 0) {
    $file_name = generate_filename();
    $file_path = "/" . $upload_directory . "/" . $file_name;
    $target_file_name = SITE_ROOT . $file_path; // SITE_ROOT is a constant for the file system location. This could be /var/www/images for example.

    if ($_FILES["file_upload"]["type"] == "image/jpeg") {
        if (getimagesize($_FILES["file_upload"]["tmp_name"])) {
            if (move_uploaded_file($_FILES["file_upload"]["tmp_name"],$target_file_name)) {
                exit_status("File uploaded successfully to $file_path");
            } else {
                exit_status("Eek, something went wrong with your image upload");
            }
        } else {
            exit_status("Not a valid image");
        }
    } else {
        exit_status("Invalid file type. We only support JPEG");
    }
} else {
    exit_status("You didn’t specify a file to upload. Try again");
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top