Rename a file with multer is not working - node.js

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());
});
});

Related

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.

Rename uploaded images using MULTER

I am uploading the images using multer. They all are given random names (dec93b9f333c7a731723b06ce73c0bbc.jpg), which is very bad for SEO... Can you guys help me out, how to save the images with the pattern: 'fixed-name'+'random-name'.extension. Then at least part of the file would be readable for the google. Thanks!
app.set('images', '/var/www/images');
app.use(app.get('images'), express.static(app.get('images')));
var multerForImage = multer({
dest: app.get('images'),
onParseStart: function (file) {
console.log("Started parsing file stream", file);
},
onFileUploadStart: function (file) {
console.log('File recieved: ', file.originalname);
},
onFileUploadComplete: function (file, req, res) {
console.log("File upload complete");
var path = app.get('images') + "/" + file.name;
var user = req.session.user;
res.json({
success: true,
data: path
});
},
onFileUploadData: function (file, data, req, res) {
console.log('Data recieved for file upload');
},
onParseEnd: function (req, next) {
console.log("Parsing data end for file upload");
}
});
You can use the storage configuration.
app.set('images', '/var/www/images');
app.use(app.get('images'), express.static(app.get('images')));
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, app.get('images'))
},
filename: function (req, file, cb) {
const randomPart = uuidV4(); // use whatever random you want.
const extension = file.mimetype.split('/')[1];
cb(null, 'fixed-name'+ randomPart + `.${extension}`)
}
})
var multerForImage = multer({
storage: storage,
...

NodeJS: 'multer' file upload callback function

I am using 'multer' plugin for file upload. I want to call another function after file upload successfully.
Here my code:
module.exports.uploadFile = upload.single('file', '_id'), function (req, res, next) {
console.log('Uploade Successful');
}
var upload = multer({
storage: multer.diskStorage({
destination: './Media/ChatDocUpload',
filename: function (req, file, cb) {
var dest = './Media/ChatDocUpload';
//query string params
var _chatMessageID = req.query.chatMessageID;
var _ext = file.originalname.substring(file.originalname.indexOf("."));
var _fileName = _chatMessageID + _ext;
cb(null, _fileName);
}
})
});
I want to call my new function after image uploaded. Using this code i can upload image successfully, but not get call callback function.
I need call new function after image uploading completed.
//I need to call this function after image fully uploaded
var uploadSuccessFn = function () {
//code
}
You could maybe change the code to use 2 functions in your POST handler:
module.exports = {uploadFile: uploadFile, afterUpload: afterUpload};
function uploadFile(){
upload.single('file', '_id');
}
function afterUpload(req, res, next) {
console.log('Uploade Successful');
}
var upload = multer({
storage: multer.diskStorage({
destination: './Media/ChatDocUpload',
filename: function (req, file, cb) {
var dest = './Media/ChatDocUpload';
//query string params
var _chatMessageID = req.query.chatMessageID;
var _ext = file.originalname.substring(file.originalname.indexOf("."));
var _fileName = _chatMessageID + _ext;
cb(null, _fileName);
}
})
});
Then simply require the file and use it in the post request handler:
.
.
var imageUpload = require('./handler');
app.post('/image/upload',imageUpload.uploadFile,imageUpload.afterUpload);
.
.
The function (inside the process) when you are calling the process of upload, is the callback fuction just use it . you are written line console.log it means your callback fuction is called when your file is upload but you are not using ..
can be done like this:-
function(req,res){ //callback function
res.json({message:"file uploaded successfully"});
}
it will give you json response.
I suggest that you create your own customized storage engine based on multer:
Multer Storage Engine
Then you just add the customized code after your file has been uploaded. Something like this:
MyCustomStorage.prototype._handleFile = function _handleFile (req, file, cb) {
this.getDestination(req, file, function (err, path) {
if (err) return cb(err)
var outStream = fs.createWriteStream(path)
file.stream.pipe(outStream)
outStream.on('error', cb)
outStream.on('finish', function () {
// Insert here whatever you want to do...
console.log('Successfully Uploaded');
cb(null, {
path: path,
size: outStream.bytesWritten
})
}) })}
Please note that you have to use var fs = require('fs') to make it work. Hope this help.
In your code from where you calling upload put an if condition which checks the checks the callback response. If response null then you can call another function in that condition else show some error.
I guess the function you trying call will show some kind of success message to the user.
try like this
var storage = multer.diskStorage({
destination: function (req, file, cb) {
return cb(null, './Media/ChatDocUpload')
},
filename: function (req, file, cb) {
var _chatMessageID = req.query.chatMessageID;
var _ext = file.originalname.substring(file.originalname.indexOf("."));
var _fileName = _chatMessageID + _ext;
return cb(null, _fileName);
}
})
var upload = multer({ storage: storage })
module.exports.uploadFile = upload.single('file'), function (req, res, next) {
console.log('Uploade Successful');
// you function after uploading images
}

multer: dynamic destination path

I am writing a node application and I was looking for something to upload files on the server. I could get files to upload when there was only one static directory. But I need to make directories per user and then upload files to those, according to the user that's logged in. I looked stuff up but everything that I try ends in an Error: ENOENT: no such file or directory, open ... error. What I am trying to do currently is this -
let storage = multer.diskStorage({
destination: function(req, file, cb) {
let dest = path.join(__dirname, './documents', 'somenameigetfromtheuser');
let stat = null;
try {
stat = fs.statSync(dest);
}
catch (err) {
fs.mkdirSync(dest);
}
if (stat && !stat.isDirectory()) {
throw new Error('Directory cannot be created');
}
cb(null, dest);
}
});
let upload = multer({
storage: storage,
dest: 'documents/'
});
app.post('/testUpload', upload.single('testfile'), (req, res) => {
res.json({
test: 'test'
})
});
There is a similar question that has been answered but it doesn't work that way for me because I want the directory name from the request object.
When I remove the storage property in my multer initialization, the files are stored in the documents directory with a random name. I want the file to have its original name and I want it to be stored in a directory where I get the name of the directory from the req object.
Help a brother out, thanks!
edited
See https://github.com/expressjs/multer#diskstorage
Note that req.body might not have been fully populated yet. It depends on the order that the client transmits fields and files to the server.
Due to that, first write file in temp directory, read directory name from req and move file:
fs = require('fs-extra'); //npm install fs.extra
...
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, '../tempDir/')
},
filename: function (req, file, cb) {
cb(null, file.originalname)
}
});
var upload = multer({
storage: storage
}).single('file');
upload(req, res, function (err) {
if (err) {
res.json({});
return;
}
var dir = JSON.parse(req.body.data).directory;
var filename = req.file.filename;
fs.move('../tempDir/' + fileName, '../tempDir/' + dir + '/' + fileName, function (err) {
if (err) {
return console.error(err);
}
res.json({});
});
});
Here's code for dynamic path by argument!
exports.upload = (folderName) => {
return imageUpload = multer({
storage: multer.diskStorage({
destination: function (req, file, cb) {
const path = `src/assets/uploads/${folderName}/`;
fs.mkdirSync(path, { recursive: true })
cb(null, path);
},
// By default, multer removes file extensions so let's add them back
filename: function (req, file, cb) {
cb(null, Date.now() + path.extname(file.originalname));
}
}),
limits: { fileSize: 10000000 },
fileFilter: function (req, file, cb) {
if (!file.originalname.match(/\.(jpg|JPG|webp|jpeg|JPEG|png|PNG|gif|GIF|jfif|JFIF)$/)) {
req.fileValidationError = 'Only image files are allowed!';
return cb(null, false);
}
cb(null, true);
}
})
}
and call it
Make sure you append first the textfields on the client-side and only then do you append the files. In my case i had something like this:
`
for(let i=0; i<files.length;i++)
{
formData.append("files[]",files[i]);
}
formData.append("username",username);
`
The fix was to first append the textfield like so:
`
formData.append("username",username);
for(let i=0; i<files.length;i++)
{
formData.append("files[]",files[i]);
}
`
Here's what I do for uploading files to dynamic directories.
In frontend I use URL parameters to pass user IDs.
await axios({
method: 'post',
data: formData,
url: '/api/upload?userId=123',
headers: { 'content-type': 'multipart/form-data' }
})
In backend get that parameter and use for destination. Also create the directory if it doesn't exist.
const upload = multer({
storage: multer.diskStorage({
destination: (req, file, cb) => {
const directory = `./public/uploads/${req.query.userId}`
if (!fs.existsSync(directory)) {
fs.mkdirSync(directory, { recursive: true })
}
cb(null, directory)
},
filename: (req, file, cb) => {
cb(null, `${Date.now()}-${file.originalname}`)
}
})
})
In my project I use multer as follow:
1.Store the file first in a common directory, like /tmp/.
2.Copy/move the file anywhere you want, to CDN in my case, and to a user folder in yours.
3.Remove the original file in /tmp if needed.
And maybe let upload = multer({
storage: storage,
dest: 'documents/'
}); you should remove the dest here since you specified dest in storage, right?
const storage = multer.diskStorage({
destination: function(req, file, callback){
callback(null, path.dirname('D:/') + 'Integra Qamba Site/');
},
filename: function(req, file, callback){
let data = new Date();
callback(null, dateTime +".jpg");
}
});

Resources