Multipart forms

  • Web interfaces postal services, which allow you to add an attachment (attach) to a letter, and to do this you must first upload the file to the server, and only after that it can be added to the letter;
  • Interactive photo galleries and photo albums that cannot exist without a mechanism for uploading files to the server;
  • Free software portals used for file sharing various programs, etc.

Uploading a file to the server is carried out using a multipart form, which has a file upload field. The enctype parameter is set to multipart/form-data :



This is what the given multipart form will look like (you can try using it to see the result of the multipart forms by uploading a file small size to server):

Multipart forms typically use the POST submission method. As can be seen from the previous example, this form has two fields:

  • File selection field for uploading ;
  • Field for specifying the file name that it will have on the server .

Processing multipart forms

Before you start writing a script for processing a multipart form, you need to edit the configuration file php.ini to allow files to be uploaded to the server.

The PHP configuration file php.ini has three parameters related to uploading files to the server:

  • file_uploads=On - allows files to be uploaded to the server via HTTP;
  • upload_tmp_dir=/tmp - sets the directory for temporary storage of uploaded files;
  • upload_max_filesize=2M - sets the maximum size of uploaded files.

If your web server is running a Linux operating system, then you need to restart the service:

service httpd restart

How does PHP handle multipart forms? Once it receives the file, it saves it in a temporary directory called upload_tmp_dir , with the file name chosen at random. It then creates four superglobal array variables $_FILES . This array contains information about the downloaded file.

The variables defined for uploaded files depend on the PHP version and current configuration. The superglobal array $_FILES is available since PHP 4.1.0. In case the register_globals configuration directive is set to on, additionally variables with appropriate names will be declared. As of version 4.2.0, the default value for the register_globals option is off.

The contents of the $_FILES array for our example are shown below. Note that this assumes the name uploadfile is used for the file selection field, as per the multipart form above. Of course, the field name can be anything.

  • $_FILES["uploadfile"]["name"] - the name of the file before it is sent to the server, for example, pict.gif;
  • $_FILES["uploadfile"]["size"] - size of the received file in bytes;
  • $_FILES["uploadfile"]["type"] - MIME type of the received file (if the browser was able to detect it), for example: image/gif, image/png, image/jpeg, text/html;
  • (that’s what we called the file upload field) - contains the name of the file in the temporary directory, for example: /tmp/phpV3b3qY;
  • $_FILES["uploadfile"]["error"] - Error code that may occur when downloading a file. Key ["error"] was added in PHP 4.2.0. You can see the corresponding error codes

After the script completes, the temporary file will be deleted. This means that we must copy it to another location before the script completes. That is, the algorithm for the script to upload a file to the server is as follows:

If the "Submit" button is pressed, the file will already be uploaded to the server and its name will be in the $_FILES["uploadfile"]["name"] variable. In this case, the script should immediately copy the file with the name $_FILES["uploadfile"]["tmp_name"] to some directory (write rights to this directory are required).

The file is copied using the function copy() :

Only use the copy() copy function, not the move function, because:

  • The temporary file will be deleted automatically;
  • If the temporary directory is on other media, an error message will be displayed.

Let's say we need to upload a file to the uploads directory, which is located in root directory web server (in the DocumentRoot directory).

// Let's create a directory just in case. If he already created,
// we won't see an error message because we'll use the @ operator:

@mkdir("uploads", 0777);

// Copy the file from /tmp to uploads
// The file name will be the same as before sending to the server:

Copy($_FILES["uploadfile"]["tmp_name"],"uploads/".basename($_FILES["uploadfile"]["name"]));

On Linux, everything is much more complicated - we need to take into account the permissions of the uploads directory. Most likely in this case, the function mkdir() won't work because we don't have write permission to the DocumentRoot directory (usually /var/www/html or /home/httpd/html). Log in as root, create an uploads directory, and change its owner and permissions as follows:

// Create the uploads directory

// Set the apache owner name and its group - also apache:

Chown apache:apache uploads

// Allow everyone to write (777) + set the sticky bit (1):

Chmod 1777 uploads

The file size can be limited; if desired, you can edit the .htaccess file and limit access to the uploads directory - specify either specific users who can access the directory, or IP addresses.

Now you can upload files to the server.

We write PHP script uploading files to the server


// Directory where we will receive the file:
$uploaddir = "./files/" ;
$uploadfile = $uploaddir. basename($_FILES["uploadfile"]["name"]);

// Copy the file from the directory for temporary storage of files:
if (copy ($ _FILES [ "uploadfile" ][ "tmp_name" ], $uploadfile ))
{
echo "

The file was successfully uploaded to the server

" ;
}
else ( echo "

Error! Failed to upload file to server!

"
; exit ; )

// Display information about the downloaded file:
echo "

Information about the file uploaded to the server:

"
;
echo "

Original name of the uploaded file: ".$ _FILES [ "uploadfile" ][ "name" ]. "

" ;
echo "

Mime type of the uploaded file: ".$ _FILES [ "uploadfile" ][ "type" ]. "

" ;
echo "

Uploaded file size in bytes: ".$ _FILES [ "uploadfile" ][ "size" ]. "

" ;
echo "

Temporary file name: ".$ _FILES [ "uploadfile" ][ "tmp_name" ]. "

" ;

?>

Loading multiple files can be implemented using, for example, different name values ​​for the input tag.

It is also possible to automatically obtain information organized into an array about several simultaneously downloaded files. To implement this feature, use the same syntax for submitting an array from an HTML form as for multiple select and checkbox fields:


Send these files:






If such a form was submitted, the $_FILES["userfile"] , $_FILES["userfile"]["name"] , and $_FILES["userfile"]["size"] arrays will be initialized (in the same way , like $HTTP_POST_FILES for PHP 4.1.0 and earlier). If the register_globals configuration directive is set to on , the accompanying global variables will also be initialized. Each of these variables will be a numerically indexed array of corresponding values ​​for the received files.

Let's assume that the files /home/test/some.html and /home/test/file.bin were loaded. In this case, the $_FILES["userfile"]["name"] variable will have the value some.html , and the $_FILES["userfile"]["name"] variable will have the value file.bin . Likewise, the variable $_FILES["userfile"]["size"] will contain the size of the some.html file and so on.

Variables $_FILES["userfile"]["name"] , $_FILES["userfile"]["tmp_name"], $_FILES["userfile"]["size"] and $_FILES["userfile"]["type"] will also be initialized.

Conclusion:

As you can see, organizing file uploads to the server is not that difficult. It is more difficult to ensure the required level of security, since uploading files to the server can be used by attackers to attack the server. For information on how to ensure the required level of security when working with Uploads, see.



<<< Назад Content Forward >>>
If you have any other questions or something is not clear - welcome to our

Sorry... I can"t deal with all the SPAM so until I can find a better solution for the forums, I"m locking them down. For now please use awesome services like stackoverflow.com for community support. Thanks.

