how to validate a minimum number of files uploaded with multer? - node.js

I want to upload files with multer, but I need that if less than 3 files are loaded simultaneously it shows an error and does not save them on my server. I know how to limit a maximum number of files, but I don't know how to limit a minimum number of files. This is my Multer configuration
const multer = require('multer');
function uploadFile() {
const storage = multer.diskStorage({
destination: './public/files',
filename: function (_req, file, cb) {
var extension = file.originalname.slice(file.originalname.lastIndexOf('.'));
cb(null, Date.now() + extension);
}
});
const upload = multer({
storage,
limits: {fileSize: 11657128, files: 3},
fileFilter: function(req, file, cb) {
let type = req.files
type?cb(null, true):cb(new Error ('no es un archivo de tipo texto plano'));
}}
).array('file');
return upload;
}
module.exports = uploadFile;

You can add a middleware or a validation at your routes.
app.post('/your/route', upload.array('field', 3), function (req, res) {
if (req.files.length !== 3) {
return res.status(400).json({ error: 'Three files is required'})
}
})
With array of middleware:
function validUploadLength (req, res, next) {
if (req.files.length !== 3) {
return res.status(400).json({ error: 'Three files is required'})
}
next()
}
app.post('/your/route', [upload.array('field', 3), validUploadLength], function (req, res) {
/// Your code
})

Related

Multer error cannot upload file with size above 50kb

I'm having an issue with multer since I'm using socket.io(I'm not sure but after I use this my multer middleware did not work properly). Here is my code for more information
const maxSize = 1024 * 1024 * 2
const storage = multer.diskStorage({
destination: function (_req, _file, cb) {
cb(null, path.join(process.cwd(), 'assets', 'pictures'))
},
filename: function (_req, file, cb) {
const ext = file.originalname.split('.')[1]
const date = new Date()
cb(null, `${date.getTime()}.${ext}`)
}
})
const upload = multer({
storage: storage,
limits: { fileSize: maxSize }
}).single('picture')
const uploadFilter = (req, res, next) => {
console.log(req, 'test mmulter first')
upload(req, res, function (err) {
if (err instanceof multer.MulterError) {
return response(res, false, err.message, 400)
} else if (err) {
return response(res, false, err.message, 500)
}
// console.log(req, 'test multer second')
next()
})
}
So when I try to upload a file under 50kb the upload works perfectly, but when I try to put a file with a size of more than 50kb it will keep hanging, no return any response even it no returns an error, so when this error happens the console.log() and next() inside upload not called. The weird thing is the file indeed saved to my local folder (either 50kb or greater) but when it came to the file with size above 50kb it will cropped.
like this
enter image description here

How to catch errors in multer

I have read documentation for multer. But the current set up I have in my code is different and this makes difficult for me to understand how to handle errors.
It is important now because it happened (only once) that a file was not stored on the server but the code continued saving info in database as if the storing of the file had worked. But it probably did not.
const multer = require('multer');
var docPath = "path_to_disk_where_to_store_files";
var storage = multer.diskStorage({
inMemory: true,
destination: function (request, file, callback) {
callback(null, docPath);
},
filename: function (request, file, callback) {
//Just a function that creates an unique name with timestamp
renamedFile = helpers.createUniqueName(file.originalname);
callback(null, renamedFile);
}
});
var fileFilter = function (req, file, cb) {
var path = require('path');
var ext = path.extname(file.originalname);
if (file.mimetype !== 'application/pdf' || ext.toLowerCase() != '.pdf') {
req.fileValidationError = 'goes wrong on the mimetype';
return cb(null, false, new Error('goes wrong on the mimetype'));
}
cb(null, true);
};
const multerUploader = multer({storage: storage, fileFilter: fileFilter, limits: { fileSize: maxSize }});
router.post('/save_document',[multerUploader.single('file'),saveDocumentInDb]);
I dont really understand where the if-statement that will check if the upload got an error would fit.
Please refer the following for error handling when using multer:
https://github.com/expressjs/multer#error-handling
Your implementation will be something like this:
const multerUploader = multer({storage: storage, fileFilter: fileFilter, limits: { fileSize: maxSize }});
const upload = multerUploader.single('file');
router.post('/save_document', function (req, res) {
upload(req, res, function (err) {
if (err instanceof multer.MulterError) {
// A Multer error occurred when uploading.
} else if (err) {
// An unknown error occurred when uploading.
}
// Everything went fine and save document in DB here.
})
})

express body-parser and multer value receiving issue?

I am giving post request /product/create with some value and an image.
if I console every value before
upload(req, res, (err) => {})
it is showing properly with out image info.
if I receive the value after upload(req, res, (err) => {})
No value is showing.
Full post request code:
app.post('/product/create', (req, res) => {
let filename;
upload(req, res, (err) => {
if(err){
res.render('index', {
msg: err
});
} else {
if(req.file == undefined){
res.render('index', {
msg: 'Error: No File Selected!'
});
} else {
res.render('index', {
msg: 'File Uploaded!',
filename = req.file.filename;
});
}
}
});
const product = {
title : req.body.title,
desc : req.body.desc,
image : filename,
}
});
configuring Multer:
const storage = multer.diskStorage({
destination: './public/uploads/',
filename: function(req, file, cb){
cb(null,file.fieldname + '-' + Date.now() + path.extname(file.originalname));
}
});
const upload = multer({
storage: storage,
limits:{fileSize: 1000000},
fileFilter: function(req, file, cb){
checkFileType(file, cb);
}
}).single('myImage');
function checkFileType(file, cb){
const filetypes = /jpeg|jpg|png|gif/;
const extname = filetypes.test(path.extname(file.originalname).toLowerCase());
const mimetype = filetypes.test(file.mimetype);
if(mimetype && extname){
return cb(null,true);
} else {
cb('Error: Images Only!');
}
}
Multer does not support 'req.file.filename' outside upload function. As filename, originalname, fieldname etc is inbuild API of multer. It is limited to upload function only.
Now, if you are trying to upload product values inside database then you have to create an insert function inside multer upload function only.

Multer is uploading file, but not populating req.files

I'm studying node.js for a school project and I can't figure out why my code won't work. Whenever I upload a form that contains text and a file, the req.body gets populated but the req.files doesn't
server.js
const multer = require('multer')
const bparser = require('body-parser')
app.use(bparser.urlencoded(settings.body_parser))
...
let multer_storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, path.join(__dirname, settings.multer.destination))
},
filename: (req, file, cb) => {
cb(null, Date.now() + path.extname(file.originalname))
}
})
let multer_options = {
storage: multer_storage,
fileFilter: (req, file, cb) => {
if (settings.multer.allowed_files.indexOf(file.mimetype) >= 0)
cb(null, true)
cb(null, false)
}
}
app.use(multer(multer_options).any())
app.use("*", (req, res, next) => {
if (!req.session.user)
if (req.cookies.user)
req.session.user = req.cookies.user
next()
})
for (let i = 0; i < settings.routes.length; i++) {
app.use('/', require("./core/routers/" + settings.routes[i]))
}
...
./core/routers/post.js
const router = require('express').Router()
...
router.post('/post/share/', (req, res) => {
let data = {
title: req.body.title,
user: req.session.user,
post: req.files[0].path,
tags: req.tags.split(" ")
}
post.create(data).then((result) => {
return result
})
})
I keep encountering a "TypeError: Cannot read property 'path' of undefined"
When you call cb(null, false) in your fileFilter method, you tell multer that it shouldn't process the file, but it will still enter your middleware with: req.files being undefined that's why you get that error.
If you don't want it to enter to your middleware if the file wasn't processed, then you should pass an error to the callback instead:
let multer_options = {
storage: multer_storage,
fileFilter: (req, file, cb) => {
if (settings.multer.allowed_files.indexOf(file.mimetype) >= 0)
return cb(null, true); // this return is missing
cb(new Error('Invalid file'));
}
}
In any case, you're missing a return statement before cb(null, true); otherwise you're calling twice the callback, once with true and the other once with false
To sum up, if you don't pass an Error to the fileFilter function, you should check for the presence of req.files in your middleware.
Or you can try the code below:
var tmp_path = req.file.path;

