Saving Uploaded Files in ActiveX/Java Uploader PHP

As you know ActiveX/Java Uploader sends files and additional metadata from client computers to server side in HTTP POST requests. This approach requires server script to parse the received requests and handle uploaded data. Reading this topic you will get to know how to extract files and additional data sent by clients, save it all to file system on a server or handle in some other way. There are three approaches to perform this task:

  • Uploading files to the specified folder on a server. This is the simplest way, it allows saving all uploaded files almost without coding. However, this method is not flexible enough, so do not use it if you need to access additional data (e.g. information about original files, additional fields, etc.).
  • Extended processing of uploaded data using the UploadHandler. This approach gives you flexible typed access to all data sent from client computers. It suites best for PHP applications because ActiveX/Java Uploader PHP classes offer server-side API allowing to accomplish any operation on the uploaded data in a usual for PHP developers way.
  • Parsing POST requests using PHP predefined variables ($_FILES and $_POST). This method does not differ from the one when you are using form-based file upload in HTML (browse/upload buttons on your page). If you use it, you get untyped access to uploaded data, also this approach does not support automatic assembling files from chunks (if you enable them in the ActiveX/Java Uploader, of course). The main advantage of this method is that you do not have additional references to ActiveX/Java Uploader PHP in your application.
Note

If you parse requests using PHP predefined variables and enable sending files by chunks you will have to write significant amount of non-trivial server-side code to assembly the files on your server. This way, we do not recommend enabling chunks if you use this method of handling requests.

Further in this topic every approach will be described in detail. Let us start with the UploadHandler class description.

UploadHandler Class

All the ActiveX/Java Uploader PHP classes are located in the /ImageUploaderPHP/ folder. The key class is UploadHandler, which allows processing the data uploaded from client computers. This class has user-friendly API and functionality giving flexible typed access to these data. In order to use UploadHandler you have to include UploadHandler.class.php into your upload handling script (see: Quick Start with ActiveX/Java Uploader PHP), for example, upload.php:

PHP
<?php
require_once "ImageUploaderPHP/UploadHandler.class.php";
$handler = new UploadHandler();
?>

And specify URL to this script as a value of the UploadSettings.ActionUrl property (both absolute and relative URLs are supported) like it is shown below:

PHP
<?php
$uploader->getUploadSettings()->setActionUrl("upload.php");
?>

Uploading Files to Specified Folder

This section describes the simplest way of handling uploaded data - autosave. This approach allows you to save all the uploaded files to the specified folder on your server without writing a lot of code. The UploadHandler class described in the previous section can save uploaded files automatically. You just create a new instance of this class in your upload handling script and call its saveFiles(string) method providing a path to the folder where uploaded files should be saved as a parameter. If the specified folder does not exist ActiveX/Java Uploader tries to create it.

Also autosave supports the Uploader.FolderProcessingMode feature that allows uploading whole folders rather than just files and restoring their structure on server side automatically, see the Uploading Folders via ActiveX/Java Uploader in PHP topic for more information.

If you need to process the saved files in some way, then a page specified in the UploadSettings.RedirectUrl setting is the right place for this. Just put your code there and it will be executed after the upload process is completed.

The example below shows how to save all the uploaded files.

The upload.php file:

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

$handler = new UploadHandler();
$handler->saveFiles("Catalog/");
?>

And a script initializing the Uploader object must contain the following code:

PHP
<?php
$uploader->getUploadSettings()->setActionUrl("upload.php");
?>

Filenames Conversions and Collisions

ActiveX/Java Uploader prepares files on client side in the way set by so-called converters. Each converter specifies what to do with a file selected for upload: upload it as is or apply some transformation before upload (resize image down, extract and send icon associated with a file, or compress a file to ZIP format). Converters (except for SourceFile one) add suffixes to file names uploaded to a server. For example, the name.ext_Thumbnail0.ext filename is the result of applying Mode="*.*=Thumbnail" converter on name.ext file. For a full list of possible suffixes see the ConvertedFile.Name property description.

Filenames collisions may occur while saving uploaded files to a destination folder. If the destination folder already has a file with the same name as uploaded one, the uploaded file will be saved under its name appended by _xx, where xx is a number starting from 2. For example, if there is a file with the name name.ext in the destination folder and a user tries to upload another file with the same name then uploaded file is saved as name_02.ext file. If name_02.ext file exists as well then the recently uploaded file gets name_03.ext filename and so on.

Extended Processing of Uploaded Data

