Categories
PHP

Uploading Multiple Files and Directories

Learn how to handle multiple file uploads in PHP. You’ll also learn how to select directories (instead of files) with the directory picker attribute and upload the directories content to the server. You’ll also use the new feature “full_path” (as of PHP 8.1), a subkey of $_FILES array to create the exact directory structure of uploaded directories.

Handling multiple uploads

PHP can handle multiple file uploads. Since HTML5, the <input> element with type="file" allows you to select one or more files. To do so follow these steps:

<input type="file" name="upload[]" multiple>
  1. Add multiple attribute. When the multiple attribute is specified, the file input allows the user to select more than one file.
  2. Add square brackets [] to the name attribute. Adding square brackets to the name attribute submits multiple values as an array.
<?php
 if ($_SERVER['REQUEST_METHOD'] == 'POST') {
  echo '<pre>';
  print_r($_FILES);
  echo '</pre>';
 }
?>
<form action="example.php" method="post" enctype="multipart/form-data">
 <input type="file" name="upload[]" multiple>
 <input type="submit" name="submit" value="Upload">
</form>
The result of $_FILES array when uploading multiple files

You can see that the details of each file stored in a separate subarray. You can use the numeric keys to retrieve the details of each file, for example, the key 0 refer to the details of the first file in the array:

 $_FILES['upload']['name'][0]
 $_FILES['upload']['type'][0]
 $_FILES['upload']['size'][0] 

The key 1 refers to the details of the next file in the array and so on:

 $_FILES['upload']['name'][1]
 $_FILES['upload']['type'][1]
 $_FILES['upload']['size'][1] 

By running that array through a foreach loop, you can access each file’s details, like this:

<?php
 if ($_SERVER['REQUEST_METHOD'] == 'POST') {
  //$files = isset($_FILES['upload']) ? $_FILES['upload'] : array();

  $files = $_FILES['upload'] ?? [];
  
  foreach ($files['name'] as $k => $v) {
   echo $files['name'][$k].'<br>';
   echo $files['size'][$k].'<br>';
   echo $files['type'][$k].'<br>';
   echo $files['tmp_name'][$k].'<br>';
   echo $files['error'][$k].'<br><br>';
  }

 }
?>
<form action="example.php" method="post" enctype="multipart/form-data">
 <input type="file" name="upload[]" multiple>
 <input type="submit" name="submit" value="Upload">
</form>

Uploading entire directory or folder recursively

The directory picker webkitdirectory attribute in <input> element with type="file" allow you to select directories instead of files. To do so follow these steps:

<input type="file" name="upload[]" multiple webkitdirectory>
  • Add webkitdirectory attribute. Use this directory picker attribute to select directories instead of files.
  • Add multiple attribute. When the multiple attribute is specified, the file input allows the user to select more than one directory.
  • Add square brackets [] to the name attribute. Adding square brackets to the name attribute submits multiple values as an array.

Note: When the webkitdirectory attribute is specified, the entire content of the directory/folder is sent to the server including the subdirectories. You can recreate the same directory structure on the server with the help of full_path ($_FILES['upload']['full_path'][index]) subkey.

The full path (full_path) is submitted by the browser, it does not always contain a real directory structure, and cannot be trusted.

<?php
 if ($_SERVER['REQUEST_METHOD'] == 'POST') {
  $files = $_FILES['upload'] ?? [];

  foreach ($files['name'] as $k => $v) {
   if ($files['error'][$k] == UPLOAD_ERR_OK) {
    $name = $files['name'][$k];

    // full_path available since PHP 8.1
    $full_path = $files['full_path'][$k] ?? $name;

    // Browser didn't send the directory structure
    if ($name == $full_path ) {
     $uploadDir = 'upload/';
    } else {
     //remove filename from the full_path
     $path = str_replace($name, '', $full_path);
     $uploadDir = 'upload/'.$path;
     //if dir not exist on the server, create it
     if (! is_dir($uploadDir) ) {
      mkdir ($uploadDir, 0777, true)
       or die("Failed to create directory: $uploadDir");
     } 
    }

    if ( is_uploaded_file($files['tmp_name'][$k]) ) {
     $m = move_uploaded_file($files['tmp_name'][$k], $uploadDir.'/'.$name);
     if ($m === true)
      echo "$name uploaded successfully<br>";
    }
   }
  }
 }
?>
<form action="example.php" method="post" enctype="multipart/form-data">
 <input type="file" name="upload[]" multiple webkitdirectory>
 <input type="submit" name="submit" value="Upload">
</form>

Note: You need to properly configure your PHP server or you’ll receive the following warning messages (depending on your server configuration):

  • Warning: Maximum number of allowable file uploads has been exceeded…
  • Warning: POST Content-Length of 68982407 bytes exceeds the limit of 41943040 bytes in Unknown on line 0

For detail, see Handling File Uploads tutorial.


Processing Forms in PHP: