views:

117

answers:

1

Admittedly, there are similar questions lying around on SO. But it seems none quite meet my requirements. Here is what I'm looking to do:

  • Upload an entire form of data, one piece of which is a single file
  • Work with Codeigniter's file upload library

Up until here, all is well. The data gets in my database as I need it. Good good. But I'd also like to submit my form via an AJAX post:

  • Using the native HTML5 File API, not flash or an iFrame solution
  • Preferably interfacing with the low-level .ajax jQuery method

I think I could imagine how to do this by auto-uploading the file when the field's value changes using pure javascript, but I'd rather do it all in one fell swoop on for submit in jQuery. I'm thinking it's not possible to do via query strings as I need to pass the entire file object, but I'm a little lost on what to do at this point. Am I chasing a unicorn here?

Thanks so much for any help you could give.

+2  A: 

It's not too hard. Firstly, take a look at FileReader Interface.

So, when the form is submitted, catch the submission process and

var file = document.getElementById('fileBox').files[0]; //Files[0] = 1st file
var reader = new FileReader();
reader.readAsText(file, 'UTF-8');
reader.onload = shipOff;
//reader.onloadstart = ...
//reader.onprogress = ... <-- Allows you to update a progress bar.
//reader.onabort = ...
//reader.onerror = ...
//reader.onloadend = ...


function shipOff(event) {
    var result = event.target.result;
    var fileName = document.getElementById('fileBox').files[0].name; //Should be 'picture.jpg'
    $.post('/myscript.php', { data: result; name: fileName; }, continueSubmission);
}

Then, on the server side (i.e. myscript.php):

$data = $_POST['data'];
$fileName = $_POST['fileName'];
$serverFile = time().$fileName;
$fp = fopen('/uploads/'.$serverFile,'w'); //Prepends timestamp to prevent overwriting
fwrite($fp, $data);
fclose($fp);
$returnData = array( "serverFile" => $serverFile );
echo json_encode($returnData);

Or something like it. I may be mistaken (and if I am, please, correct me), but this should store the file as something like 1287916771myPicture.jpg in /uploads/ on your server, and respond with a JSON variable (to a continueSubmission() function) containing the fileName on the server.

Check out fwrite() and jQuery.post().

On the above page it details how to use readAsBinaryString(), readAsDataUrl(), and readAsArrayBuffer() for your other needs (e.g. images, videos, etc).

clarkf
Hey Clark, am I understanding correctly? This will send the uploaded file as soon as it's loaded into the FileReader constructor from the file system, bypassing jQuery's low-level .ajax handler. Then the rest of the form will submit as normal?
Joshua Cody
All right, so I was wrong in my understanding before. Now I'm taking the readAsDataUrl of an image, adding it to my datastring in .ajax, and submitting all my info together. My previous solution involved CodeIgniter's default file input class which grabbed data from $_FILES['field'], so it looks like I'll need to switch to a different solution for parsing the base64 image data. Any advice on that is welcomed, upvoting your answer here, and once I finish implementation, I'll mark it as correct.
Joshua Cody
@Joshua Cody - I updated the answer to give a little more detail. You'll have to forgive that I haven't used CodeIgniter in many moons and couldn't tell you how to integrate this into their codebase. I'm not sure why you need to upload the file before submission, but this should at least give you a clue. (You could also insert the image into a database if that's better for you).
clarkf
@Clarkf, I don't need to upload before submission, I was misunderstanding your previous example :) After SO went down and I spent some time on the w3 and [HTML5Rocks](http://www.html5rocks.com/tutorials/file/dndfiles/#toc-monitoring-progress), I started to understand. I'll give this a shot and be back here.
Joshua Cody
All right, been messing with this all morning. PHP seems to be returning badly-formatted files. See [two images](http://drp.ly/GCdK), one rendered immediately and the other after a $_POST to the server and immediate echo. A diff on the two elements reveals [this](http://drp.ly/PVMe), that apparently PHP is stripping all "+" characters. A str_replace fixes this for immediate return, but the file that's saved is still corrupt and can't be opened via my file system. Also, going ahead and marking this as correct. Thanks so much for your help so far.
Joshua Cody
@Joshua Cody - Ah, well, it seems the problem lay in the encoding aspect. There are two different ways to encode a space character (' ') for use in a query string - '%20' and '+'. jQuery's `.post()` method utilizes their `.param()` method, which formats according to the +. Running a quick test, `$.param({hi: 'HELLO + WORLD'})` yields `hi=HELLO+%2B+WORLD`, meaning the literal + is encoded as `%2B`, and for some reason PHP is double-unserializing the data.
clarkf
Hey Clark, I got the solution. Turns out I needed to URIEncode what I was passing, then do a preg_replace to pull out the file's metadata, then base64_decode what that left me, then write those contents to disk. Perfect! Thanks so much for all of your help!
Joshua Cody