Many people say uploading files with AJAX is impossible! Well, they‘re wrong :-)
Granted this solution only works with FireFox/Mozilla. And the user has to change a setting in "about:config" and accept the advanced access privileges.
Anyway, such an AJAX file upload is only suitable for restricted area stuff, such as Content Management Systems, Group-Ware etc., so users can be briefed before actually using it.
FireFox/Mozilla settings:
Open about:config and check that
signed.applets.codebase_principal_support
is set to "true"
Otherwise Firefox will display something like this
Error: uncaught exception: A script from "http://www.captain.at"was denied UniversalXPConnect privileges.
Also make sure you check the checkbox "Remember this decision", when FireFox will display this message
A script from "http://www.captain.at" is requesting enhanced abilities that areUNSAFE and could be used to compromise your machine or data:Run or install software on your machineAllow these abilities only if you trust this source to be free of viruses or maliciousprograms.[ ] Remember this decision
and click "Allow", otherwise you have to click "Allow" everytime you upload a file.
The example itself is rather straightforward:
We use some Components.classes and Components.interfaces stuff to open the local file from within FireFox/Mozilla - we read the file, construct our request body for the POST request and send the whole data with an AJAX "multipart/form-data" request.
NOTE about encoding the local files:
Since we also want to upload binary files, we need to encode (javascript "escape") the file content. This is basically encoding a string for use in an URL. On the server, after uploading the file we need to decode ("urldecode") the file. "escape" does not encode the plus sign "+", but on the server PHP‘s "urldecode" interprets any "+" and space. So we need an additional preg_replace to replace any "+" to the HEX value "%2B".
This is a little annoying, since escaping large files (up to 1MB it is still fast) with javascript can hang the browser for a few seconds. The problem here is that the AJAX object XMLHttpRequest doesn‘t seem to be able to handle binary data.
ADVANTAGES:
If you upload images and process them on the server, it is common that the server stops the script due too much memory consumption and/or the runtime limit has been exceeded. In such a case PHP is just returning an error message ("Fatal error: memory limit exceeded" or "Fatal error: running too long" or whatever) and the user usually has to back up with the browser back button to repeat the procedure with a smaller image. With AJAX you can check the returned string for errors and if an error has occured, notify the user gracefully.
A possible extension to this example would be:
Let the user select a directory with a custom "directory-browser" or one file in a directory with the regular file-dialog as shown here, then parse the directory automatically for file with a certain extension and upload them in a bulk.
LICENCE: As stated in the policy:
The information provided on the websites of Captain‘s Universe is free for non-commercial, educational use. For commercial use of any of the information provided, contact the owner at the email address listed in the footer below.
index.html
<html><body><script>var url = "post.php";var binary;var filename;var mytext;function upload() {filename = document.getElementById(‘myfile‘).value;mytext = document.getElementById(‘mytext‘).value;document.getElementById(‘a(chǎn)jaxbutton‘).disabled = true;// request local file read permissiontry {netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");} catch (e) {alert("Permission to read file was denied.");}// open the local filevar file = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);file.initWithPath( filename );stream = Components.classes["@mozilla.org/network/file-input-stream;1"].createInstance(Components.interfaces.nsIFileInputStream);stream.init(file, 0x01, 00004, null);var bstream = Components.classes["@mozilla.org/network/buffered-input-stream;1"].getService();bstream.QueryInterface(Components.interfaces.nsIBufferedInputStream);bstream.init(stream, 1000);bstream.QueryInterface(Components.interfaces.nsIInputStream);binary = Components.classes["@mozilla.org/binaryinputstream;1"].createInstance(Components.interfaces.nsIBinaryInputStream);binary.setInputStream (stream);// start AJAX file upload in 1 secondwindow.setTimeout("ajax_upload()", 1000);}function ajax_upload() {// request more permissionstry {netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");} catch (e) {alert("Permission to read file was denied.");}http_request = false;http_request = new XMLHttpRequest();if (!http_request) {alert(‘Cannot create XMLHTTP instance‘);return false;}// prepare the MIME POST datavar boundaryString = ‘capitano‘;var boundary = ‘--‘ + boundaryString;var requestbody = boundary + ‘\n‘+ ‘Content-Disposition: form-data; name="mytext"‘ + ‘\n‘+ ‘\n‘+ mytext + ‘\n‘+ ‘\n‘+ boundary + ‘\n‘+ ‘Content-Disposition: form-data; name="myfile"; filename="‘+ filename + ‘"‘ + ‘\n‘+ ‘Content-Type: application/octet-stream‘ + ‘\n‘+ ‘\n‘+ escape(binary.readBytes(binary.available()))+ ‘\n‘+ boundary;document.getElementById(‘sizespan‘).innerHTML ="requestbody.length=" + requestbody.length;// do the AJAX requesthttp_request.onreadystatechange = requestdone;http_request.open(‘POST‘, url, true);http_request.setRequestHeader("Content-type", "multipart/form-data; boundary=\"" + boundaryString + "\"");http_request.setRequestHeader("Connection", "close");http_request.setRequestHeader("Content-length", requestbody.length);http_request.send(requestbody);}function requestdone() {if (http_request.readyState == 4) {if (http_request.status == 200) {result = http_request.responseText;document.getElementById(‘myspan‘).innerHTML = result;} else {alert(‘There was a problem with the request.‘);}document.getElementById(‘a(chǎn)jaxbutton‘).disabled = false;}}</script><form>Text: <input type="text" id="mytext" name="mytext" size="40"><br>File: <input type="file" id="myfile" name="datafile" size="40"><br><input type="button" id="ajaxbutton" value="AJAX IT" onclick="upload();"></form><div id="sizespan"></div><hr><div id="myspan"></div></body></html>post.php<?print_r(Many people say uploading files with AJAX is impossible! Well, they‘re wrong :-)
Granted this solution only works with FireFox/Mozilla. And the user has to change a setting in "about:config" and accept the advanced access privileges.
Anyway, such an AJAX file upload is only suitable for restricted area stuff, such as Content Management Systems, Group-Ware etc., so users can be briefed before actually using it.FireFox/Mozilla settings:
Open about:config and check thatsigned.applets.codebase_principal_supportis set to "true"
Otherwise Firefox will display something like thisError: uncaught exception: A script from "http://www.captain.at"was denied UniversalXPConnect privileges.
Also make sure you check the checkbox "Remember this decision", when FireFox will display this messageA script from "http://www.captain.at" is requesting enhanced abilities that areUNSAFE and could be used to compromise your machine or data:Run or install software on your machineAllow these abilities only if you trust this source to be free of viruses or maliciousprograms.[ ] Remember this decision
and click "Allow", otherwise you have to click "Allow" everytime you upload a file.
The example itself is rather straightforward:
We use some Components.classes and Components.interfaces stuff to open the local file from within FireFox/Mozilla - we read the file, construct our request body for the POST request and send the whole data with an AJAX "multipart/form-data" request.
NOTE about encoding the local files:
Since we also want to upload binary files, we need to encode (javascript "escape") the file content. This is basically encoding a string for use in an URL. On the server, after uploading the file we need to decode ("urldecode") the file. "escape" does not encode the plus sign "+", but on the server PHP‘s "urldecode" interprets any "+" and space. So we need an additional preg_replace to replace any "+" to the HEX value "%2B".
This is a little annoying, since escaping large files (up to 1MB it is still fast) with javascript can hang the browser for a few seconds. The problem here is that the AJAX object XMLHttpRequest doesn‘t seem to be able to handle binary data.
ADVANTAGES:
If you upload images and process them on the server, it is common that the server stops the script due too much memory consumption and/or the runtime limit has been exceeded. In such a case PHP is just returning an error message ("Fatal error: memory limit exceeded" or "Fatal error: running too long" or whatever) and the user usually has to back up with the browser back button to repeat the procedure with a smaller image. With AJAX you can check the returned string for errors and if an error has occured, notify the user gracefully.
A possible extension to this example would be:
Let the user select a directory with a custom "directory-browser" or one file in a directory with the regular file-dialog as shown here, then parse the directory automatically for file with a certain extension and upload them in a bulk.LICENCE: As stated in the policy:
The information provided on the websites of Captain‘s Universe is free for non-commercial, educational use. For commercial use of any of the information provided, contact the owner at the email address listed in the footer below.
index.html<html><body><script>var url = "post.php";var binary;var filename;var mytext;function upload() {filename = document.getElementById(‘myfile‘).value;mytext = document.getElementById(‘mytext‘).value;document.getElementById(‘a(chǎn)jaxbutton‘).disabled = true;// request local file read permissiontry {netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");} catch (e) {alert("Permission to read file was denied.");}// open the local filevar file = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);file.initWithPath( filename );stream = Components.classes["@mozilla.org/network/file-input-stream;1"].createInstance(Components.interfaces.nsIFileInputStream);stream.init(file, 0x01, 00004, null);var bstream = Components.classes["@mozilla.org/network/buffered-input-stream;1"].getService();bstream.QueryInterface(Components.interfaces.nsIBufferedInputStream);bstream.init(stream, 1000);bstream.QueryInterface(Components.interfaces.nsIInputStream);binary = Components.classes["@mozilla.org/binaryinputstream;1"].createInstance(Components.interfaces.nsIBinaryInputStream);binary.setInputStream (stream);// start AJAX file upload in 1 secondwindow.setTimeout("ajax_upload()", 1000);}function ajax_upload() {// request more permissionstry {netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");} catch (e) {alert("Permission to read file was denied.");}http_request = false;http_request = new XMLHttpRequest();if (!http_request) {alert(‘Cannot create XMLHTTP instance‘);return false;}// prepare the MIME POST datavar boundaryString = ‘capitano‘;var boundary = ‘--‘ + boundaryString;var requestbody = boundary + ‘\n‘+ ‘Content-Disposition: form-data; name="mytext"‘ + ‘\n‘+ ‘\n‘+ mytext + ‘\n‘+ ‘\n‘+ boundary + ‘\n‘+ ‘Content-Disposition: form-data; name="myfile"; filename="‘+ filename + ‘"‘ + ‘\n‘+ ‘Content-Type: application/octet-stream‘ + ‘\n‘+ ‘\n‘+ escape(binary.readBytes(binary.available()))+ ‘\n‘+ boundary;document.getElementById(‘sizespan‘).innerHTML ="requestbody.length=" + requestbody.length;// do the AJAX requesthttp_request.onreadystatechange = requestdone;http_request.open(‘POST‘, url, true);http_request.setRequestHeader("Content-type", "multipart/form-data; boundary=\"" + boundaryString + "\"");http_request.setRequestHeader("Connection", "close");http_request.setRequestHeader("Content-length", requestbody.length);http_request.send(requestbody);}function requestdone() {if (http_request.readyState == 4) {if (http_request.status == 200) {result = http_request.responseText;document.getElementById(‘myspan‘).innerHTML = result;} else {alert(‘There was a problem with the request.‘);}document.getElementById(‘a(chǎn)jaxbutton‘).disabled = false;}}</script><form>Text: <input type="text" id="mytext" name="mytext" size="40"><br>File: <input type="file" id="myfile" name="datafile" size="40"><br><input type="button" id="ajaxbutton" value="AJAX IT" onclick="upload();"></form><div id="sizespan"></div><hr><div id="myspan"></div></body></html>___FCKpd___4
Last-Modified: Sat, 04 Feb 2006 16:03:20 GMT來(lái)自 http://www.captain.at/ajax-file-upload.phpFILES);?><hr><?print_r(Many people say uploading files with AJAX is impossible! Well, they‘re wrong :-)
Granted this solution only works with FireFox/Mozilla. And the user has to change a setting in "about:config" and accept the advanced access privileges.
Anyway, such an AJAX file upload is only suitable for restricted area stuff, such as Content Management Systems, Group-Ware etc., so users can be briefed before actually using it.FireFox/Mozilla settings:
Open about:config and check thatsigned.applets.codebase_principal_supportis set to "true"
Otherwise Firefox will display something like thisError: uncaught exception: A script from "http://www.captain.at"was denied UniversalXPConnect privileges.
Also make sure you check the checkbox "Remember this decision", when FireFox will display this messageA script from "http://www.captain.at" is requesting enhanced abilities that areUNSAFE and could be used to compromise your machine or data:Run or install software on your machineAllow these abilities only if you trust this source to be free of viruses or maliciousprograms.[ ] Remember this decision
and click "Allow", otherwise you have to click "Allow" everytime you upload a file.
The example itself is rather straightforward:
We use some Components.classes and Components.interfaces stuff to open the local file from within FireFox/Mozilla - we read the file, construct our request body for the POST request and send the whole data with an AJAX "multipart/form-data" request.
NOTE about encoding the local files:
Since we also want to upload binary files, we need to encode (javascript "escape") the file content. This is basically encoding a string for use in an URL. On the server, after uploading the file we need to decode ("urldecode") the file. "escape" does not encode the plus sign "+", but on the server PHP‘s "urldecode" interprets any "+" and space. So we need an additional preg_replace to replace any "+" to the HEX value "%2B".
This is a little annoying, since escaping large files (up to 1MB it is still fast) with javascript can hang the browser for a few seconds. The problem here is that the AJAX object XMLHttpRequest doesn‘t seem to be able to handle binary data.
ADVANTAGES:
If you upload images and process them on the server, it is common that the server stops the script due too much memory consumption and/or the runtime limit has been exceeded. In such a case PHP is just returning an error message ("Fatal error: memory limit exceeded" or "Fatal error: running too long" or whatever) and the user usually has to back up with the browser back button to repeat the procedure with a smaller image. With AJAX you can check the returned string for errors and if an error has occured, notify the user gracefully.
A possible extension to this example would be:
Let the user select a directory with a custom "directory-browser" or one file in a directory with the regular file-dialog as shown here, then parse the directory automatically for file with a certain extension and upload them in a bulk.LICENCE: As stated in the policy:
The information provided on the websites of Captain‘s Universe is free for non-commercial, educational use. For commercial use of any of the information provided, contact the owner at the email address listed in the footer below.
index.html<html><body><script>var url = "post.php";var binary;var filename;var mytext;function upload() {filename = document.getElementById(‘myfile‘).value;mytext = document.getElementById(‘mytext‘).value;document.getElementById(‘a(chǎn)jaxbutton‘).disabled = true;// request local file read permissiontry {netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");} catch (e) {alert("Permission to read file was denied.");}// open the local filevar file = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);file.initWithPath( filename );stream = Components.classes["@mozilla.org/network/file-input-stream;1"].createInstance(Components.interfaces.nsIFileInputStream);stream.init(file, 0x01, 00004, null);var bstream = Components.classes["@mozilla.org/network/buffered-input-stream;1"].getService();bstream.QueryInterface(Components.interfaces.nsIBufferedInputStream);bstream.init(stream, 1000);bstream.QueryInterface(Components.interfaces.nsIInputStream);binary = Components.classes["@mozilla.org/binaryinputstream;1"].createInstance(Components.interfaces.nsIBinaryInputStream);binary.setInputStream (stream);// start AJAX file upload in 1 secondwindow.setTimeout("ajax_upload()", 1000);}function ajax_upload() {// request more permissionstry {netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");} catch (e) {alert("Permission to read file was denied.");}http_request = false;http_request = new XMLHttpRequest();if (!http_request) {alert(‘Cannot create XMLHTTP instance‘);return false;}// prepare the MIME POST datavar boundaryString = ‘capitano‘;var boundary = ‘--‘ + boundaryString;var requestbody = boundary + ‘\n‘+ ‘Content-Disposition: form-data; name="mytext"‘ + ‘\n‘+ ‘\n‘+ mytext + ‘\n‘+ ‘\n‘+ boundary + ‘\n‘+ ‘Content-Disposition: form-data; name="myfile"; filename="‘+ filename + ‘"‘ + ‘\n‘+ ‘Content-Type: application/octet-stream‘ + ‘\n‘+ ‘\n‘+ escape(binary.readBytes(binary.available()))+ ‘\n‘+ boundary;document.getElementById(‘sizespan‘).innerHTML ="requestbody.length=" + requestbody.length;// do the AJAX requesthttp_request.onreadystatechange = requestdone;http_request.open(‘POST‘, url, true);http_request.setRequestHeader("Content-type", "multipart/form-data; boundary=\"" + boundaryString + "\"");http_request.setRequestHeader("Connection", "close");http_request.setRequestHeader("Content-length", requestbody.length);http_request.send(requestbody);}function requestdone() {if (http_request.readyState == 4) {if (http_request.status == 200) {result = http_request.responseText;document.getElementById(‘myspan‘).innerHTML = result;} else {alert(‘There was a problem with the request.‘);}document.getElementById(‘a(chǎn)jaxbutton‘).disabled = false;}}</script><form>Text: <input type="text" id="mytext" name="mytext" size="40"><br>File: <input type="file" id="myfile" name="datafile" size="40"><br><input type="button" id="ajaxbutton" value="AJAX IT" onclick="upload();"></form><div id="sizespan"></div><hr><div id="myspan"></div></body></html>___FCKpd___4
Last-Modified: Sat, 04 Feb 2006 16:03:20 GMT
___FCKpd___5POST); $fpath = "/tmp/"; // move (actually just rename) the temporary file to the real name move_uploaded_file (
Many people say uploading files with AJAX is impossible! Well, they‘re wrong :-)
Granted this solution only works with FireFox/Mozilla. And the user has to change a setting in "about:config" and accept the advanced access privileges.
Anyway, such an AJAX file upload is only suitable for restricted area stuff, such as Content Management Systems, Group-Ware etc., so users can be briefed before actually using it.
FireFox/Mozilla settings:
Open about:config and check that
signed.applets.codebase_principal_support
is set to "true"
Otherwise Firefox will display something like this
Error: uncaught exception: A script from "http://www.captain.at"was denied UniversalXPConnect privileges.
Also make sure you check the checkbox "Remember this decision", when FireFox will display this message
A script from "http://www.captain.at" is requesting enhanced abilities that areUNSAFE and could be used to compromise your machine or data:Run or install software on your machineAllow these abilities only if you trust this source to be free of viruses or maliciousprograms.[ ] Remember this decision
and click "Allow", otherwise you have to click "Allow" everytime you upload a file.
The example itself is rather straightforward:
We use some Components.classes and Components.interfaces stuff to open the local file from within FireFox/Mozilla - we read the file, construct our request body for the POST request and send the whole data with an AJAX "multipart/form-data" request.
NOTE about encoding the local files:
Since we also want to upload binary files, we need to encode (javascript "escape") the file content. This is basically encoding a string for use in an URL. On the server, after uploading the file we need to decode ("urldecode") the file. "escape" does not encode the plus sign "+", but on the server PHP‘s "urldecode" interprets any "+" and space. So we need an additional preg_replace to replace any "+" to the HEX value "%2B".
This is a little annoying, since escaping large files (up to 1MB it is still fast) with javascript can hang the browser for a few seconds. The problem here is that the AJAX object XMLHttpRequest doesn‘t seem to be able to handle binary data.
ADVANTAGES:
If you upload images and process them on the server, it is common that the server stops the script due too much memory consumption and/or the runtime limit has been exceeded. In such a case PHP is just returning an error message ("Fatal error: memory limit exceeded" or "Fatal error: running too long" or whatever) and the user usually has to back up with the browser back button to repeat the procedure with a smaller image. With AJAX you can check the returned string for errors and if an error has occured, notify the user gracefully.
A possible extension to this example would be:
Let the user select a directory with a custom "directory-browser" or one file in a directory with the regular file-dialog as shown here, then parse the directory automatically for file with a certain extension and upload them in a bulk.
LICENCE: As stated in the policy:
The information provided on the websites of Captain‘s Universe is free for non-commercial, educational use. For commercial use of any of the information provided, contact the owner at the email address listed in the footer below.
index.html
<html><body><script>var url = "post.php";var binary;var filename;var mytext;function upload() {filename = document.getElementById(‘myfile‘).value;mytext = document.getElementById(‘mytext‘).value;document.getElementById(‘a(chǎn)jaxbutton‘).disabled = true;// request local file read permissiontry {netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");} catch (e) {alert("Permission to read file was denied.");}// open the local filevar file = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);file.initWithPath( filename );stream = Components.classes["@mozilla.org/network/file-input-stream;1"].createInstance(Components.interfaces.nsIFileInputStream);stream.init(file, 0x01, 00004, null);var bstream = Components.classes["@mozilla.org/network/buffered-input-stream;1"].getService();bstream.QueryInterface(Components.interfaces.nsIBufferedInputStream);bstream.init(stream, 1000);bstream.QueryInterface(Components.interfaces.nsIInputStream);binary = Components.classes["@mozilla.org/binaryinputstream;1"].createInstance(Components.interfaces.nsIBinaryInputStream);binary.setInputStream (stream);// start AJAX file upload in 1 secondwindow.setTimeout("ajax_upload()", 1000);}function ajax_upload() {// request more permissionstry {netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");} catch (e) {alert("Permission to read file was denied.");}http_request = false;http_request = new XMLHttpRequest();if (!http_request) {alert(‘Cannot create XMLHTTP instance‘);return false;}// prepare the MIME POST datavar boundaryString = ‘capitano‘;var boundary = ‘--‘ + boundaryString;var requestbody = boundary + ‘\n‘+ ‘Content-Disposition: form-data; name="mytext"‘ + ‘\n‘+ ‘\n‘+ mytext + ‘\n‘+ ‘\n‘+ boundary + ‘\n‘+ ‘Content-Disposition: form-data; name="myfile"; filename="‘+ filename + ‘"‘ + ‘\n‘+ ‘Content-Type: application/octet-stream‘ + ‘\n‘+ ‘\n‘+ escape(binary.readBytes(binary.available()))+ ‘\n‘+ boundary;document.getElementById(‘sizespan‘).innerHTML ="requestbody.length=" + requestbody.length;// do the AJAX requesthttp_request.onreadystatechange = requestdone;http_request.open(‘POST‘, url, true);http_request.setRequestHeader("Content-type", "multipart/form-data; boundary=\"" + boundaryString + "\"");http_request.setRequestHeader("Connection", "close");http_request.setRequestHeader("Content-length", requestbody.length);http_request.send(requestbody);}function requestdone() {if (http_request.readyState == 4) {if (http_request.status == 200) {result = http_request.responseText;document.getElementById(‘myspan‘).innerHTML = result;} else {alert(‘There was a problem with the request.‘);}document.getElementById(‘a(chǎn)jaxbutton‘).disabled = false;}}</script><form>Text: <input type="text" id="mytext" name="mytext" size="40"><br>File: <input type="file" id="myfile" name="datafile" size="40"><br><input type="button" id="ajaxbutton" value="AJAX IT" onclick="upload();"></form><div id="sizespan"></div><hr><div id="myspan"></div></body></html>___FCKpd___4
Last-Modified: Sat, 04 Feb 2006 16:03:20 GMT
___FCKpd___5FILES{myfile}{tmp_name}, $fpath.
Many people say uploading files with AJAX is impossible! Well, they‘re wrong :-)
Granted this solution only works with FireFox/Mozilla. And the user has to change a setting in "about:config" and accept the advanced access privileges.
Anyway, such an AJAX file upload is only suitable for restricted area stuff, such as Content Management Systems, Group-Ware etc., so users can be briefed before actually using it.
FireFox/Mozilla settings:
Open about:config and check that
signed.applets.codebase_principal_support
is set to "true"
Otherwise Firefox will display something like this
Error: uncaught exception: A script from "http://www.captain.at"was denied UniversalXPConnect privileges.
Also make sure you check the checkbox "Remember this decision", when FireFox will display this message
A script from "http://www.captain.at" is requesting enhanced abilities that areUNSAFE and could be used to compromise your machine or data:Run or install software on your machineAllow these abilities only if you trust this source to be free of viruses or maliciousprograms.[ ] Remember this decision
and click "Allow", otherwise you have to click "Allow" everytime you upload a file.
The example itself is rather straightforward:
We use some Components.classes and Components.interfaces stuff to open the local file from within FireFox/Mozilla - we read the file, construct our request body for the POST request and send the whole data with an AJAX "multipart/form-data" request.
NOTE about encoding the local files:
Since we also want to upload binary files, we need to encode (javascript "escape") the file content. This is basically encoding a string for use in an URL. On the server, after uploading the file we need to decode ("urldecode") the file. "escape" does not encode the plus sign "+", but on the server PHP‘s "urldecode" interprets any "+" and space. So we need an additional preg_replace to replace any "+" to the HEX value "%2B".
This is a little annoying, since escaping large files (up to 1MB it is still fast) with javascript can hang the browser for a few seconds. The problem here is that the AJAX object XMLHttpRequest doesn‘t seem to be able to handle binary data.
ADVANTAGES:
If you upload images and process them on the server, it is common that the server stops the script due too much memory consumption and/or the runtime limit has been exceeded. In such a case PHP is just returning an error message ("Fatal error: memory limit exceeded" or "Fatal error: running too long" or whatever) and the user usually has to back up with the browser back button to repeat the procedure with a smaller image. With AJAX you can check the returned string for errors and if an error has occured, notify the user gracefully.
A possible extension to this example would be:
Let the user select a directory with a custom "directory-browser" or one file in a directory with the regular file-dialog as shown here, then parse the directory automatically for file with a certain extension and upload them in a bulk.
LICENCE: As stated in the policy:
The information provided on the websites of Captain‘s Universe is free for non-commercial, educational use. For commercial use of any of the information provided, contact the owner at the email address listed in the footer below.
index.html
<html><body><script>var url = "post.php";var binary;var filename;var mytext;function upload() {filename = document.getElementById(‘myfile‘).value;mytext = document.getElementById(‘mytext‘).value;document.getElementById(‘a(chǎn)jaxbutton‘).disabled = true;// request local file read permissiontry {netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");} catch (e) {alert("Permission to read file was denied.");}// open the local filevar file = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);file.initWithPath( filename );stream = Components.classes["@mozilla.org/network/file-input-stream;1"].createInstance(Components.interfaces.nsIFileInputStream);stream.init(file, 0x01, 00004, null);var bstream = Components.classes["@mozilla.org/network/buffered-input-stream;1"].getService();bstream.QueryInterface(Components.interfaces.nsIBufferedInputStream);bstream.init(stream, 1000);bstream.QueryInterface(Components.interfaces.nsIInputStream);binary = Components.classes["@mozilla.org/binaryinputstream;1"].createInstance(Components.interfaces.nsIBinaryInputStream);binary.setInputStream (stream);// start AJAX file upload in 1 secondwindow.setTimeout("ajax_upload()", 1000);}function ajax_upload() {// request more permissionstry {netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");} catch (e) {alert("Permission to read file was denied.");}http_request = false;http_request = new XMLHttpRequest();if (!http_request) {alert(‘Cannot create XMLHTTP instance‘);return false;}// prepare the MIME POST datavar boundaryString = ‘capitano‘;var boundary = ‘--‘ + boundaryString;var requestbody = boundary + ‘\n‘+ ‘Content-Disposition: form-data; name="mytext"‘ + ‘\n‘+ ‘\n‘+ mytext + ‘\n‘+ ‘\n‘+ boundary + ‘\n‘+ ‘Content-Disposition: form-data; name="myfile"; filename="‘+ filename + ‘"‘ + ‘\n‘+ ‘Content-Type: application/octet-stream‘ + ‘\n‘+ ‘\n‘+ escape(binary.readBytes(binary.available()))+ ‘\n‘+ boundary;document.getElementById(‘sizespan‘).innerHTML ="requestbody.length=" + requestbody.length;// do the AJAX requesthttp_request.onreadystatechange = requestdone;http_request.open(‘POST‘, url, true);http_request.setRequestHeader("Content-type", "multipart/form-data; boundary=\"" + boundaryString + "\"");http_request.setRequestHeader("Connection", "close");http_request.setRequestHeader("Content-length", requestbody.length);http_request.send(requestbody);}function requestdone() {if (http_request.readyState == 4) {if (http_request.status == 200) {result = http_request.responseText;document.getElementById(‘myspan‘).innerHTML = result;} else {alert(‘There was a problem with the request.‘);}document.getElementById(‘a(chǎn)jaxbutton‘).disabled = false;}}</script><form>Text: <input type="text" id="mytext" name="mytext" size="40"><br>File: <input type="file" id="myfile" name="datafile" size="40"><br><input type="button" id="ajaxbutton" value="AJAX IT" onclick="upload();"></form><div id="sizespan"></div><hr><div id="myspan"></div></body></html>___FCKpd___4
Last-Modified: Sat, 04 Feb 2006 16:03:20 GMT
___FCKpd___5FILES{myfile}{name} ); // convert the uploaded file back to binary // javascript "escape" does not encode the plus sign "+", but "urldecode" // in PHP make a space " ". So replace any "+" in the file with %2B first $filename = $fpath.
Many people say uploading files with AJAX is impossible! Well, they‘re wrong :-)
Granted this solution only works with FireFox/Mozilla. And the user has to change a setting in "about:config" and accept the advanced access privileges.
Anyway, such an AJAX file upload is only suitable for restricted area stuff, such as Content Management Systems, Group-Ware etc., so users can be briefed before actually using it.
FireFox/Mozilla settings:
Open about:config and check that
signed.applets.codebase_principal_support
is set to "true"
Otherwise Firefox will display something like this
Error: uncaught exception: A script from "http://www.captain.at"was denied UniversalXPConnect privileges.
Also make sure you check the checkbox "Remember this decision", when FireFox will display this message
A script from "http://www.captain.at" is requesting enhanced abilities that areUNSAFE and could be used to compromise your machine or data:Run or install software on your machineAllow these abilities only if you trust this source to be free of viruses or maliciousprograms.[ ] Remember this decision
and click "Allow", otherwise you have to click "Allow" everytime you upload a file.
The example itself is rather straightforward:
We use some Components.classes and Components.interfaces stuff to open the local file from within FireFox/Mozilla - we read the file, construct our request body for the POST request and send the whole data with an AJAX "multipart/form-data" request.
NOTE about encoding the local files:
Since we also want to upload binary files, we need to encode (javascript "escape") the file content. This is basically encoding a string for use in an URL. On the server, after uploading the file we need to decode ("urldecode") the file. "escape" does not encode the plus sign "+", but on the server PHP‘s "urldecode" interprets any "+" and space. So we need an additional preg_replace to replace any "+" to the HEX value "%2B".
This is a little annoying, since escaping large files (up to 1MB it is still fast) with javascript can hang the browser for a few seconds. The problem here is that the AJAX object XMLHttpRequest doesn‘t seem to be able to handle binary data.
ADVANTAGES:
If you upload images and process them on the server, it is common that the server stops the script due too much memory consumption and/or the runtime limit has been exceeded. In such a case PHP is just returning an error message ("Fatal error: memory limit exceeded" or "Fatal error: running too long" or whatever) and the user usually has to back up with the browser back button to repeat the procedure with a smaller image. With AJAX you can check the returned string for errors and if an error has occured, notify the user gracefully.
A possible extension to this example would be:
Let the user select a directory with a custom "directory-browser" or one file in a directory with the regular file-dialog as shown here, then parse the directory automatically for file with a certain extension and upload them in a bulk.
LICENCE: As stated in the policy:
The information provided on the websites of Captain‘s Universe is free for non-commercial, educational use. For commercial use of any of the information provided, contact the owner at the email address listed in the footer below.
index.html
<html><body><script>var url = "post.php";var binary;var filename;var mytext;function upload() {filename = document.getElementById(‘myfile‘).value;mytext = document.getElementById(‘mytext‘).value;document.getElementById(‘a(chǎn)jaxbutton‘).disabled = true;// request local file read permissiontry {netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");} catch (e) {alert("Permission to read file was denied.");}// open the local filevar file = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);file.initWithPath( filename );stream = Components.classes["@mozilla.org/network/file-input-stream;1"].createInstance(Components.interfaces.nsIFileInputStream);stream.init(file, 0x01, 00004, null);var bstream = Components.classes["@mozilla.org/network/buffered-input-stream;1"].getService();bstream.QueryInterface(Components.interfaces.nsIBufferedInputStream);bstream.init(stream, 1000);bstream.QueryInterface(Components.interfaces.nsIInputStream);binary = Components.classes["@mozilla.org/binaryinputstream;1"].createInstance(Components.interfaces.nsIBinaryInputStream);binary.setInputStream (stream);// start AJAX file upload in 1 secondwindow.setTimeout("ajax_upload()", 1000);}function ajax_upload() {// request more permissionstry {netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");} catch (e) {alert("Permission to read file was denied.");}http_request = false;http_request = new XMLHttpRequest();if (!http_request) {alert(‘Cannot create XMLHTTP instance‘);return false;}// prepare the MIME POST datavar boundaryString = ‘capitano‘;var boundary = ‘--‘ + boundaryString;var requestbody = boundary + ‘\n‘+ ‘Content-Disposition: form-data; name="mytext"‘ + ‘\n‘+ ‘\n‘+ mytext + ‘\n‘+ ‘\n‘+ boundary + ‘\n‘+ ‘Content-Disposition: form-data; name="myfile"; filename="‘+ filename + ‘"‘ + ‘\n‘+ ‘Content-Type: application/octet-stream‘ + ‘\n‘+ ‘\n‘+ escape(binary.readBytes(binary.available()))+ ‘\n‘+ boundary;document.getElementById(‘sizespan‘).innerHTML ="requestbody.length=" + requestbody.length;// do the AJAX requesthttp_request.onreadystatechange = requestdone;http_request.open(‘POST‘, url, true);http_request.setRequestHeader("Content-type", "multipart/form-data; boundary=\"" + boundaryString + "\"");http_request.setRequestHeader("Connection", "close");http_request.setRequestHeader("Content-length", requestbody.length);http_request.send(requestbody);}function requestdone() {if (http_request.readyState == 4) {if (http_request.status == 200) {result = http_request.responseText;document.getElementById(‘myspan‘).innerHTML = result;} else {alert(‘There was a problem with the request.‘);}document.getElementById(‘a(chǎn)jaxbutton‘).disabled = false;}}</script><form>Text: <input type="text" id="mytext" name="mytext" size="40"><br>File: <input type="file" id="myfile" name="datafile" size="40"><br><input type="button" id="ajaxbutton" value="AJAX IT" onclick="upload();"></form><div id="sizespan"></div><hr><div id="myspan"></div></body></html>___FCKpd___4
Last-Modified: Sat, 04 Feb 2006 16:03:20 GMT
___FCKpd___5FILES{myfile}{name}; $handle = fopen($filename, "r"); $contents = fread($handle, filesize($filename)); fclose($handle); $contents = preg_replace("/\+/", "%2B", $contents); $handle = fopen($filename, "w"); fwrite($handle, urldecode($contents)); fclose($handle); ?>
Last-Modified: Sat, 04 Feb 2006 16:03:20 GMT
___FCKpd___5

