154

I would like to simply limit the size of a file that a user can upload.

I thought maxlength = 20000 = 20k but that doesn't seem to work at all.

I am running on Rails, not PHP, but was thinking it'd be much simpler to do it client side in the HTML/CSS, or as a last resort using jQuery. This is so basic though that there must be some HTML tag I am missing or not aware of.

Looking to support IE7+, Chrome, FF3.6+. I suppose I could get away with just supporting IE8+ if necessary.

Thanks.

Sebastian B.
  • 2,141
  • 13
  • 21
delphi
  • 10,705
  • 5
  • 22
  • 18
  • 2
    It is possible. Please refer [this](http://stackoverflow.com/questions/3717793/javascript-file-upload-size-validation) question. – sandSK Jun 16 '14 at 05:01

10 Answers10

190
var uploadField = document.getElementById("file");

uploadField.onchange = function() {
    if(this.files[0].size > 2097152){
       alert("File is too big!");
       this.value = "";
    };
};

This example should work fine. I set it up for roughly 2MB, 1MB in Bytes is 1,048,576 so you can multiply it by the limit you need.

Here is the jsfiddle example for more clearence:
https://jsfiddle.net/7bjfr/808/

Haseeb Rehman
  • 1,929
  • 1
  • 8
  • 13
  • 47
    @AkshayAnurag client side validation prevent wasting time of the client and bandwidth of the server,its not about security its about the UX – Arash Nov 02 '19 at 21:13
  • 35
    @AkshayAnurag you can only check image size on backend after the whole image is uploaded and if that is a huge image, lets say 16mb and client have a slow connection than user will have to wait the whole time the image is uploading just to get an error at the end. To prevent something like that you need some sort of validation on front-end. Please do let me know if I am wrong or missing something or maybe you have something to prevent this? – Haseeb Rehman Nov 04 '19 at 13:14
  • 13
    @AkshayAnurag If "_there are better ways of doing it_", you should post your own answer. – Monday Fatigue Sep 07 '21 at 10:31
  • Unnecessary semicolon after brace: `};` – Anton Duzenko Aug 10 '23 at 10:39
137

This is completely possible. Use Javascript.

I use jQuery to select the input element. I have it set up with an onChange event.

$("#aFile_upload").on("change", function (e) {

    var count=1;
    var files = e.currentTarget.files; // puts all files into an array

    // call them as such; files[0].size will get you the file size of the 0th file
    for (var x in files) {
    
        var filesize = ((files[x].size/1024)/1024).toFixed(4); // MB
    
        if (files[x].name != "item" && typeof files[x].name != "undefined" && filesize <= 10) { 

            if (count > 1) {
                
                approvedHTML += ", "+files[x].name;
            }
            else {
            
                approvedHTML += files[x].name;
            }

            count++;
        }
    }
    $("#approvedFiles").val(approvedHTML);

});

The code above saves all the file names that I deem worthy of persisting to the submission page before the submission actually happens. I add the "approved" files to an input element's val using jQuery so a form submit will send the names of the files I want to save. All the files will be submitted, however, now on the server-side, we do have to filter these out. I haven't written any code for that yet but use your imagination. I assume one can accomplish this by a for loop and matching the names sent over from the input field and matching them to the $_FILES (PHP Superglobal, sorry I don't know ruby file variable) variable.

My point is you can do checks for files before submission. I do this and then output it to the user before he/she submits the form, to let them know what they are uploading to my site. Anything that doesn't meet the criteria does not get displayed back to the user and therefore they should know, that the files that are too large won't be saved. This should work on all browsers because I'm not using the FormData object.

Saeed Zhiany
  • 2,051
  • 9
  • 30
  • 41
mark.inman
  • 2,521
  • 2
  • 18
  • 12
  • 58
    You can't do it client side and expect it to always work. If it is important check on the server side too, else people will use modified copies of the form (or other client side means) to upload oversize files. Server side checks are like a lock, client side checks are like a post-it note that says "keep out". Lock the door first, then put up the "keep out" sign. – user340140 Oct 09 '13 at 02:49
  • 2
    @user340140 As long as the client supports javascript you can. If the client doesn't just simply state that the site requires javascript to be enabled. Javascript has a file reader that essentially cant be tricked, it reads bit by bit so there is no worry about receiving a small file that is secretly another size. Server side is the preferred "secure" method, but i don't see how javascript isn't just as secure when talking about file size. – mark.inman Oct 21 '13 at 17:38
  • 8
    Because like user340140 said Javascript can be easily modified whatever you do. You can do this on top of the server side check for usability, but you can't secure it with client side Javascript. – Sinan Samet Mar 28 '14 at 11:04
  • 3
    While the server side should always do final validation, doing it on the client side as well will limit the number of bad uploads from anyone not looking to bypass the checks and having Javascript enabled - this will generally represent the vast number of users, if you are implementing both user facing and server portions. – Andre M Jun 25 '21 at 12:49
  • @mark.inman the reason javascript isn't as secure as checking server side is because the end user is able to see and modify the javascript with their own. Try this - create a html element like this now open up the html file you created in a browser like chrome and right click on the text box input and click "Inspect"... Using the inspector double click on the "onchange" attribute and alter it to read onchange="alert('Please change me');" - change the text in the input box what happens? oops! – TheKLF99 Dec 21 '21 at 07:30
  • @mark.inman that example above is only a basic example how someone inspecting the site through Chrome's debugger (Edge, Firefox and Safari also all have their own debuggers) can circumvent your Javascript quite easily and why it shouldn't be fully trusted. – TheKLF99 Dec 21 '21 at 07:34
31

You can't do it client-side. You'll have to do it on the server.

Edit: This answer is outdated!

When I originally answered this question in 2011, HTML File API was nothing but a draft. It is now supported on all major browsers.

I'd provide an update with solution, but @mark.inman.winning has already answered better than I could.

Keep in mind that even if it's now possible to validate on the client, you should still validate it on the server, though. All client side validations can be bypassed.

Ortiga
  • 8,455
  • 5
  • 42
  • 71
  • 3
    See: http://www.cs.tut.fi/~jkorpela/forms/file.html, "Setting restrictions on the file size", on why trying to do it client-side is pointless. – magma Apr 18 '11 at 01:17
  • You don't have access to the local file system on a visitors computer, the best you can hope for is to have apache limit the file size and stop the upload if it is too large. – Brent Friar Apr 18 '11 at 01:18
  • It's stupid to do it on the client side - unless you just want to make it convenient for the user. "You must validate server side. You may validate client side." – d-_-b Apr 18 '11 at 01:19
  • See: http://swfupload.org/ if you really want to implement a Flash (.swf) solution in 2011. It says it supports file size checking. I wouldn't do that, but. – magma Apr 18 '11 at 01:21
  • 3
    Interesting...this seems to work: http://www.plupload.com/. The only problem is that IE8 without flash, silverlight, gears, etc plugins will default to HTML4 it seems. – delphi Apr 19 '11 at 01:06
17

const input = document.getElementById('input')

input.addEventListener('change', (event) => {
  const target = event.target
   if (target.files && target.files[0]) {

      /*Maximum allowed size in bytes
        5MB Example
        Change first operand(multiplier) for your needs*/
      const maxAllowedSize = 5 * 1024 * 1024;
      if (target.files[0].size > maxAllowedSize) {
       // Here you can ask your users to load correct file
        target.value = ''
      }
  }
})
<input type="file" id="input" />

If you need to validate file type, write in comments below and I'll share my solution.

(Spoiler: accept attribute is not bulletproof solution)

user229044
  • 232,980
  • 40
  • 330
  • 338
Yury Lavrukhin
  • 209
  • 2
  • 3
  • 2
    The browser can inform the user that the file limit has been exceeded by using target.setCustomValidity('Exceeds file size of 5mb'); target.reportValidity(); Don't forget to reset target.setCustomValidity(''); if everything is valid. Docs: https://developer.mozilla.org/en-US/docs/Web/API/HTMLObjectElement/setCustomValidity – Robert Nov 07 '22 at 09:54
4

Video file example (HTML + Javascript):

function upload_check()
{
    var upl = document.getElementById("file_id");
    var max = document.getElementById("max_id").value;

    if(upl.files[0].size > max)
    {
       alert("File too big!");
       upl.value = "";
    }
};
<form action="some_script" method="post" enctype="multipart/form-data">
    <input id="max_id" type="hidden" name="MAX_FILE_SIZE" value="250000000" />
    <input onchange="upload_check()" id="file_id" type="file" name="file_name" accept="video/*" />
    <input type="submit" value="Upload"/>
</form>
mayor
  • 49
  • 5
Fanda
  • 325
  • 5
  • 14
2

I made a solution using just JavaScript, and it supports multiple files:

const input = document.querySelector("input")
const result = document.querySelector("p")

const maximumSize = 10 * 1024 * 1024 // In MegaBytes

input.addEventListener("change", function(e){
    const files = Array.from(this.files)
    const approvedFiles = new Array

    if(!files.length) return result.innerText = "No selected files"

    for(const file of files) if(file.size <= maximumSize) approvedFiles.push(file)

    if(approvedFiles.length) result.innerText = `Approved files: ${approvedFiles.map(file => file.name).join(", ")}`
    else result.innerText = "No approved files"
})
<input type="file" multiple>
<p>Result</p>
Alphka
  • 70
  • 2
  • 6
1

This question was from a long time ago, but maybe this could help someone struggling. If you are working with forms, the easiest way to do this is by creating a new FormData with your form. For example:

form.addEventListener("submit", function(e){
  e.preventDefault()

  const fd = new FormData(this)

  for(let key of fd.keys()){

    if(fd.get(key).size >= 2000000){
      return console.log(`This archive ${fd.get(key).name} is bigger than 2MB.`)
    }

    else if(fd.get(key).size < 2000000){
      console.log(`This archive ${fd.get(key).name} is less than 2MB.`)
    }

    else{
      console.log(key, fd.get(key))
    }

  }

  this.reset()
})

As you can see, you can get the size from an archive submited with a form by typing this:

fd.get(key).size

And the file name is also reachable:

fd.get(key).name

Hope this was helpful!

Matias Coco
  • 351
  • 3
  • 9
0

An <input type="file"> can use multiple, so if you only need to remove some of the files, you can do this:

<input id="file-upload" type="file" multiple />
// define max size in bytes
const maxSize = 10000000;

// get element
const el = document.getElementById('file-upload');

// create data transfer
const dt = new DataTransfer();

// add eligible files to data transfer
for (const file of el.files) {
  if (file.size <= maxSize) {
    dt.items.add(f);
  }
}

// update input files
el.files = dt.files;

In my case, I am using React, so I used a ref.

const refInput = useRef();
<input type="file" multiple ref={refInput} />
// add eligible files to data transfer
for (const file of refInput.current.files) {
  if (file.size <= maxSize) {
    dt.items.add(f);
  }
}

// update input files
refInput.current.files = dt.files;
Michael Lynch
  • 2,682
  • 3
  • 31
  • 59
-2
<script type="text/javascript">
    $(document).ready(function () {

        var uploadField = document.getElementById("file");

        uploadField.onchange = function () {
            if (this.files[0].size > 300000) {
                this.value = "";
                swal({
                    title: 'File is larger than 300 KB !!',
                    text: 'Please Select a file smaller than 300 KB',
                    type: 'error',
                    timer: 4000,
                    onOpen: () => {
                        swal.showLoading()
                        timerInterval = setInterval(() => {
                            swal.getContent().querySelector('strong')
                                .textContent = swal.getTimerLeft()
                        }, 100)
                    },
                    onClose: () => {
                        clearInterval(timerInterval)

                    }
                }).then((result) => {
                    if (
                        // Read more about handling dismissals
                        result.dismiss === swal.DismissReason.timer


                    ) {

                        console.log('I was closed by the timer')
                    }
                });

            };
        };



    });
</script>
Alex Riabov
  • 8,655
  • 5
  • 47
  • 48
-3

PHP solution to verify the size in the hosting.

<?php
        
    if ($_FILES['name']['size'] > 16777216) {
                
    ?>
            
        <script type="text/javascript">
                alert("The file is too big!");
                location.href = history.back();
        </script>
            
    <?php
        
        die();
        
    }
       
?>

16777216 Bytes = 16 Megabytes

Convert units: https://convertlive.com/u/convert/megabytes/to/bytes#16

Adapted from https://www.php.net/manual/en/features.file-upload.php