Rename a file with multer is not working

I'm trying to rename a file using multer. I want to rename the file uploaded to a .jpg
Instead of the tutorial about multer, i'm calling the method rename in my route file. The file is well uploaded but I don't get why the function rename is not working.
By the way, the word 'ici' doesn't appear into my console
router.post('/edit/saveEdit',multer({
rename : function(fieldname, filename, req, res) {
console.log('ici');
return req.body.infoUser.id
}}),
function(req,res){
// console.log(req.body);
// console.log(JSON.stringify(req.files));
var conf = JSON.parse(fs.readFileSync(file_user));
var user = req.body.infoUser;
//changement de nom de fichier
// console.log(req.files.uploadAvatar);
Thanks for answers/help
Thibault
res.end('good');
It is working for me with the code as below:
var multer = require('multer')
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, 'public/uploads/')
},
filename: function (req, file, cb) {
var getFileExt = function(fileName){
var fileExt = fileName.split(".");
if( fileExt.length === 1 || ( fileExt[0] === "" && fileExt.length === 2 ) ) {
return "";
}
return fileExt.pop();
}
cb(null, Date.now() + '.' + getFileExt(file.originalname))
}
})
var multerUpload = multer({ storage: storage })
var uploadFile = multerUpload.single('file');
try using multer first for performing the desired operation on file and then serving the request.
example :
router.use(multer({
dest: './path/to/folder',
rename : function (fieldname, filename, req, res) {
console.log('ici');
return req.body.infoUser.id
}
}
)));
router.post('/edit/saveEdit', function(req, res){
// Operations saveEdit is hit
});
It is working on my side, please check if that works for you as well.
app.post('/api/photo', function(req, res) {
upload(req,res,function(err) {
if(err) {
return res.end("Error uploading file.");
}
//console.log("Resopnse "+res); e74e107b91f6ed71c70eabb2c2d87d6c
res.end("File is uploaded .... "+Date.now());
});
});

Resources