This forum is a community forum meant for users of the plugin to collaborate and help solve issues with implementation, etc. Unfortunately, as the creator of the plugin, I do not have much time to attend to every request here as this is only a side project and I must work a full-time job to provide for my family. This is how I keep the Flash version free and the HTML5 version low cost.

    I tried using the str_replace function in various places in the uploadify.php script, but not luck, it either continued uploading but did not change the spaces. Or it did not upload at all, although it looked like it did...

    How/where would this be implemented?

    Generally like this

    $str = "This is a test";
    $count = 1;
    while($count)
    $str = str_replace(" ","", $str, $count);
    echo $str;
    ?>

    But maybe preg_replace is the better choice to clean everything bad from the filename

    $fname="File"ame 1\/23;"."""."la\l[a]*(/.jpg";
    $replace="_";
    $pattern="/[^a-zA-Z0-9\.]/";
    $fname=preg_replace($pattern,$replace,$fname);
    $fname=str_replace($replace,"",$fname);
    echo "
    ".$fname;

    This is my final php, which cleans the filename from spaces and other problematic chars,
    randomizes the filename afterwards and send it back to the backend:

    if (!empty($_FILES)) (
    $replace="_";
    $newfile= $_FILES["Filedata"]["name"] ;
    $ext = substr($newfile,-4); //comment out to not ramdomize the filename
    $pre = mb_split($ext,$newfile); //comment out to not ramdomize the filename
    $randoms = base_convert(mt_rand(0x1679616, 0x39AA3FF), 10, 36); //comment out to not ramdomize the filename
    $newfile = $pre.$randoms.$ext; //comment out to not ramdomize the filename
    $pattern="/[^a-zA-Z0-9\.]/";
    $newfile = preg_replace($pattern,$replace,$newfile);
    $tempFile = $_FILES["Filedata"]["tmp_name"];
    $targetPath = $_SERVER["DOCUMENT_ROOT"] . $_REQUEST["folder"] . "/";
    $targetFile = str_replace("//","/",$targetPath) . $newfile;
    move_uploaded_file($tempFile,$targetFile);
    chmod($targetFile,0777);
    echo $newfile; // Required to trigger onComplete function on Mac OSX (same for linux and windows as it seems)
    //and to send back the new filename to the "response" variable in uploadify
    }
    else ( // Required to trigger onComplete function on Mac OSX
    echo "ERROR!";
    }
    ?>

    This is great, but I have noticed that now the Checking script doesn't work quite right. check.php is looking to see if there are files with a different name, but the file we are uploading is going to have its name changed, how do account for that in the check script, another str_replace?

    How do we write that?

    Actually I don"t use the check script. In my case I have to upload hundreds of images and therefore I need to give the user the possibility to upload files, without worrying about the file name as he could want to upload a file named logo .gif for different datasets maybe ten times.
    That's why I added a random part to the filename. The $randoms very likely never gives the same result twice.
    I think you can"t alter the check.php to follow the same rules, as the $randoms will be different even for the same finename, though

    I would be possible if you comment out the ramdomising part and only use the "cleaning" part.
    Then the output is predictable.
    I haven't tested that, but it should be something like this:

    $fileArray = array();
    $replace="_";
    $pattern="/[^a-zA-Z0-9\.]/";
    foreach ($_POST as $key => $value) (
    if ($key != "folder") (
    $value= preg_replace($pattern,$replace,$value);
    if (file_exists($_SERVER["DOCUMENT_ROOT"] . $_POST["folder"] . "/" . $value)) (
    $fileArray[$key] = $value;
    }
    }
    }
    echo json_encode($fileArray);

    This is just a quick guess, try if it works.
    And comment out the lines in upload.php which are indicated.

JavaScript is blocked in your browser. Please enable JavaScript for the site to function!

Uploading files to the server

A short excursion into upload

What are Upload files, or why doesn't it work?
copy ("c:\images\sample.jpg", "http://mysite.ru/uploads/sample.jpg")

Even if you have only one computer, which combines both a server and a workstation, do not forget that php uses client/server technology. The file we want to download is usually located on the client's machine, i.e. user, an ordinary visitor to the site. The destination is the server. In order to complete the file transfer process, we need the following form:

Send this file:

In this case, the action field must indicate the URL of your PHP script, which will subsequently process the downloaded files. The hidden field MAX_FILE_SIZE must precede the file selection field and contain the maximum allowed file size in bytes. Its purpose is to check the file size before sending the file to the server. This should save the user from lengthy and fruitless uploading of a file to the server and the generation of unnecessary traffic, but you should not rely too much on this limitation, as it is easy to bypass.

What happens when the user selects a file on his disk and clicks on the "Send file" button? The browser sends the file to the server, where the PHP interpreter places it in its temporary directory, assigning it a random name and executes the script specified in the action field.

What should upload.php look like?

$uploaddir = "/var/www/uploads/"; if (move_uploaded_file($_FILES["userfile"]["tmp_name"], $uploaddir. $_FILES["userfile"]["name"])) ( print "File is valid, and was successfully uploaded."; ) else ( print "There are some errors!"; )

When writing a script, a natural question arises: how to get information about the downloaded file and access the file itself. If you are using PHP versions 4.1.0 and older, it is best to refer to the global $_FILES array. For each downloaded file, it contains a hash array with the following data:

  • $_FILES["userfile"]["name"]- the original file name, as the user saw it when selecting the file;
  • $_FILES["userfile"]["type"]- mime/type of the file, for example, can be image/gif; This field is useful to save if you want to provide an interface for downloading uploaded files;
  • $_FILES["userfile"]["size"]- size of the downloaded file;
  • $_FILES["userfile"]["tmp_name"]- full path to the temporary file on disk;
  • $_FILES["userfile"]["error"]- Since version 4.2.0, contains an error code that is equal to 0 if the operation was successful.

