Saving Uploaded Files in ActiveX/Java Uploader Other Platforms

As you know ActiveX/Java Uploader sends files and additional metadata from client computers to server side in HTTP POST requests. This approach requires a server script to parse the received requests and handle uploaded data. Such script usually extracts files and additional data sent by clients and save them all to file system on a server or handle in some other way. Reading this topic you will learn how to create such scripts in general. Moreover, this topic presents sample upload scripts for the ASP, JSP, and ColdFusion platforms.

Upload Processing Approaches

Note

Whatever approach you choose pay attention to the fact that 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.

Reading the Entire Request at Once

The most obvious way to provide access to uploaded data from the upload processing page is to receive the entire request and after that fill a special memory structure with elements of the request. Usually upload processing facilities provide two collections: Form and Files. The first one contains a collection of simple POST fields (integer and string values), the second one contains files.

The advantage of such an approach is that after you fill these collections, you have an access to any element of the request at any moment. You do not care in what order the files and variables were sent. In a number of cases it makes script logic clear and coding easier.

However, the price for it is a memory overhead. It becomes more noticeable when you upload a lot of files and these files are big. Usually you do not need to have all files at one time because you process files one-by-one (save them to disk or carry out some else operations). But you have to load all files into memory, and it makes your server to work much slower, especially if multiple users are uploading files simultaneously.

You can eliminate this problem by uploading files in separate requests as discussed in the Sending All Files at Once or in Several Parts in ActiveX/Java Uploader topic. It will reduce the problem if multiple small files are uploaded; however, it will not be helpful enough if few huge files are uploaded (e.g. video movies, etc).

In some implementations of the server-side upload facilities this problem is solved by storing uploaded files on a disk instead of memory.

Reading the Request Incrementally

A more complex, but more efficient upload processing technique is to process the data while receiving the request (in other words, incrementally). The crucial difference with the previous approach is that you work with the uploaded request as with a stream rather than a collection of elements.

It means that you cannot rewind to the files which were processed before and go forward to files which are not yet processed. But you do not have to wait until all files are received, and more importantly, you do not have memory overhead.

So incremental upload processing is more difficult to use, but the performance is noticeably better. That is why if you expect that users will upload a large amount of data, we strongly recommend you to consider this technique in your upload processing script.

This stream-based uploading technique is implemented with some ASP components, for example - Dundas Upload component.

Request Integrity Checking

Even through the user aborts uploading, the upload script is run and receives an incomplete request. Such requests may cause unexpected errors in your upload script. For example, the script may try to save a thumbnail which is not actually uploaded due to cancellation. To avoid this problem, it is recommended to add request integrity check in your upload script before parsing the request and saving uploaded files.

To perform this check you can use the RequestComplete POST field which is sent by ActiveX/Java Uploader at the end of the upload request. Thus, if this field is not received the upload is considered as cancelled.

The code samples below demonstrate how this check can be done in JSP and ColdFusion.

JSP
// Check that all files are uploaded
FileItem requestComplete = fileItems.get("RequestComplete");
if (requestComplete == null || !"1".equals(requestComplete.getString())) {
	return;
}
ColdFusion
<!--- Check that all files are uploaded. --->
<cfif NOT IsDefined("FORM.RequestComplete")>
	<cfabort />
</cfif>

Client-Side Configuration

All the server-side upload scripts considered in this topic is designed having in mind that ActiveX/Java Uploader is configured to send SourceFile as first converted file and Thumbnail as the second one. The following code snippet shows such configuration:

JavaScript
var fu = $au.uploader({
    id: 'Uploader1',
    converters: [
    {mode: '*.*=SourceFile'},
    {mode: '*.*=Thumbnail'}
    ]
});

If you send some other set of converted files, the server scripts can be easily adapted to your configuration.

Uploading in ASP

ASP does not have any standard file upload processing facilities, and that is why there are a lot of third-party ActiveX components for this purpose available. Most components implement the simple uploading technique of loading entire request into memory; however, there are components which can process the request incrementally.

The following code sample demonstrates incremental uploading technique of the Dundas Upload component.

When you call the GetNextFile method, the component uploads data until the first uploaded file is encountered. This way it fills the Form collection with variables, which are sent before the file, but the file itself is not requested. As soon as you call the Save method, the file is actually uploaded and saved directly to disk (without storing it in memory). Then the GetNextFile and Save calls are repeated for all other files.

