Keep Directory Structure When Uploading

2012
12
June
1:18 pm

So lately I’ve been playing around a lot with the new File API and some image manipulation etc. in javascript and am having tremendous fun doing so!
I’ve seen many people asking about folder uploading, which is an exciting new development. The problem most people seem to be having is with retaining file structures when uploading folders.

It is possible to retain the structure of folders during uploading. At the point of writing, I have been unable to find an equivalent for browsers that do not use webkit.
This post is for TESTING ONLY.

I’m working on a full AJAX folder upload script, but as I go, I’ll try to post little snippets I find interesting!

So, without further ado, the code:

<input type="file" id="files" name="files[]" multiple webkitdirectory />​

document.getElementById('files').onchange = function(e) {
  var files = e.target.files; // FileList
  for (var i = 0, f; f = files[i]; ++i)
    console.debug(files[i].webkitRelativePath);
}​

Retrieving the paths is as simple as that!
And here’s a working example:
This is the most basic version and will display a list of the submitted.
The fiddle is slightly more complex than the code above to allow it to be displayed without consoles and whatnot.

Uploading This To The Server!

Things start getting slightly more complex when we come to uploading this to the server.

As far as I’ve been able to find at the time of writing, HTTP request does not support the transfer of file paths when uploading. This can be easily resolved by adding it into the request data ourselves.

function uploadFiles(files){

	// Create a new HTTP requests, Form data item (data we will send to the server) and an empty string for the file paths.
	xhr = new XMLHttpRequest();
	data = new FormData();
	paths = "";
	
	// Set how to handle the response text from the server
	xhr.onreadystatechange = function(ev){
		console.debug(xhr.responseText);
	};
	
	// Loop through the file list
	for (var i in files){
		// Append the current file path to the paths variable (delimited by tripple hash signs - ###)
		paths += files[i].webkitRelativePath+"###";
		// Append current file to our FormData with the index of i
		data.append(i, files[i]);
	};
	// Append the paths variable to our FormData to be sent to the server
	// Currently, As far as I know, HTTP requests do not natively carry the path data
	// So we must add it to the request manually.
	data.append('paths', paths);
		
	// Open and send HHTP requests to upload.php
	xhr.open('POST', "upload.php", true);
	xhr.send(this.data);
}

This will simply create a triple hash delimited string which we will split into an array of file paths on the server which will correspond to our array of files.

<?php
if(sizeof($_FILES) > 0)
	$fileUploader = new FileUploader($_FILES);

class FileUploader{
	public function __construct($uploads,$uploadDir='uploads/'){
		
		// Split the string containing the list of file paths into an array 
		$paths = explode("###",rtrim($_POST['paths'],"###"));
		
		// Loop through files sent
		foreach($uploads as $key => $current)
		{
			// Stores full destination path of file on server
			$this->uploadFile=$uploadDir.rtrim($paths[$key],"/.");
			// Stores containing folder path to check if dir later
			$this->folder = substr($this->uploadFile,0,strrpos($this->uploadFile,"/"));
			
			// Check whether the current entity is an actual file or a folder (With a . for a name)
			if(strlen($current['name'])!=1)
				// Upload current file
				if($this->upload($current,$this->uploadFile))
					echo "The file ".$paths[$key]." has been uploadedn";
				else 
					echo "Error";
		}
	}
	
	private function upload($current,$uploadFile){
		// Checks whether the current file's containing folder exists, if not, it will create it.
		if(!is_dir($this->folder)){
			mkdir($this->folder,0700,true);
		}
		// Moves current file to upload destination
		if(move_uploaded_file($current['tmp_name'],$uploadFile))
			return true;
		else 
			return false;
	}
}
?>

Progress

This is by no means perfect, this is just something I’ve been playing around with and felt like sharing my findings. I’ll be updating this post when I have more to post. Or if it’s something especially exciting, I may even make a new post

So for now, have fun and find the archived source here!

Posted in: Development
Download
Source

Comments

  1. Pingback: Sapphion » HTML5 Upload Folder With Webkitdirectory

  2. I’ve downloaded the package and tried to upload 6 pics of different types, but it doesn’t work, without any prompt. I used it in IE, in firefox and in google-chrome. None of them worked!

  3. my fault… it worked! Thanks :-)

  4. hi, Alan it was great! thanks a lot…

  5. How can i show the progress bar in the above for uploading the directory

  6. R u sure it will work in linux evironment?

  7. Doesnt Work with pics & not working in firefox….
    please help

  8. Hello Alan

    We it seems theres some bug in the code,can you help me out? It works fine but when I try to send a folder to the server(localhost:xampp) with 25 files it only sends 20, theres always some missing like that. can you check it out please?

    Awsome work otherwise (y)

Leave a Reply

Your email address will not be published. Required fields are marked *