For PHP versions below 4.1.0 this array is called $HTTP_POST_FILES. Do not forget that, unlike $_FILES, this array is not super-global and when accessing it, for example, from a function, you must explicitly specify global $HTTP_POST_FILES;

If in your server settings register_globals=on, additional variables like $userfile_name, $userfile_type, $userfile_size... Considering that, starting from version 4.2.0, in the default settings register_globals=off, the use of these variables is not recommended, even if they defined. The best way to get information about downloaded files is to use the $_FILES array.

To work with uploaded files, it is best to use the built-in functions is_uploaded_file() and move_uploaded_file(), which check if the file has been uploaded and place it in the specified folder accordingly. More detailed information can be found on the manual pages. You shouldn’t reinvent the wheel and work with temporary files yourself, copy them, delete them. This has already been done before you and for you.

Server Tuning

I did everything right, but something is not working for me. Maybe my server is configured incorrectly?

If you “did everything right”, but your code does not work, or does not work correctly, do not rush to despair. Perhaps the problem is not in your hands, but in incorrect server settings. Here is a list of directives that relate to file uploading:

In the php.ini file:

  • If you want to find out where your php.ini is located, run
  • file_uploads- the ability to prohibit or allow file downloads in general. Default is On.
  • upload_max_filesize- the maximum file size that can be uploaded. If you need to work with large files, change this setting. Default is 2M. Don't forget to change post_max_size.
  • post_max_size - general limitation on top of the size of the data transferred to POST request. If you need to work with large files, or transfer multiple files at the same time, change this setting. The default value is 8M.
  • upload_tmp_dir- a temporary directory on the server in which all downloaded files will be placed. Check what rights are assigned to it (if at this stage If you have any difficulties, see the explanations at the end of the article). Such a directory must exist and the user under which Apache is running must also have write permissions to this directory. If you are working with the open_basedir restriction enabled, then the temporary directory must be inside. You don't have to worry about cleaning it up or making names unique, PHP solves this problem for you.

