Uploading Folders in HTML5 Uploader PHP

Uploading folders is extremely useful when users are allowed to upload large amounts of files. This topic describes how to set up uploading folders on client side and restore folders structure on a server.

Uploading Folders on Client Side

Configuring folders uploading in HTML5 Uploader is very easy. Just use a single method - ImageUploaderFlash.FolderProcessingMode to specify what you want to allow users doing with folders. Here is a list of possible values:

  • None (same as Skip) - turn folder uploading off.
  • Mixed (same as Show and Upload) - allows both files and folders.
  • Folder - allows only folders.

Note, that you can use the values accepted by Java/ActiveX uploader as well for compatibility.

Important

HTML5 Uploader supports folder uploads only in Chrome. If you want to use it with other browsers as well, it is recommended to use both Java/ActiveX and HTML5/Flash uploaders together as discussed below.

When you turn this feature on, it affects not only the open file/folder dialog, but also drag-and-drop functionality. All its subfolders become selected recursively.

Note

There is a limitation in Google Chrome for a number of files added when you drop a folder - it adds not more than 100 files per a folder. This limitation is not applied if the user adds a folder using a dialog. There is no official information from Google regarding this issue, so it is probably happens only on particular versions.

Here is an example how to use the FolderProcessingMode property:

PHP
<?php
  $uploader = new ImageUploaderFlash("Uploader1");
  $uploader->setFolderProcessingMode("Mixed");
?>

As a result, if a user selects a whole folder, all the files in this folder will be recursively added to the upload pane; so a user can clearly see all the files selected at once. When a user starts the uploading process, the structure of this folder will be sent to a server via relative paths to each of the selected files. For instance, if a user sends a MyDocuments folder, which contains a MyPhotos subfolder, all files inside this subfolder will be sent to a server along with MyDocuments\MyPhotos\filename relative paths and all files contained directly in the MyDocuments folder will have MyDocuments\filename relative paths. In opposite, if the user selects an individual file inside the MyDocuments, no folder name is appended ot the file name.

If you need to access the folder structure of a selected file before the upload, from your JavaScript code, you can use (both getter and setter).

Note

HTML5 Uploader sends only relative paths along with uploaded files rather than full paths. Unfortunately, browsers don't allow receiving full paths from a file system because of the security/privacy reasons.

Restoring Folders Structure on Server Side

Saving files on the server is pretty similar to a regular file uploads as discussed in the Saving Uploaded Files in HTML5/Flash Uploader PHP topic. Just use the UploadHandler class as explained there.

In short, you will have to implement the FileUploadedCallback or AllFilesUploadedCallback event handlers. In these handlers you will receive instances of UploadedFile class which allows saving results easily.

To maintain a folder structure, this class exposes the UploadedFile.RelativePath property which returns the folder structure for a particular file.

Here is a small example:

PHP
<?php
require_once '../ImageUploaderPHP/UploadHandler.class.php';

function onFileUploaded($uploadedFile) {
  global $galleryPath;

  $absGalleryPath = realpath($galleryPath) . DIRECTORY_SEPARATOR;

  $originalFileName = $uploadedFile->getSourceName();
  $originalFilePath = str_replace('\\', '/', $uploadedFile->getRelativePath());

  $path = explode('/', $originalFilePath);

  // Sanitize the path to avoid invalid characters.
  $dirName = '';
  for ($j = 0; $j < count($path); $j++) {
    $dirName .= preg_replace('/[^a-z0-9_\-\.()\[\]{}]/i', '_', $path[$j]) . '/';
    if (!is_dir($absGalleryPath . $dirName)) {
      mkdir($absGalleryPath . $dirName, 0777);
    }
  }
  $path = rtrim($dirName, '/\\') . '/';

  //save source file
  $sourceFile = $uploadedFile->getConvertedFiles()[0];
  if ($sourceFile) {
    $sourceFileName = getSafeFileName($absGalleryPath, $originalFileName);
    $sourceFile->moveTo($absGalleryPath . $path . $sourceFileName);
  }
}

$uh = new UploadHandler();
$uh->setFileUploadedCallback('onFileUploaded');
$uh->processRequest();
?>

If you rather prefer saving files without the UploadHandler and use the $_FILES and $_POST arrays directly, the relative path data is appended to the SourceName_i POST variable.

Using both HTML5 and Java uploaders together

Unfortunately the folder selection functionality works only in Google Chrome browser. If you enable the folder uploading and open the uploader in, say, Firefox or IE, it will ignore the FolderProcessingMode property.

The workaround is to use HTML5 Uploader in Chrome while load Java/ActiveX uploader in other browsers. Like this:

PHP
// If the user uses Chrome, create ImageUploaderFlash or Uploader class. 
$uploader = null;
if (strpos($_SERVER['HTTP_USER_AGENT'],"Chrome") === false)
{
  // It is Firefox, IE or Safari. Specify here the Java/ActiveX specific params.
              require_once '../ImageUploaderPHP/Uploader.class.php';
              $uploader = new Uploader('Uploader1');
              $uploader->getFolderPane()->setViewMode('Details');
              $uploader->getFolderPane()->setHeight(500);
            $uploader->getPaneItem()->setShowFileNameInThumbnailsView(TRUE);
            
          $uploader->getDetailsViewColumns()->setInfoText('');
          $uploader->getDetailsViewColumns()->setDimensionsText('');
          $uploader->getUploadSettings()->setFilesPerPackage(1);
}
else 
{
  // It is Chrome. Specify here the HTML5/Flash specific params.
              require_once '../ImageUploaderFlashPHP/ImageUploaderFlash.class.php';
    ImageUploaderFlash::renderCssRules();
  $uploader = new ImageUploaderFlash('Uploader1');
}

        // Specify here the shared params (which are the same in both uploaders)
        $uploader->setHeight('500px');
        $uploader->setWidth('100%');
// You can insert both Java/ActiveX and HTML5/Flash license keys separated with a semicolon.
        $uploader->setLicenseKey('XXXXX-XXXXX-XXXXX-XXXXX-XXXXXX;ZZZZZ-ZZZZZ-ZZZZZ-ZZZZZ-ZZZZZZ');
        $uploader->setFolderProcessingMode('Upload');
        $uploader->getUploadPane()->setViewMode('Tiles');
        $uploader->getUploadSettings()->setActionUrl('upload.php');
        $uploader->getUploadSettings()->setRedirectUrl('gallery.php');
        
        $converter1 = new Converter();
        $converter1->setMode('*.*=SourceFile');
        $uploader->setConverters(array($converter1));
        
        $uploader->render();

The same server file processing code should work fine with both uploaders.

See Also

Reference

Manual