This approach requires quite a bit of code, however, this method is more flexible than autosave described before. The main idea is to handle uploaded files and data in the callback functions specified by FileUploadedCallback and/or AllFilesUploadedCallback settings of the mentioned before UploadHandler class. The first function is called each time a user-specified file is successfully uploaded. The second function is called when the whole upload session completes and all the files, metadata, and additional data are received on the server side. The first one is called as many times as number of files selected for upload, whereas the second one is called only once.

Now, when you understand the differences between these events, let us discuss how to create these event handlers. There are two steps to this process:

Creating Skeleton Callback Functions

There is a requirement for the callback functions - they must have an argument, which gets an UploadedFile or an UploadedFile array value. The following example sets both, FileUploadedCallback and AllFilesUploadedCallback, callback functions, and enables request processing by calling the processRequest() method:

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

$handler = new UploadHandler();
$handler->setFileUploadedCallback("saveUploadedFile");
$handler->setAllFilesUploadedCallback("saveAllUploadedFiles");
$handler->processRequest();

function saveAllUploadedFiles($uploadedFiles) {
    //...
    foreach ($uploadedFiles as $uploadedFile)
    {
        //...
    }
    //...
}

function saveUploadedFile($uploadedFile) {
    //...
}
?>

There is the example of callback function implementation below.

Also do not forget to set the UploadSettings.ActionUrl property.

Writing Implementation of Callback Functions

For better understanding let us separate description of the uploaded data handling into the following sections:

Files Handling

The PHP server-side part of ActiveX/Java Uploader among its types has the UploadedFile class. This type holds all the data associated with a single file selected for upload (files prepared on client side by ActiveX/Java Uploader from the original file in accordance with converters set in the settings, additional fields, and other data). The FileUploadedCallback callback function gives access to an UploadedFile instance through the function argument. The AllFilesUploadedCallback callback function gives access to an array of UploadedFile objects also via its argument.

Now let us examine how to get access to uploaded files via the UploadedFile instances. Each UploadedFile object has associated collection of files prepared by ActiveX/Java Uploader converters on client side. Each of these files is represented by an instance of the ConvertedFile type. This way, the collection of converted files associated with a particular file selected for upload is accessible via the UploadedFile.ConvertedFiles property.

Each ConvertedFile object has two main members to handle the file:

  • the FileContent property for getting access to the file content
  • the moveTo(string) method for moving the file to the specified location

Metadata Handling

All the metadata uploaded along with a file is accessible through the UploadedFile properties and can be divided into the following groups:

File Location

There is the only one property in this group - the UploadedFile.RelativePath which returns a relative path to the original file on the client machine. This property makes sense only if ActiveX/Java Uploader is allowed to upload folders (FolderProcessingMode has Upload value).

Original File Information

This group includes properties containing information about the original file:

Converted File Information

The ConvertedFile class provides access to some additional information along with access to the converted file itself. Its properties contain the following information:

  • Mode contains a converter type applied to create the converted file.
  • Size represents size (in bytes) of the converted file.
  • Height and Width represent dimensions of the created downsized image (in pixels) if the converter was set to resize an original image down.

User-defined Data

This group includes the following properties:

Callback Function Example

This example is a FileUploadedCallback callback function which saves an original file and its resized copy to the ../Gallery/ and ../Gallery/Thumbnails/ folders respectively and writes some file-related information (filenames, image dimensions, user description, and etc.) to an XML file. This function is called only once when the whole upload session completes as it is set by the AllFilesUploadedCallback property.

PHP
<?php
function saveAllUploadedFiles($uploadedFiles) {
    $galleryPath = "Gallery/";
    $absGalleryPath = realpath($galleryPath);
    $absThumbnailsPath = realpath($galleryPath . DIRECTORY_SEPARATOR . "Thumbnails/");
    
    //Create or load XML file which will keep information about files (image dimensions, description, etc).
    $descriptions = new DOMDocument('1.0');
    if (file_exists($absGalleryPath . DIRECTORY_SEPARATOR . "Descriptions.xml"))
        $descriptions->load($absGalleryPath . DIRECTORY_SEPARATOR . "Descriptions.xml");
    else
        $descriptions->appendChild($descriptions->createElement("files"));
    
    foreach ($uploadedFiles as $uploadedFile)
    {
        $convertedFiles = $uploadedFile->getConvertedFiles();
        //Save original file.
        //It is the first file in ConvertedFiles collection as we set first converter mode to SourceFile.
        $sourceFile = $convertedFiles[0];
        getSafeFileName($absGalleryPath, rawurlencode($uploadedFile->getSourceName()));
        $sourceFile->moveTo($absGalleryPath . DIRECTORY_SEPARATOR . $sourceFileName);
        
        //Save thumbnail.
        //It is the second file in ConvertedFiles collection as we set second converter mode to Thumbnail.
        $thumbnailFile = $convertedFiles[1];
        $thumbnailFileName = getSafeFileName($absThumbnailsPath, rawurlencode($uploadedFile->getSourceName()));
        $thumbnailFile->moveTo($absThumbnailsPath . DIRECTORY_SEPARATOR . $thumbnailFileName);
        
        //Save file info.
        $xmlFile = $descriptions->createElement("file");
        $xmlFile->setAttribute("name", $sourceFileName);
        $xmlFile->setAttribute("thumbName", $thumbnailFileName);
        $xmlFile->setAttribute("width", $uploadedFile->getSourceWidth());
        $xmlFile->setAttribute("height", $uploadedFile->getSourceHeight());
        $xmlFile->setAttribute("description", $uploadedFile->getDescription());
        $descriptions->documentElement->appendChild($xmlFile);
    }
    $descriptions->save($absGalleryPath . DIRECTORY_SEPARATOR . "Descriptions.xml");
}