In file httpd.conf:

  • First of all, make sure that you are using Apache 1.3 web server ( latest version at the time of writing - 1.3.27). If you are using Apache 2.0, you should read the following excerpt from the documentation:

    Do not use Apache 2.0 and PHP in a production environment neither on Unix nor on Windows.

  • If you receive a "POST Method Not Allowed" message, this means that you need to look for something similar to the following directives, and use keyword Allow: Order allow,deny Allow from all
  • Problems with downloading binary files - the classic question “why do files crash when uploading”. Here is a solution proposed by Dima Borodin (http://php.spb.ru): In the directory where the script is located, create a .htaccess file in which we write: CharsetDisable On To file httpd.conf add the lines: CharsetRecodeMultipartForms Off

A few clarifications for this recipe: the problem described above, when archives uploaded to the server are not unpacked and pictures are not displayed, may occur due to the fact that the Russian Apache web server is used. The CharsetDisable directive disables the charset-processing module, i.e. no recoding will occur when downloading files located in this folder. The CharsetRecodeMultipartForms directive disables recoding of data transferred POST method with the header Content-Type: multipart/form-data. Those. binary data transmitted with this setting will be left in its original form, and all other site content will be recoded according to the current server settings.

But complications may arise: be prepared for the fact that in some cases you will have to recode the text parts of requests yourself. Here's what the documentation says about this:

Use the CharsetRecodeMultipartForms directive, which was introduced in PL23, but you will still have to manually recode the text parts of the requests. To do this, you can use the Russian Apache API, available in other modules, or the Russian Apache Perl API, available from mod_perl.

One example of determining the encoding can be found here: http://tony2001.phpclub.net/detect_charset/detect.phps

The latest documentation for Russian Apache is located on its official website: http://apache.lexa.ru/.

Don't forget that after any configuration change, you need to restart your web server.

It is also possible to configure Apach settings using .htaccess:

Php_value upload_max_filesize 50M php_value post_max_size 50M

Additional features

Uploading multiple files at once

Example of a multiple file upload form:

Send these files:


And don't forget to increase post_max_size, if there are many files expected

Automatically upload files to the server

Do not forget that the files on the user's disk are confidential information, to which neither JavaScript, nor even more so PHP, have the slightest connection. Until the user himself selects the file using There can be no talk of any work with him. And don't forget that of this field The value attribute is write-protected.

Storing files in a mySQL database

If you are planning to store downloaded files in a database, you need to remember the following points:

  • You must use a BLOB field
  • Before putting it into the database, do not forget to apply mysql_escape_string() to the string
  • When displaying a file, you must specify the content/type header

Remember that the script that displays your HTML is in no way related to the script that should display the image. These must be two different applications.

Storing images in a database is not good style. It is much more convenient to store only the paths to image files in the database.

Getting image properties.

If you are faced with the task of checking the type or size of an image before uploading a file to the server, you will need the getimagesize() function. It takes the name of a file on disk as an argument and returns an array whose first two elements are the width and height, respectively, and the third is the image type. If it is impossible to read from specified file correct image, the function returns false.

Uploading files with Russian-language names

When uploading files to the server, you must check their original names for the presence of “non-standard” characters (for example, Russian letters). If they are present, they must be replaced. The original file name can be found in the $_FILES["userfile"]["name"] variable. How to recode a Russian-language string into transliteration can be found in the PHP examples.

Displaying download status (Progress bar)

It is necessary to take into account that until the file is fully downloaded, PHP cannot operate with either the file size or the percentage of its download. Only when the file is already on PHP server, then he gets the opportunity to access information. If you still absolutely need to implement this feature, use the Java applet.

File permissions

Problems with rights on the server (upload_tmp_dir)

In Unix-like operating systems Each folder, file, link is assigned corresponding access rights. They may look like rwx-rw-r- or the number 754.

The availability of a file or directory depends on the user ID and group ID of which the user is a member. The mode as a whole is described in terms of three sequences, each with three letters:

Owner Group Other (u) (g) (o) rwx rwx rwx

Here, the owner, group members, and all other users have the rights to read, write to, and execute the file. Rights are any meaningful combination of the following letters:

r Reading rights. (4)
w Write permission. (2)
x Execute right (catalog search). (1)

  • Set the owner of the directory to the user with whose privileges apache is running. You can find this out from the httpd.conf file or by looking at the list of processes on the server. Directory rights must be 700 (rwx------).
  • Regardless of who owns the directory, set permissions to 777 (rwxrwxrwx).

    An example of the implementation of uploading pictures to the server.

    $max_image_width = 380; $max_image_height = 600; $max_image_size = 64 * 1024; $valid_types = array("gif","jpg", "png", "jpeg"); if (isset($_FILES["userfile"])) ( if (is_uploaded_file($_FILES["userfile"]["tmp_name"])) ( $filename = $_FILES["userfile"]["tmp_name"]; $ ext = substr($_FILES["userfile"]["name"], 1 + strrpos($_FILES["userfile"]["name"], ".")); if (filesize($filename) > $max_image_size ) ( echo "Error: File size > 64K."; ) elseif (!in_array($ext, $valid_types)) ( echo "Error: Invalid file type."; ) else ( $size = GetImageSize($filename); if (($size) && ($size< $max_image_width) && ($size < $max_image_height)) { if (@move_uploaded_file($filename, "/www/htdocs/upload/")) { echo "File successful uploaded."; } else { echo "Error: moving fie failed."; } } else { echo "Error: invalid image properties."; } } } else { echo "Error: empty file."; } } else { echo "
    Send this file:
    "; }

    The original article is on the PHP Club website


    How to download a file from the server?
  • This feature allows you to upload both text and binary files. With PHP's authentication and file handling features, you have full control over who is allowed to upload files and what to do with the file once it has been uploaded.

    PHP is capable of receiving downloaded files from any RFC-1867 compliant browser.

    It's also worth noting that PHP supports file upload using the PUT method, which is used in the Netscape Composer and W3C Amaya clients. For more detailed documentation, please refer to the section PUT method support.

    Example #1 Form for uploading files

    A file upload page can be implemented using special form, which looks something like this:

    Send this file:

    In the above example __URL__ must be replaced with a link to a PHP script.

    Hidden field MAX_FILE_SIZE(the value must be specified in bytes) must precede the file selection field, and its value is the maximum accepted file size in PHP. It is recommended to always use this variable as it prevents users from waiting anxiously when transferring huge files, only to find out that the file is too large and the transfer actually failed. Keep in mind that it is quite easy to bypass this limitation on the browser side, so you should not rely on all larger files being blocked by this feature. This is mostly a convenience feature for users of the client side of your application. However, the PHP settings (on the server) regarding the maximum size cannot be bypassed.

    Comment:

    You should also make sure that the upload form has the attribute enctype="multipart/form-data", otherwise the files will not be uploaded to the server.

    The original name of the file on the client's computer.

    $_FILES["userfile"]["type"]

    Mime file type, if the browser provided such information. An example is "image/gif". This mime type is not checked for PHP side, so don't rely on its value without checking.

    $_FILES["userfile"]["size"]

    Size in bytes of the received file.

    $_FILES["userfile"]["tmp_name"]

    The temporary name with which the received file was saved on the server.

    $_FILES["userfile"]["error"]

    At the end of the script, if the downloaded file has not been renamed or moved, it will be automatically deleted from the temporary folder.

    Images:

    foreach ($_FILES [ "pictures" ][ "error" ] as $key => $error ) (
    if ($error == UPLOAD_ERR_OK ) (
    $tmp_name = $_FILES [ "pictures" ][ "tmp_name" ][ $key ];
    // basename() can save you from attacks on the file system;
    // additional file name checking/cleaning may be needed
    $name = basename($_FILES[ "pictures" ][ "name" ][ $key ]);
    move_uploaded_file($tmp_name, "data/$name");
    }
    }
    ?>

    A file download progress bar can be implemented using " tracking file download progress using sessions ".

    Use Psr\Http\Message\UploadedFileInterface;
    use Zend\Diactoros\ServerRequestFactory;

    $request = ServerRequestFactory::fromGlobals();

    if ($request -> getMethod() !== "POST" ) (
    http_response_code(405);
    exit("Use POST method." );
    }

    $uploaded_files = $request -> getUploadedFiles();

    if (
    !isset($uploaded_files [ "files" ][ "x" ][ "y" ][ "z" ]) ||
    ! $uploaded_files [ "files" ][ "x" ][ "y" ][ "z" ] instanceof UploadedFileInterface
    ) {
    http_response_code(400);
    exit("Invalid request body." );
    }

    $file = $uploaded_files [ "files" ][ "x" ][ "y" ][ "z" ];

    if ($file -> getError () !== UPLOAD_ERR_OK ) (
    );
    }

    $file -> moveTo("/path/to/new/file" );

    ?>

    10 years ago

    I think the way an array of attachments works is kind of cumbersome. Usually the PHP guys are right on the money, but this is just counter-intuitive. It should have been more like:

    Array
    => Array
    => facepalm.jpg
    => image/jpeg
    => /tmp/phpn3FmFr
    => 0
    => 15476
    )

    => Array
    =>
    =>
    =>
    => 4
    =>
    )

    and not this
    Array
    => Array
    => facepalm.jpg
    =>
    )

    => Array
    => image/jpeg
    =>
    )

    => Array
    => /tmp/phpn3FmFr
    =>
    )

    => Array
    => 0
    => 4
    )

    => Array
    => 15476
    => 0
    )

    Anyways, here is a fuller example than the sparce one in the documentation above:

    foreach ($_FILES [ "attachment" ][ "error" ] as $key => $error )
    {
    $tmp_name = $_FILES [ "attachment" ][ "tmp_name" ][ $key ];
    if (! $tmp_name ) continue;

    $name = basename($_FILES[ "attachment" ][ "name" ][ $key ]);

    If ($error == UPLOAD_ERR_OK )
    {
    if (move_uploaded_file ($tmp_name, "/tmp/" . $name ))
    $uploaded_array .= "Uploaded file "" . $name . "".
    \n" ;
    else
    $errormsg .= "Could not move uploaded file "". $tmp_name. "" to "" . $name. ""
    \n" ;
    }
    else $errormsg .= "Upload error. [" . $error . "] on file "" . $name . ""
    \n" ;
    }
    ?>

    3 years ago

    The documentation doesn't have any details about how the HTML array feature formats the $_FILES array.

    Example $_FILES array:

    For single file -

    Array
    => Array
    => sample-file.doc
    => application/msword
    => /tmp/path/phpVGCDAJ
    => 0
    => 0
    )

    Multi-files with HTML array feature -

    Array
    => Array
    => Array
    => sample-file.doc
    => sample-file.doc
    )

    => Array
    => application/msword
    => application/msword
    )

    => Array
    => /tmp/path/phpVGCDAJ
    => /tmp/path/phpVGCDAJ
    )

    => Array
    => 0
    => 0
    )

    => Array
    => 0
    => 0
    )

    The problem occurs when you have a form that uses both single file and HTML array feature. The array isn't normalized and tends to make coding for it really sloppy. I have included a nice method to normalize the $_FILES array.

    Function normalize_files_array ($files = ) (

    $normalized_array = ;

    Foreach($files as $index => $file ) (

    If (! is_array ($file [ "name" ])) (
    $normalized_array [ $index ] = $file ;
    continue;
    }

    Foreach($file [ "name" ] as $idx => $name ) (
    $normalized_array [ $index ][ $idx ] = [
    "name" => $name ,
    "type" => $file [ "type" ][ $idx ],
    "tmp_name" => $file [ "tmp_name" ][ $idx ],
    "error" => $file [ "error" ][ $idx ],
    "size" => $file [ "size" ][ $idx ]
    ];
    }

    Return $normalized_array ;

    ?>

    The following is the output from the above method.

    Array
    => Array
    => Array
    => sample-file.doc
    => application/msword
    => /tmp/path/phpVGCDAJ
    => 0
    => 0
    )

    => Array
    => Array
    => sample-file.doc
    => application/msword
    => /tmp/path/phpVGCDAJ
    => 0
    => 0
    )

    => Array
    => sample-file.doc
    => application/msword
    => /tmp/path/phpVGCDAJ
    => 0
    => 0
    )

    10 years ago

    Also note that since MAX_FILE_SIZE hidden field is supplied by the browser doing the submitting, it is easily overridden from the clients" side. You should always perform your own examination and error checking of the file after it reaches you, instead of relying on information submitted by the client. This includes checks for file size (always check the length of the actual data versus the reported file size) as well as file type (the MIME type submitted by the browser can be inaccurate at best, and intentionally set to an incorrect value at worst).

    3 years ago

    For clarity the reason you would NOT want to replace the example script with
    $uploaddir = "./";
    is because if you have no coded file constraints a nerd could upload a php script with the same name of one of your scripts in the scripts directory.

    Given the right settings and permissions php-cgi is capable of replacing even php files.

    Imagine if it replaced the upload post processor file itself. The next "upload" could lead to some easy exploits.

    Even when replacements are not possible; uploading an .htaccess file could cause some problems, especially if it is sent after the nerd throws in a devious script to use htaccess to redirect to his upload.

    There are probably more ways of exploiting it. Don't let the nerds get you.

    More sensible to use a fresh directory for uploads with some form of unique naming algorithm; maybe even a cron job for sanitizing the directory so older files do not linger for too long.

    2 years ago

    I have found it useful to re-order the multidimensional $_FILES array into a more intuitive format, as proposed by many other developers already.

    Unfortunately, most of the proposed functions are not able to re-order the $_FILES array when it has more than 1 additional dimension.

    Therefore, I would like to contribute the function below, which is capable of meeting the aforementioned requirement:

    function get_fixed_files() (
    $function = function($files, $fixed_files = array(), $path = array()) use (& $function ) (
    foreach ($files as $key => $value) (
    $temp = $path ;
    $temp = $key ;

    If (is_array($value)) (
    $fixed_files = $function ($value, $fixed_files, $temp);
    ) else (
    $next = array_splice($temp, 1, 1);
    $temp = array_merge($temp, $next);

    $new = & $fixed_files ;

    Foreach ($temp as $key ) (
    $new = & $new [ $key ];
    }

    $new = $value ;
    }
    }

    Return $fixed_files ;
    };

    Return $function($_FILES);
    }
    ?>

    Side note: the unnamed function within the function is used to avoid confusion regarding the arguments necessary for the recursion within the function, for example when viewing the function in an IDE.