Note

Although the GetNextFile does not upload all form variables, but only those ones that were met before, you still have access to all data after the first call of the GetNextFile. ActiveX/Java Uploader puts all form variables (both additional form and its own variables like FileCount, etc) in the beginning of upload stream. That is why first call of GetNextFile will request all these variables.

ASP
<%@  language="VBScript" %>
<!--#INCLUDE FILE="../Config.asp"-->
<%
Server.ScriptTimeout = 450

'This variable specifies relative path to the folder, where the gallery with uploaded files is located.
'Do not forget to put slash at the end of the folder name.
Dim strGalleryPath
strGalleryPath = "../UploadedFiles/"

Sub ProcessDundasUpload
	'Create Dundas Upload object for upload processing.
	Dim objUpload
	Set objUpload = Server.CreateObject("Dundas.Upload.2")
	objUpload.UseVirtualDir = False
	objUpload.MaxUploadSize = 1000000000
	
	'Fetch first source file to populate Form collection.
	Dim objSourceFile
	Set objSourceFile = objUpload.GetNextFile

	'Get total number of uploaded files (all files are uploaded in a single package).
	Dim intFileCount, i
	intFileCount = CInt(objUpload.Form("PackageFileCount").Value)

	'Iterate through uploaded data and save the original file, thumbnail, and description.
	For i = 0 To intFileCount - 1
		'Get source file and save it to disk.
		If i > 0 Then
			Set objSourceFile = objUpload.GetNextFile
		End If		
		
		'Get source file and save it to disk.
		Dim strFileName
		strFileName = objUpload.GetFileName(objSourceFile.OriginalPath)
		objSourceFile.Save Server.MapPath(strGalleryPath)
		objUpload.FileMove Server.MapPath(strGalleryPath & objSourceFile.FileName), _
			Server.MapPath(strGalleryPath & strFileName)		

		'Get first thumbnail (the single thumbnail in this code sample) and save it to disk.
		Dim objThumbnail1File
		Set objThumbnail1File = objUpload.GetNextFile		
		objThumbnail1File.Save Server.MapPath(strGalleryPath)
		objUpload.FileMove Server.MapPath(strGalleryPath & objThumbnail1File.FileName), _
			Server.MapPath(strGalleryPath & "Thumbnails/" & strFileName & ".jpg")
	Next
End Sub

Dim objFileSystem
Set objFileSystem = Server.CreateObject("Scripting.FileSystemObject")

If Request.ServerVariables("REQUEST_METHOD")= "POST" Then
	ProcessDundasUpload
End If
%>

You can find full source code of this and other samples in the ASP\ subfolder of the ActiveX/Java Uploader installation folder (usually it is C:\Program Files\Aurigma\Upload Suite 8.5.81\ActiveX-Java\).

Uploading in JSP

Here we consider an open-source package called Apache Commons-FileUpload. The package is developed by the Apache Software Foundation, and you can find the most recent version of FileUpload at the following location: http://commons.apache.org/proper/commons-fileupload/.

Our upload script uses the following two classes belonging to the FileUpload package: DiskFileItemFactory and ServletFileUpload. The ServletFileUpload class handles multiple files per single HTML widget, using an instance of DiskFileItemFactory to determine how the data for individual parts is stored. When you call the parseRequest method of the ServletFileUpload class, it returns a list of FileItem class instances that represent uploaded files and POST fields. Finally, script saves uploaded files (an original file and its thumbnail) to the disk.

The following upload script "assumes" that ActiveX/Java Uploader is configured in the way considered above.