function getSafeFileName($path, $fileName) {
    // ...
}
?>

Parsing POST Requests Using PHP Predefined Variables ($_FILES and $_POST)

The last way of handling uploaded files is to parse the upload request manually via the $_FILES and $_POST "superglobals". To simplify accessing the POST request fields ActiveX/Java Uploader PHP provides the PostFields class.

Note

If you choose this approach we do not recommend enabling chunks, otherwise, you will have to write significant amount of non-trivial server-side code to assembly the files on your server.

Note

ActiveX/Java Uploader sends a HEAD request before the POST one to check if authentication is needed. So, you should check the type of request and handle POST requests only.

The following code sample demonstrates how to save original files, thumbnails, and original file-related information using described approach.

PHP
<?php
require_once "ImageUploaderPHP/PostFields.class.php";

// Check if it is POST request;
// we should not try to save files in HEAD requests.
if ($_SERVER['REQUEST_METHOD'] != 'POST') 
  exit();

$galleryPath = "Gallery";
$absGalleryPath = realpath($galleryPath);
$absThumbnailsPath = realpath($galleryPath . DIRECTORY_SEPARATOR . "Thumbnails");


//Create or load XML file which will keep information about files (image dimensions, description, etc).
$descriptions = new DOMDocument('1.0');
if (file_exists($absGalleryPath . DIRECTORY_SEPARATOR . "Descriptions.xml"))
    $descriptions->load($absGalleryPath . DIRECTORY_SEPARATOR . "Descriptions.xml");
else
    $descriptions->appendChild($descriptions->createElement("files"));

//Get number of files in the current package.
$fileCount = $_POST[PostFields::packageFileCount];

//Iterate through uploaded data and save the original file, thumbnail, and description.
for ($i = 0; $i < $fileCount; $i++) {
    
    $originalFileName = rawurlencode($_POST[sprintf(PostFields::sourceName,$i)]);
    
    //save source file
    $sourceFileName = getSafeFileName($absGalleryPath, $originalFileName);
    if (isset($_FILES[sprintf(PostFields::file, 0, $i)])) {
        move_uploaded_file($_FILES[sprintf(PostFields::file, 0, $i)]["tmp_name"], 
            $absGalleryPath . DIRECTORY_SEPARATOR . $sourceFileName);
    }
    
    //save thumbnail file
    $thumbnailFileName = getSafeFileName($absThumbnailsPath, $originalFileName);
    if (isset($_FILES[sprintf(PostFields::file, 1, $i)])) {
         move_uploaded_file($_FILES[sprintf(PostFields::file, 1, $i)]["tmp_name"], 
            $absThumbnailsPath . DIRECTORY_SEPARATOR . $thumbnailFileName);
    }
    
    //Save file info.
    $xmlFile = $descriptions->createElement("file");
    $xmlFile->setAttribute("name", $sourceFileName);
    $xmlFile->setAttribute("thumbName", $thumbnailFileName);
    $xmlFile->setAttribute("width", $_POST[sprintf(PostFields::sourceWidth, $i)]);
    $xmlFile->setAttribute("height", $_POST[sprintf(PostFields::sourceHeight, $i)]);
    $xmlFile->setAttribute("description", $_POST[sprintf(PostFields::description, $i)]);
    $descriptions->documentElement->appendChild($xmlFile);

}

$descriptions->save($absGalleryPath . DIRECTORY_SEPARATOR . "Descriptions.xml");

function getSafeFileName($path, $fileName) {
    // ...
}
?>

Also do not forget to set the UploadSettings.ActionUrl property.

See Also

Reference

Manual