192

I want to implement a simple file upload in my intranet-page, with the smallest setup possible.

This is my HTML part:

<input id="sortpicture" type="file" name="sortpic" />
<button id="upload">Upload</button>

and this is my JS jquery script:

$("#upload").on("click", function() {
    var file_data = $("#sortpicture").prop("files")[0];   
    var form_data = new FormData();
    form_data.append("file", file_data);
    alert(form_data);
    $.ajax({
        url: "/uploads",
        dataType: 'script',
        cache: false,
        contentType: false,
        processData: false,
        data: form_data,                         
        type: 'post',
        success: function(){
            alert("works"); 
        }
    });
});

There is a folder named "uploads" in the root directory of the website, with change permissions for "users" and "IIS_users".

When I select a file with the file-form and press the upload button, the first alert returns "[object FormData]". the second alert doesn't get called and the"uploads" folder is empty too!?

Can someone help my finding out whats wrong?

Also the next step should be, to rename the file with a server side generated name. Maybe someone can give me a solution for this, too.

Basti
  • 606
  • 1
  • 12
  • 22
user2355509
  • 1,973
  • 2
  • 14
  • 11

5 Answers5

329

You need a script that runs on the server to move the file to the uploads directory. The jQuery ajax method (running on the client in the browser) sends the form data to the server, then a script running on the server handles the upload.

Your HTML is fine, but update your JS jQuery script to look like this:

(Look for comments after // <-- )

$('#upload').on('click', function() {
    var file_data = $('#sortpicture').prop('files')[0];   
    var form_data = new FormData();                  
    form_data.append('file', file_data);
    alert(form_data);                             
    $.ajax({
        url: 'upload.php', // <-- point to server-side PHP script 
        dataType: 'text',  // <-- what to expect back from the PHP script, if anything
        cache: false,
        contentType: false,
        processData: false,
        data: form_data,                         
        type: 'post',
        success: function(php_script_response){
            alert(php_script_response); // <-- display response from the PHP script, if any
        }
     });
});

And now for the server-side script, using PHP in this case.

upload.php: a PHP script that is located and runs on the server, and directs the file to the uploads directory:

<?php

    if ( 0 < $_FILES['file']['error'] ) {
        echo 'Error: ' . $_FILES['file']['error'] . '<br>';
    }
    else {
        move_uploaded_file($_FILES['file']['tmp_name'], 'uploads/' . $_FILES['file']['name']);
    }

?>

Also, a couple things about the destination directory:

  1. Make sure you have the correct server path, i.e., starting at the PHP script location what is the path to the uploads directory, and
  2. Make sure it's writeable.

And a little bit about the PHP function move_uploaded_file, used in the upload.php script:

move_uploaded_file(

    // this is where the file is temporarily stored on the server when uploaded
    // do not change this
    $_FILES['file']['tmp_name'],

    // this is where you want to put the file and what you want to name it
    // in this case we are putting in a directory called "uploads"
    // and giving it the original filename
    'uploads/' . $_FILES['file']['name']
);

$_FILES['file']['name'] is the name of the file as it is uploaded. You don't have to use that. You can give the file any name (server filesystem compatible) you want:

move_uploaded_file(
    $_FILES['file']['tmp_name'],
    'uploads/my_new_filename.whatever'
);

And finally, be aware of your PHP upload_max_filesize AND post_max_size configuration values, and be sure your test files do not exceed either. Here's some help how you check PHP configuration and how you set max filesize and post settings.

bloodyKnuckles
  • 11,551
  • 3
  • 29
  • 37
  • hey BloodyKnuckles! thanks, i think this was one big thing, i misunderstood. So i added the php file, and now i am a little closer. The second alert also pops up! but the folder is still empty. – user2355509 Jun 01 '14 at 15:06
  • Ah, the form input name "sortpic" is changed to "file" in the `form_data.append` function. So I changed the PHP script to reflect the new form input name. I also pulled the PHP script response into the ajax success alert to help with debugging. – bloodyKnuckles Jun 01 '14 at 15:21
  • I changed the server path to the uploads directory. I'm assuming it's in the same directory as your PHP upload script, and not at the top level of the computer directory. – bloodyKnuckles Jun 01 '14 at 15:28
  • 1
    Buddy, it give me error undefined index file at `$_FILES['file']` – Hendry Tanaka Oct 10 '14 at 06:57
  • @HendryTanaka, be sure to include the HTML part, shown in the question, and include the jQuery library. – bloodyKnuckles Oct 10 '14 at 15:03
  • may you explain please, prop('files')[0] ? what does this code do? – partho Jul 25 '15 at 12:01
  • 1
    @partho , the code prop('files')[0] accesses the local file intended for upload to the server. If you need more explanation look up jQuery function "prop" and "html5 file upload". – bloodyKnuckles Jul 26 '15 at 12:49
  • I tried this code but its not working or am I missing the right jquery library to run this code? – Rayden Black Dec 16 '15 at 02:24
  • PHP is returning error: 1. I changed "sortpic" to "file2upload" in the HTML and the $uploaddir to my upload path A var_dump($_FILES) shows the correct filename, but there is no "tmp_name" (length=0). What am I missing? – ron tornambe May 21 '16 at 17:50
  • 1
    I resolved this issue.The reason for it was the filesize was too large. – ron tornambe May 21 '16 at 17:58
  • You may need [a FormData shiv](https://github.com/francois2metz/html5-formdata) for some older browsers. – Volomike Aug 12 '16 at 00:21
  • 1
    I'm currently trying this solution for my current project. I'm only getting the first alert and it shows a message [object FormData]. I followed everything mentioned. In my directory I have an index.html, upload.php and uploads folder – clestcruz Jan 18 '17 at 10:52
  • when i trying to above case like `$("#qdocument").prop('files')[0]` i got this `Uncaught TypeError: Cannot read property '0' of null` error in console – Balakumar B Dec 21 '17 at 07:47
  • @BalakumarB Check the element with id "qdocument", is it type "file"? `` – bloodyKnuckles Dec 22 '17 at 17:50
  • how to fix ".prop('files')[0]; jquery prop is not a function" ?? pls help – shin Mar 27 '18 at 02:06
  • @nej What is the `prop` method attached to? What do you get when you console.log that? For example, in my answer I would `console.log($('#sortpicture'))`. – bloodyKnuckles Mar 27 '18 at 15:14
  • is there any working solution for android devices via mobile chrome browser? – hillcode Dec 18 '19 at 09:59
  • i get this error `TypeError: 'append' called on an object that does not implement interface FormData.` – Mostafa Jul 08 '20 at 09:09
  • 3
    Also..dont we need use `event.preventDefault()` ? – Mostafa Jul 08 '20 at 09:11
  • 1
    this has to be the best answer on SO – skull Oct 04 '21 at 10:09
13
**1. index.php**
<body>
    <span id="msg" style="color:red"></span><br/>
    <input type="file" id="photo"><br/>
  <script type="text/javascript" src="jquery-3.2.1.min.js"></script>
  <script type="text/javascript">
    $(document).ready(function(){
      $(document).on('change','#photo',function(){
        var property = document.getElementById('photo').files[0];
        var image_name = property.name;
        var image_extension = image_name.split('.').pop().toLowerCase();

        if(jQuery.inArray(image_extension,['gif','jpg','jpeg','']) == -1){
          alert("Invalid image file");
        }

        var form_data = new FormData();
        form_data.append("file",property);
        $.ajax({
          url:'upload.php',
          method:'POST',
          data:form_data,
          contentType:false,
          cache:false,
          processData:false,
          beforeSend:function(){
            $('#msg').html('Loading......');
          },
          success:function(data){
            console.log(data);
            $('#msg').html(data);
          }
        });
      });
    });
  </script>
</body>

**2.upload.php**
<?php
if($_FILES['file']['name'] != ''){
    $test = explode('.', $_FILES['file']['name']);
    $extension = end($test);    
    $name = rand(100,999).'.'.$extension;

    $location = 'uploads/'.$name;
    move_uploaded_file($_FILES['file']['tmp_name'], $location);

    echo '<img src="'.$location.'" height="100" width="100" />';
}
Hasib Kamal Chowdhury
  • 2,476
  • 26
  • 28
5

Use pure js

async function saveFile() 
{
    let formData = new FormData();           
    formData.append("file", sortpicture.files[0]);
    await fetch('/uploads', {method: "POST", body: formData});    
    alert('works');
}
<input id="sortpicture" type="file" name="sortpic" />
<button id="upload" onclick="saveFile()">Upload</button>
<br>Before click upload look on chrome>console>network (in this snipped we will see 404)

The filename is automatically included to request and server can read it, the 'content-type' is automatically set to 'multipart/form-data'. Here is more developed example with error handling and additional json sending

async function saveFile(inp) 
{
    let user = { name:'john', age:34 };
    let formData = new FormData();
    let photo = inp.files[0];      
         
    formData.append("photo", photo);
    formData.append("user", JSON.stringify(user));  
    
    try {
       let r = await fetch('/upload/image', {method: "POST", body: formData}); 
       console.log('HTTP response code:',r.status); 
       alert('success');
    } catch(e) {
       console.log('Huston we have problem...:', e);
    }
    
}
<input type="file" onchange="saveFile(this)" >
<br><br>
Before selecting the file Open chrome console > network tab to see the request details.
<br><br>
<small>Because in this example we send request to https://stacksnippets.net/upload/image the response code will be 404 ofcourse...</small>
Kamil Kiełczewski
  • 85,173
  • 29
  • 368
  • 345
4
var formData = new FormData($("#YOUR_FORM_ID")[0]);
$.ajax({
    url: "upload.php",
    type: "POST",
    data : formData,
    processData: false,
    contentType: false,
    beforeSend: function() {

    },
    success: function(data){




    },
    error: function(xhr, ajaxOptions, thrownError) {
       console.log(thrownError + "\r\n" + xhr.statusText + "\r\n" + xhr.responseText);
    }
});
Azhar
  • 101
  • 2
  • 7
1

and this is the php file to receive the uplaoded files

<?
$data = array();
    //check with your logic
    if (isset($_FILES)) {
        $error = false;
        $files = array();

        $uploaddir = $target_dir;
        foreach ($_FILES as $file) {
            if (move_uploaded_file($file['tmp_name'], $uploaddir . basename( $file['name']))) {
                $files[] = $uploaddir . $file['name'];
            } else {
                $error = true;
            }
        }
        $data = ($error) ? array('error' => 'There was an error uploading your files') : array('files' => $files);
    } else {
        $data = array('success' => 'NO FILES ARE SENT','formData' => $_REQUEST);
    }

    echo json_encode($data);
?>
Mr.Web
  • 6,992
  • 8
  • 51
  • 86
kavehmb
  • 9,822
  • 1
  • 19
  • 22