0

I'm trying to upload files to a remote server using javascript, with PHP as the back end. The javascript works fine, but at the PHP end $_FILES and $_POST are blank. However, $_SERVER does show a lot of data. I'm trying to move the file to a users directory but cannot find it's temp path. How do I do this?

PHP

<?php
print_r($_FILES); // empty array
print_r($_POST); // empty array

echo "Name: " . $_SERVER['HTTP_X_FILE_NAME'] . "<br />"; // shows file name
echo "Type: " . $_SERVER['HTTP_X_FILE_TYPE'] . "<br />"; // shows file type
echo "File: " . $_FILES['file1']['tmp_name'] . "<br />"; // throws array

print_r($_SERVER);
?>

Notice:  Undefined index: file1 in /*/*/upload.php on line 11
Notice:  Trying to access array offset on value of type null in /*/*/upload.php on line 11

print_r($_SERVER);
Array
(
    [HTTP_HOST] => *.com
    [CONTENT_LENGTH] => 236881
    [HTTP_DNT] => 1
    [HTTP_X_FILE_TYPE] => image/jpeg
    [HTTP_X_FILE_NAME] => Image00001.jpg
    [HTTP_USER_AGENT] => Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.135 Safari/537.36
    [CONTENT_TYPE] => image/jpeg
    [HTTP_ACCEPT] => */*
    [HTTP_ORIGIN] => *.com
    [HTTP_REFERER] => *.com
    [HTTP_ACCEPT_ENCODING] => gzip, deflate
    [HTTP_ACCEPT_LANGUAGE] => en-US,en;q=0.9,kn;q=0.8
    [HTTP_COOKIE] => 
    [PATH] => /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin
    [SERVER_SIGNATURE] => 
    [SERVER_SOFTWARE] => Apache
    [SERVER_NAME] => *.com
    [SERVER_ADDR] => *
    [SERVER_PORT] => 80
    [REMOTE_ADDR] => *
    [DOCUMENT_ROOT] => */public_html
    [REQUEST_SCHEME] => http
    [CONTEXT_PREFIX] => 
    [CONTEXT_DOCUMENT_ROOT] => */public_html
    [SERVER_ADMIN] => webmaster@localhost
    [SCRIPT_FILENAME] => */upload.php
    [REMOTE_PORT] => 17770
    [GATEWAY_INTERFACE] => CGI/1.1
    [SERVER_PROTOCOL] => HTTP/1.1
    [REQUEST_METHOD] => POST
    [QUERY_STRING] => 
    [REQUEST_URI] => */upload.php
    [SCRIPT_NAME] => */upload.php
    [PHP_SELF] => */upload.php
    [REQUEST_TIME_FLOAT] => 1598508354.225
    [REQUEST_TIME] => 1598508354
)

<form id="upload_form">
  <input type="file" name="file1" id="file1"><br>
  <input type="button" value="Upload File" onclick="uploadFile()">
  <progress id="progressBar" value="0" max="100" style="width:300px;"></progress>
  <pre id="status"></pre>
  <p id="loaded_n_total"></p>
</form>

function uploadFile(){
    var file = _("file1").files[0];
    var ajax = new XMLHttpRequest();
    ajax.open("POST", "upload.php",true);
    ajax.setRequestHeader("X-File-Type", file.type);
    ajax.setRequestHeader("X-File-Name", file.name);
    ajax.send(file);
    console.log(ajax.response);
}
ADyson
  • 57,178
  • 14
  • 51
  • 63
Norman
  • 6,159
  • 23
  • 88
  • 141
  • 1
    Your form has the wrong (none) encType – Honk der Hase Aug 27 '20 at 06:23
  • @LarsStegelitz I changed it to `enctype="multipart/form-data"` and the results are still the same... – Norman Aug 27 '20 at 06:26
  • 1
    Still trying to avoid using FormData at any cost? https://stackoverflow.com/a/63591720/1427878 Then you would at least have to set the necessary request headers yourself, I think, I doubt XMLHttpRequest will add those on its own. – CBroe Aug 27 '20 at 06:26
  • Are you really still trying to support IE9?? – ADyson Aug 27 '20 at 06:28
  • 1
    Also, I don’t see what parameter name the file should even be send with here, when you just do `ajax.send(file);`. You are already sending those X-File-Something headers, for a reason I guess - but I doubt PHP will care about those, when it comes to parsing the request. – CBroe Aug 27 '20 at 06:28
  • What more headers do I need to set? – Norman Aug 27 '20 at 06:30
  • If you're really insistent on this then have you tried this workaround? https://stackoverflow.com/a/27595473/5947043 . P.s. Personally I'd be just making the code fall back to a standard postback for ancient browser users, rather than expending all this energy to support tech that barely anyone uses any more – ADyson Aug 27 '20 at 07:04
  • I notice the `progress` element but no code to hook into that. If the progress meter is not needed you might find that `Fetch` and `FormData` are far simpler to work with - the only issue is there is no way (afaik) to reliably monitor upload progress when using `Fetch` – Professor Abronsius Aug 27 '20 at 10:34
  • @ProfessorAbronsius I took that out for this question. Otherwise, the rest of the code is from this example http://www.developphp.com/video/JavaScript/File-Upload-Progress-Bar-Meter-Tutorial-Ajax-PHP – Norman Aug 27 '20 at 10:46
  • This backs up what I was saying earlier: https://stackoverflow.com/a/9395980/5947043 . You're trying to do something which isn't really possible. Either use the iframe workaround I suggested, or fall back to regular postbacks for ancient browsers, or just forget about supporting ancient browsers altogether because most likely no-one is using them anyway. And this one as well has the same info: https://stackoverflow.com/a/13497736/5947043 . TBH it was quite easy to find once I started searching...have you not found this info and come to this conclusion yourself yet already? I'm surprised. – ADyson Aug 27 '20 at 12:19

1 Answers1

1

File uploads happens via the content type multipart/form-data. This is what PHP $_FILEs array population would be triggered by. You have to set it in your form.

<form id="upload_form" method="post" enctype="multipart/form-data">

When the file upload is happening via ajax, you will have to set the content-type header.

ajax.setRequestHeader("content-type", "multipart/form-data");
Charlie
  • 22,886
  • 11
  • 59
  • 90