JSP
<%@page import="com.aurigma.web.imageuploader.*"%>
<%@page import="java.util.HashMap"%>
<%@page import="java.util.List"%>
<%@page import="org.apache.commons.fileupload.servlet.ServletFileUpload"%>
<%@page import="org.apache.commons.fileupload.disk.DiskFileItemFactory"%>
<%@page import="org.apache.commons.fileupload.FileItemFactory"%>
<%@page import="org.apache.commons.fileupload.FileItem"%>
<%@page import="java.io.File"%>
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%
    if (!"POST".equalsIgnoreCase(request.getMethod())) {
	return;
    }
    
    // Create a factory for disk-based file items
    FileItemFactory factory = new DiskFileItemFactory(10240, new File(gallery.getTempFilesAbsolutePath()));
    ServletFileUpload upload = new ServletFileUpload(factory);

    // Parse request
    List /* FileItem */ fileItemsList = upload.parseRequest(request);

    // Put them in hash table for fast access.
    HashMap<String, FileItem> fileItems = new HashMap<String, FileItem>();
    for (Object item : fileItemsList) {
        FileItem fileItem = (FileItem)item;
        fileItems.put(fileItem.getFieldName(), fileItem);
    }
    
    // Check that all files are uploaded
    FileItem requestComplete = fileItems.get("RequestComplete");
    if (requestComplete == null || !"1".equals(requestComplete.getString())) {
	return;
    }
    
    //Get total number of uploaded files.
    int fileCount = Integer.parseInt(fileItems.get("PackageFileCount").getString());
    
    //Iterate through uploaded data and save the original file, thumbnail, and description.
    String absSourcePath = gallery.getUploadedFilesAbsolutePath();
    for (int i = 0; i < fileCount; i++) {
        //Get source file and save it to disk.
        FileItem sourceFileItem = (FileItem) fileItems.get("File0_" + i);
        String fileName = Utils.getSafeFileName(absSourcePath, sourceFileItem.getName());
        File sourceFile = new File(absSourcePath + File.separator + fileName);
        sourceFileItem.write(sourceFile);
    }
    
%>

You can find full source code of this and other samples in the JSP\ subfolder of the ActiveX/Java Uploader installation folder (usually it is C:\Program Files\Aurigma\Upload Suite 8.5.81\ActiveX-Java\).

Uploading in ColdFusion

ColdFusion exposes easy-to-use upload handling. The tag named <cffile> provides all necessary functionality. In its attributes you specify the field name, the folder where you are going to save it, and what to do in case of file name collision.

To get access to form variables, use the following syntax:

#FORM.<field name>#

For example, to get the file count, use:

#FORM.FILECOUNT#

An example of ColdFusion script that processes the upload is presented below.

Pay attention that the script expects that ActiveX/Java Uploader configuration is the same as the mentioned above.

ColdFusion
<cfprocessingdirective pageEncoding="utf-8" />
<!--- Check if it is POST request 
	otherwise, abort the script.--->
<cfif NOT CGI.REQUEST_METHOD is "POST">
	<cfabort />
</cfif>
<!--- Check that all files are uploaded. 
	"RequestComplete" field is the last field in the POST request sent by ActiveX/Java Uploader.
	If there is no such field in a request, upload process was aborted. --->
<cfif NOT IsDefined("FORM.RequestComplete")>
	<cfabort />
</cfif>
<!---This variable specifies relative path to the folder, where the gallery with uploaded files is located.
	Do not forget to put slash at the end of the folder name.--->
<cfset galleryPath="../UploadedFiles/" />
<cfset absGalleryPath="#ExpandPath(galleryPath)#" />
<cfset absThumbnailsPath="#absGalleryPath#Thumbnails/" />
<!---Get total number of uploaded files (all files are uploaded in a single package) and
	iterate through uploaded data and save the original file, thumbnail, and description.--->
<cfset fileCount=(#Form.PackageFileCount#-1) />
<cfloop index="i" from="0" to="#fileCount#">
	<cfset name="#Form["SourceName_#i#"]#"/>
	<!--- Get source file and save it to disk. --->
	<cffile action="UPLOAD" filefield="File0_#i#" 
		destination="#absGalleryPath#" 
		nameconflict="MakeUnique">
	<cfset sourceFileName="#serverFile#" />
	<!--- Get first thumbnail (the single thumbnail in this code sample) and save it to disk. --->
	<cffile action="UPLOAD" filefield="File1_#i#" 
		destination="#absThumbnailsPath#" 
		nameconflict="MakeUnique">
	<cfset thumbnailFileName="#serverFile#" />
</cfloop>

You can find full source code of this and other samples in the ColdFusion\ subfolder of the ActiveX/Java Uploader installation folder (usually it is C:\Program Files\Aurigma\Upload Suite 8.5.81\ActiveX-Java\).

See Also

Reference