Multer: How can I get file size inside fileFilter function?

Created on 31 Jul 2015  路  20Comments  路  Source: expressjs/multer

Am I have any way to get file size inside fileFilter function?

var fileFilter = function (req, file, cb) {
  console.log(file.size); // undefined
}

I have only four first keys in file variable

| Key | Description | Note |
| --- | --- | --- |
| fieldname | Field name specified in the form | |
| originalname | Name of the file on the user's computer | |
| encoding | Encoding type of the file | |
| mimetype | Mime type of the file | |
| size | Size of the file in bytes | |
| destination | The folder to which the file has been saved | DiskStorage |
| filename | The name of the file within the destination | DiskStorage |
| path | The full path to the uploaded file | DiskStorage |
| buffer | A Buffer of the entire file | MemoryStorage |

Most helpful comment

Oh, actually that is very easily solvable in a clean way for you!

var limits = { fileSize: 1024 * 1024 * 1024 }
var upload = multer({ limits: limits })

app.post('/upload', upload.single('file'), function (req, res) {
  res.send({ result: 'ok' })
})

app.use(function (err, req, res, next) {
  if (err.code === 'LIMIT_FILE_SIZE') {
    res.send({ result: 'fail', error: { code: 1001, message: 'File is too big' } })
    return 
  }

  // Handle any other errors
})

The fileSize limit will automatically remove the file if it received a too large file, read more in the readme :)

All 20 comments

I'm sorry to say that file.size is only available after the file has been received.

This could possibly be fixed by looking at the Content-Length header of that part, but I do not yet know if browsers send those.

I have solved my problem by deleting file after receiving.
It is not a good way, but I have no idea how can I make it better.

# CoffeeScript
app.post '/upload', upload.single('file'), (req, res) ->
  if req.file.size > 1024 * 1024 * 1024 # file is bigger then 1 Gb
    fs.unlink req.file.path # delete file
    return res.send
      result: 'fail'
      error:
        code: 1001
        message: 'File is too big'

  res.send result: 'ok'

_Sorry for my English_

Oh, actually that is very easily solvable in a clean way for you!

var limits = { fileSize: 1024 * 1024 * 1024 }
var upload = multer({ limits: limits })

app.post('/upload', upload.single('file'), function (req, res) {
  res.send({ result: 'ok' })
})

app.use(function (err, req, res, next) {
  if (err.code === 'LIMIT_FILE_SIZE') {
    res.send({ result: 'fail', error: { code: 1001, message: 'File is too big' } })
    return 
  }

  // Handle any other errors
})

The fileSize limit will automatically remove the file if it received a too large file, read more in the readme :)

I was just example. Really, I have something like the following code, but with more conditions.

  if req.query.form is 'logo' and file.mimetype.slice(0, 5) is 'image' and req.file.size > 1024 * 1024 * 5

Could you use a combination? limits.fileSize and fileFilter to do mimetype filtering?

Keep in mind that with fileFilter you have two options for denying a file. Supply false to the callback and that file will be skipped, or supply an error back and the parsing will be stopped and no further files will be read.

Eventually, I split uploading images, other public files and private files

upload = multer
    storage: multer.diskStorage
        destination: './uploads/'
    limits:
        fileSize: 1024 * 1024 * 1024

uploadStatic = multer
    storage: multer.diskStorage
        destination: './public/uploads/'
    limits:
        fileSize: 1024 * 1024 * 5

uploadStatic = multer
    storage: multer.diskStorage
        destination: './public/uploads/'
    fileFilter: fileIsImageFilter
    limits:
        fileSize: 1024 * 1024 * 5

app.use (err, req, res, next) ->
    if err.code is 'LIMIT_FILE_SIZE'
        res.send
            result: 'fail'
            error: errors.FILE_BIG
        return

app.post '/upload', upload.single('file'), uploadHandler
app.post '/upload/public', uploadStatic.single('file'), uploadHandler
app.post '/upload/public/images', uploadStatic.single('file'), uploadHandler

Thank you for your help, Linus

Looks nice, no problem :+1:

Really, problem exists :) #168 I will use first solution with no limits for a while.

Absolutely, I will try to fix that :) I meant "no problem" as in "Thank you -- No problem"

@LinusU Are you sure, that the file should be removed, in case the fileSize is reached? Because that's not happening in my case.

[edit] Opened #194 for that issue.

Hi @LinusU, I have a similar problem.

Inside the fileFilter function I would like to verify if the file is really an image (reading it's first bytes), by using mmmagic module.

I understand that inside fileFilter the file isn't uploaded yet, so, what do you suggest me to do?

You can check the file's mimetype (file.mimetype) in the fileFilter.

@qqilihq file.mimetype is set only based on it's extension, which isn't safe enough for my use case (and for most ones). What I need is to read it's header (very first bytes) and guess it's filetype.

How to do that is not the problem (mmmagic module can handle it very efficiently), my real doubt is actually when/where to put the code, since populating the controller doesn't seem the right place.

@igor9silva Thank you for your input, guess I should update some of our APIs then :)

@qqilihq I'd recommend you to, depending on your needs.

Hmm, peeking into the stream could actually be a really useful feature. That would require reworking some of the internals though... This is very related to #155, #248 and #211.

Would be awesome @LinusU!

Btw, I solved it by creating a Middleware that "extends" multer.single(). It simply call mmmagic's .detectFile() on the Multer callback and exposes the real MIME-type trough res.locals.

@igor9silva I'm facing the same problem at the moment and I was wondering if you would be able to share the code of the middleware you wrote that leverages mmmagic? It'd be very helpful and much appreciated. Thanks a lot in advance.

@h4r1m4u I ended up creating my own Middleware, which calls multer handler.

Something like:

multer({
    dest:       Settings.MULTER.DESTINATION,
    limits:     Settings.MULTER.LIMITS,
}).single('pic')(req, res, callback);

And then in it's callback I use mmmagic to read the file's magic numbers:

new Magic(mmm.MAGIC_MIME_TYPE).detectFile(req.file.path, function(err, mimetype) {})

This way I'm able to redirect the request flow to the error handler whenever multer or mmmagic identify an invalid file type, and still not made my controller dirty.

@igor9silva Thank you very much, that's helpful. I'll try to adopt a similar approach. I'm currently calling the multer handler in my controller which seems really messy.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Paul-Morris picture Paul-Morris  路  3Comments

bpetty-formfast picture bpetty-formfast  路  3Comments

adrienbarreau picture adrienbarreau  路  3Comments

BlueOctober picture BlueOctober  路  3Comments

samipjain picture samipjain  路  4Comments