Page 1 of 1

Trying to use jQuery 1.4.x: AJAX file upload w/ $_FILES...?

Posted: Mon Sep 08, 2014 2:48 pm
by Wolf_22
Problem:
I've created an AJAX file upload that works wonderfully with jQuery 1.11.x but when I switch over to a local version of jQuery 1.4.x (a version I'm forced to use in production), I begin to have issues with getting PHP to acknowledge the uploaded file details.

With jQuery 1.11.x, I can see var_dump($_FILES) output as expected and it's beautiful! :)

...but with jQuery 1.4.x, I cannot and it's giving me a serious headache. Instead, the AJAX post occurs as expected per-Firebug's POST details but the RESPONSE details show only the markup I started with. Nothing new or changed.

Code (you should be able to copy-and-paste-and-run as-is):

Code: Select all

<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <title>Ajax Upload Test</title>
    </head>
    <body>
        <div id="wrapper">
            <div id="header"></div>
            <div id="left"></div>
            <div id="right">
				<form method="post" enctype="multipart/form-data">
					<input id="file" type="file" name="file"/>
				</form>
                <div id="response">
                <?php
                    print '<pre>';
                    var_dump($_FILES);
                    print '</pre>';
                ?>
                </div>
            </div>
            <div id="footer"></div>
        </div>
        <script type="text/javascript" src="http://code.jquery.com/jquery-1.11.1.min.js"></script>
		<!--<script type="text/javascript" src="jquery_1.4.4.js"></script>-->
        <script type="text/javascript">
			var input = $("#file");
			var formdata = false;

			if(window.FormData){
				formdata = new FormData();
			}

			input.bind("change", function (evt) {
				var i = 0, len = this.files.length, reader, file;

				for(;i<len;i++){
					file = this.files[i];

					//if (!!file.type.match(/image.*/)){
					if (!!file.type.match(/text.*/)){
						if ( window.FileReader ) {
							reader = new FileReader();
							reader.onloadend = function(e){};
							reader.readAsDataURL(file);
						}

						if(formdata){
							formdata.append("text", file);
							formdata.append("extra",'extra-data');
						}

						if(formdata){
							//jQuery('div#response').html('<br /><img src="ajax-loader.gif"/>');
							jQuery.ajax({
								url: "index.php",
								type: "POST",
								data: formdata,
								processData: false,
								contentType: false,
								success: function (res) {
									console.log(res);
									$('#response').empty();
									$('#response').html($(res).find('#response').html());
								}
							});
						}

					}else{
						alert('Not a vaild file type.');
					}
				}
				evt.preventDefault();
			});
		</script>
    </body>
</html>
Conclusion:
It's as if the PHP isn't able to grab / acquire / acknowledge the file payload and so when I try to use var_dump($_FILES), it just keeps coming up as an empty PHP array (which implies that either PHP isn't seeing the details or else my AJAX is inadvertently refreshing the DIV with a brand new index.php request, absent of the initial AJAX call details). Does that sound right?

Any insight into this would be very appreciated. It's really got me banging my head.

Re: Trying to use jQuery 1.4.x: AJAX file upload w/ $_FILES.

Posted: Mon Sep 08, 2014 5:41 pm
by requinix
You may need to specify the contentType (multipart/form-data).

Is the file showing up in $_POST?
What did Firebug show for the request?

Re: Trying to use jQuery 1.4.x: AJAX file upload w/ $_FILES.

Posted: Mon Sep 08, 2014 7:05 pm
by Wolf_22
You may need to specify the contentType (multipart/form-data).
If you're implying that having it in the form element isn't enough, I went ahead and added it in the jQuery.ajax() properties, too, as follows:
[syntax]contentType: 'multipart/form-data',[/syntax]

...and I get the same results back in Firefox: Firebug reports a successful 200 return code upon post but the response only returns the original index.php markup. (In other words, since I initiate .ajax() from index.php, I get that same page back--despite appearing to successfully deliver the post payload.
Is the file showing up in $_POST?
No, it isn't. Every time I initialize the ajax function, all I ever get back is just the original index.php page--nothing else. The arrays ($_POST and $_FILES) always return an empty array.
What did Firebug show for the request?
Here's the Response Headers being sent:
[syntax]HTTP/1.1 200 OK
Date: Mon, 08 Sep 2014 23:54:45 GMT
Server: Apache/2.2.22 (Win32) mod_ssl/2.2.22 OpenSSL/0.9.8k PHP/5.2.9-2
X-Powered-By: PHP/5.2.9-2
Content-Length: 3874
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: text/html
X-Pad: avoid browser bug[/syntax]

...and the Response Headers:
[syntax]POST /projects/ajax_file_upload/index.php HTTP/1.1
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:31.0) Gecko/20100101 Firefox/31.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: false
X-Requested-With: XMLHttpRequest
Content-Length: 293
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache[/syntax]

Firebug shows the test.txt file being submitted successfully (I see a 200 OK in the "Status" column). I also see the file being sent:
[syntax]-----------------------------12435295776740
Content-Disposition: form-data; name="text";
filename="test.txt" Content-Type: text/plain

-----------------------------12435295776740
Content-Disposition: form-data;
name="extra" extra-data
-----------------------------12435295776740--[/syntax]

...which is what I saw when I used the latest jQuery--which worked. The response that is returned is just the original index.php markup / page, with nothing showing up where I have var_dump($_POST) or var_dump($_FILES) (they still show array(0), etc.

Re: Trying to use jQuery 1.4.x: AJAX file upload w/ $_FILES.

Posted: Mon Sep 08, 2014 9:35 pm
by requinix
In the request headers there's

Code: Select all

Content-Type: false 
That could easily be the problem. Are those headers from the new code with that contentType change? If not, what does it all look like with the change?

Re: Trying to use jQuery 1.4.x: AJAX file upload w/ $_FILES.

Posted: Mon Sep 08, 2014 9:52 pm
by Celauran
jQuery.ajax was completely re-written in 1.5. 1.5 is exactly where this code starts working. 1.4.4 fails, 1.5 through 1.11.1 works fine. As requinix pointed out, 1.4.x sets the content-type to "false" whereas later versions, with contentType:false, the actual request header contains "multipart/form-data; boundary=whatever".

Re: Trying to use jQuery 1.4.x: AJAX file upload w/ $_FILES.

Posted: Mon Sep 08, 2014 11:34 pm
by Wolf_22
requinix wrote:In the request headers there's

Code: Select all

Content-Type: false 
That could easily be the problem. Are those headers from the new code with that contentType change? If not, what does it all look like with the change?
I changed the code to be the following:

Code: Select all

<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <title>Ajax Upload Test</title>
    </head>
    <body>
        <div id="wrapper">
            <div id="header"></div>
            <div id="left"></div>
            <div id="right">
                                <form method="post" enctype="multipart/form-data">
                                        <input id="file" type="file" name="file"/>
                                </form>
                <div id="response">
                <?php
                    print '<pre>';
                    var_dump($_FILES);
                    print '</pre>';
                ?>
                </div>
            </div>
            <div id="footer"></div>
        </div>
        <script type="text/javascript" src="jquery_1.4.4.js"></script>
        <script type="text/javascript">
                        var input = $("#file");
                        var formdata = false;

                        if(window.FormData){
                                formdata = new FormData();
                        }

                        input.bind("change", function (evt) {
                                var i = 0, len = this.files.length, reader, file;

                                for(;i<len;i++){
                                        file = this.files[i];

                                        //if (!!file.type.match(/image.*/)){
                                        if (!!file.type.match(/text.*/)){
                                                if ( window.FileReader ) {
                                                        reader = new FileReader();
                                                        reader.onloadend = function(e){};
                                                        reader.readAsDataURL(file);
                                                }

                                                if(formdata){
                                                        formdata.append("text", file);
                                                        formdata.append("extra",'extra-data');
                                                }

                                                if(formdata){
                                                        //jQuery('div#response').html('<br /><img src="ajax-loader.gif"/>');
                                                        jQuery.ajax({
                                                                url: "index.php",
                                                                type: "POST",
                                                                data: formdata,
                                                                processData: false,
                                                                contentType: "multipart/form-data",
                                                                success: function (res) {
                                                                        console.log(res);
                                                                        $('#response').empty();
                                                                        $('#response').html($(res).find('#response').html());
                                                                }
                                                        });
                                                }

                                        }else{
                                                alert('Not a vaild file type.');
                                        }
                                }
                                evt.preventDefault();
                        });
                </script>
    </body>
</html>
The Firebug Post details are as follows:
-----------------------------118961866025156
Content-Disposition: form-data; name="text"; filename="test.txt"
Content-Type: text/plain

-----------------------------118961866025156
Content-Disposition: form-data; name="extra"

extra-data
-----------------------------118961866025156--
The Firebug Response details are as follows:

Code: Select all

<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <title>Ajax Upload Test</title>
    </head>
    <body>
        <div id="wrapper">
            <div id="header"></div>
            <div id="left"></div>
            <div id="right">
                                <form method="post" enctype="multipart/form-data">
                                        <input id="file" type="file" name="file"/>
                                </form>
                <div id="response">
                <pre>array(0) {
}
</pre>                </div>
            </div>
            <div id="footer"></div>
        </div>
        <script type="text/javascript" src="jquery_1.4.4.js"></script>
        <script type="text/javascript">
                        var input = $("#file");
                        var formdata = false;

                        if(window.FormData){
                                formdata = new FormData();
                        }

                        input.bind("change", function (evt) {
                                var i = 0, len = this.files.length, reader, file;

                                for(;i<len;i++){
                                        file = this.files[i];

                                        //if (!!file.type.match(/image.*/)){
                                        if (!!file.type.match(/text.*/)){
                                                if ( window.FileReader ) {
                                                        reader = new FileReader();
                                                        reader.onloadend = function(e){};
                                                        reader.readAsDataURL(file);
                                                }

                                                if(formdata){
                                                        formdata.append("text", file);
                                                        formdata.append("extra",'extra-data');
                                                }

                                                if(formdata){
                                                        //jQuery('div#response').html('<br /><img src="ajax-loader.gif"/>');
                                                        jQuery.ajax({
																traditional: true,
																cache: false,
                                                                url: "index.php",
                                                                type: "POST",
                                                                data: formdata,
                                                                processData: false,
                                                                contentType: "multipart/form-data",

                                                                success: function (res) {
                                                                        console.log(res);
                                                                        $('#response').empty();
                                                                        $('#response').html($(res).find('#response').html());
                                                                }
                                                        });
                                                }

                                        }else{
                                                alert('Not a vaild file type.');
                                        }
                                }
                                evt.preventDefault();
                        });
                </script>
    </body>
</html>
(Basically the original index.php file I started with.)

The Request Headers:
POST /projects/ajax_file_upload/index.php HTTP/1.1
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:31.0) Gecko/20100101 Firefox/31.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: multipart/form-data
X-Requested-With: XMLHttpRequest
Content-Length: 296
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
The Response Headers:
HTTP/1.1 200 OK
Date: Tue, 09 Sep 2014 04:18:21 GMT
Server: Apache/2.2.22 (Win32) mod_ssl/2.2.22 OpenSSL/0.9.8k PHP/5.2.9-2
X-Powered-By: PHP/5.2.9-2
Content-Length: 4037
Keep-Alive: timeout=5, max=99
Connection: Keep-Alive
Content-Type: text/html
X-Pad: avoid browser bug
Side Note:
I was able to get *some* content back using var_dump(file_get_contents('php://input')) at the top of the page before the opening HTML tag (which I didn't include in the code snippet above because I didn't think it was what I wanted) but in so doing, I retrieved the following (only visible in Firebug's NET panel--I couldn't see it in the final markup after my POST was executed):
-----------------------------305083071515052
Content-Disposition: form-data; name="text"; filename="test.txt"
Content-Type: text/plain
-----------------------------305083071515052
Content-Disposition: form-data; name="extra"
extra-data
-----------------------------305083071515052--
That's not what I'm hoping for though because $_FILES is always empty... Any thoughts?

Re: Trying to use jQuery 1.4.x: AJAX file upload w/ $_FILES.

Posted: Tue Sep 09, 2014 6:36 am
by Celauran
You're missing the boundary in your content-type request header.

Re: Trying to use jQuery 1.4.x: AJAX file upload w/ $_FILES.

Posted: Tue Sep 09, 2014 11:32 am
by Wolf_22
Celauran wrote:You're missing the boundary in your content-type request header.
Ah, you mean the "whatever", right? Well, I added it (current code):

Code: Select all

<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <title>Ajax Upload Test</title>
    </head>
    <body>
        <div id="wrapper">
            <div id="header"></div>
            <div id="left"></div>
            <div id="right">
				<form method="post" enctype="multipart/form-data">
					<input id="file" type="file" name="file"/>
				</form>
                <div id="response">
					<?php 
						print '<pre>';
						var_dump($_FILES);
						print '</pre>';
					?>
				</div>
            </div>
            <div id="footer"></div>
        </div>
        <script type="text/javascript" src="jquery_1.4.4.js"></script>
        <script type="text/javascript">
                        var input = $("#file");
                        var formdata = false;

                        if(window.FormData){
                                formdata = new FormData();
                        }

                        input.bind("change", function (evt) {
                                var i = 0, len = this.files.length, reader, file;

                                for(;i<len;i++){
                                        file = this.files[i];

                                        //if (!!file.type.match(/image.*/)){
                                        if (!!file.type.match(/text.*/)){
                                                if ( window.FileReader ) {
                                                        reader = new FileReader();
                                                        reader.onloadend = function(e){};
                                                        reader.readAsDataURL(file);
                                                }

                                                if(formdata){
                                                        formdata.append("text", file);
                                                        formdata.append("extra",'extra-data');
                                                }

                                                if(formdata){
                                                        //jQuery('div#response').html('<br /><img src="ajax-loader.gif"/>');
                                                        jQuery.ajax({
																traditional: true,
																cache: false,
                                                                url: "index.php",
                                                                type: "POST",
                                                                data: formdata,
                                                                processData: false,
                                                                contentType: "multipart/form-data; boundary=whatever",

                                                                success: function (res) {
                                                                        console.log(res);
                                                                        $('#response').empty();
                                                                        $('#response').html($(res).find('#response').html());
                                                                }
                                                        });
                                                }

                                        }else{
                                                alert('Not a vaild file type.');
                                        }
                                }
                                evt.preventDefault();
                        });
                </script>
    </body>
</html>
So with that added, I executed the ajax() call and received the following results:

Firebug Post Details:
-----------------------------1015285086226
Content-Disposition: form-data; name="text"; filename="test.txt"
Content-Type: text/plain

-----------------------------1015285086226
Content-Disposition: form-data; name="extra"

extra-data
-----------------------------1015285086226--
Firebug Response Details:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Ajax Upload Test</title>
</head>
<body>
<div id="wrapper">
<div id="header"></div>
<div id="left"></div>
<div id="right">
<form method="post" enctype="multipart/form-data">
<input id="file" type="file" name="file"/>
</form>
<div id="response">
<pre>array(0) {
}
</pre> </div>
</div>
<div id="footer"></div>
</div>
<script type="text/javascript" src="jquery_1.4.4.js"></script>
<script type="text/javascript">
var input = $("#file");
var formdata = false;

if(window.FormData){
formdata = new FormData();
}

input.bind("change", function (evt) {
var i = 0, len = this.files.length, reader, file;

for(;i<len;i++){
file = this.files;

//if (!!file.type.match(/image.*/)){
if (!!file.type.match(/text.*/)){
if ( window.FileReader ) {
reader = new FileReader();
reader.onloadend = function(e){};
reader.readAsDataURL(file);
}

if(formdata){
formdata.append("text", file);
formdata.append("extra",'extra-data');
}

if(formdata){
//jQuery('div#response').html('<br /><img src="ajax-loader.gif"/>');
jQuery.ajax({
traditional: true,
cache: false,
url: "index.php",
type: "POST",
data: formdata,
processData: false,
contentType: "multipart/form-data; boundary=whatever",

success: function (res) {
console.log(res);
$('#response').empty();
$('#response').html($(res).find('#response').html());
}
});
}

}else{
alert('Not a vaild file type.');
}
}
evt.preventDefault();
});
</script>
</body>
</html>


Request Headers:
POST /practice/jquery/index.php HTTP/1.1
User-Agent: Mozilla/5.0 (Windows NT 6.1; rv:31.0) Gecko/20100101 Firefox/31.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: multipart/form-data; boundary=whatever
X-Requested-With: XMLHttpRequest
Content-Length: 290
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache


Response Headers:
HTTP/1.1 200 OK
Date: Tue, 09 Sep 2014 16:21:36 GMT
Server: Apache/2.2.22 (Win32) PHP/5.3.13
X-Powered-By: PHP/5.3.13
Content-Length: 3844
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: text/html


...still nothing in $_FILES but if you guys are right, it's likely because the boundary isn't being added. Am I going about adding it incorrectly? How do I add the boundary???