Rename uploaded images using MULTER - node.js

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,
...

Related

Not able to save image with original name and extension through multer in node.js

Hi I am trying to save an image in my image folder through multer but the issue is that the file is being saved with a randomly generated filename without extension.I have tried to resolve this issue by referring to various articles but still facing the same issue.
referred the following :
Multer is not saving the file as the same name and without extension?
The file gets saved in the image folder like below :
a9bfcba8e950ccfbdaf7f0d2f8d58374
Hence if someone could please help me resolve this issue.
profile.js
const upload = multer({
dest:'images',
filename: function (req, file, cb) {
cb(null, file.originalname)
},
limits: {
fileSize: 10000000,
},
fileFilter(req, file, cb) {
if(!file.originalname.match(/\.(jpg|jpeg|png|JPG|HEIC)$/)) {
return cb(new Error('Please attach an image'))
}
cb(undefined, true);
}
})
router.post('/user/upload', upload.single('profile_pic') , async (req,res) => {
console.log(req.body)
const url = req.protocol + '://' + req.get('host')
//when inserting the file in the database we are able to send the exact location with original file name and extension.
var filepath = url + '/Users/images/';
var reqFiles = (filepath + req.file.filename + path.extname(req.file.originalname)
console.log(req.file);
const notify = new user({
userId: req.body.userId,
profile_pic: reqFiles
})
you need to do step wise process for storing a file.
//storage for image upload
const storage = multer.diskStorage({
destination: './upload',
filename: function (req, file, cb) {
cb(null, file.fieldname + '-' + Date.now() + path.extname(file.originalname));
}
});
//file filter for extention
let fileFilter = function (req, file, cb) {
console.log(file.mimetype)
const allowedMimes = ['image/jpeg', 'image/jpg', 'image/png', 'image/gif'];
if (allowedMimes.includes(file.mimetype)) {
cb(null, true);
} else {
cb(null, false);
}
};
//upload for to pass storage, file size limit and filter
//maximum file size is 10Mb
const upload = multer({
storage: storage,
limits: { fileSize: 10 ** 7 },
fileFilter: fileFilter
}).single('userImage');
then call your route.
router.post('/upload', (req,res)=>{
upload(req, res, (err)=>{
if(err){
console.log(err)
}
else{
console.log(req.file)
console.log(req.file.path)
}
})
})
By following this approach then definitely your error will solved.

Node.js - Uploading both an image and a file with Multer?

I am working on a mod site, and I was able to create a method that uploads an image, but I was wondering if it's possible to also upload a zip file in the same method. I tried chaining on code for the file after creating a file model, but I get an unexpected field error. Here's the method I'm trying
router.post('/upload', uploadImage.single('image'), uploadFile.single('file'), IsLoggedIn, (req, res, next) => {
console.log(req.file);
var newImg = new Image({
data: req.file.filename
});
var newFile = new File({
data: req.file.filename
});
Mod.create({
name: req.body.name,
image: newImg.data,
game: req.body.game,
file: newFile.data
}, (err, newMod) => {
if (err) {
console.log(err);
}
else {
res.redirect('/mods');
}
});
});
And here are my storage engines
const imageStorage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, './public/images')
},
filename: (req, file, cb) => {
cb(null, file.originalname)
}
});
const fileStorage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, './public/images')
},
filename: (req, file, cb) => {
cb(null, file.originalname)
}
});
const uploadImage = multer({storage: imageStorage});
const uploadFile = multer({storage: fileStorage});
Is it possible to use 2 storage engines and chain 2 uploads in one method, or am I going about it all wrong? Any clarification or direction would be greatly appreciated.

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.

Custom Multer storage - Illegal operation when using Sharp

I'm using Multer together with Sharp to store images uploaded as part of an HTML form. I want to resize and transform the images before storing them on the disk and found this thread about how to do just that.
I thought I had set-up everything correctly, but when I try and upload an image I get:
Error: EISDIR: illegal operation on a directory, open 'C:\...\uploads'
Below is my code:
Routes.js:
var multer = require('multer');
var customStorage = require(path.join(__dirname, 'customStorage.js'));
var upload = multer({
storage: new customStorage({
destination: function (req, file, cb) {
cb(null, path.join(__dirname, 'uploads'));
},
filename: function (req, file, cb) {
cb(null, Date.now());
}
}),
limits: { fileSize: 5000000 }
});
...
app.use('/upload', upload.single('file'), (req, res) => { ... });
customStorage.js:
var fs = require('fs');
var sharp = require('sharp');
function getDestination (req, file, cb) {
cb(null, '/dev/null'); // >Implying I use loonix
};
function customStorage (opts) {
this.getDestination = (opts.destination || getDestination);
};
customStorage.prototype._handleFile = function _handleFile(req, file, cb) {
this.getDestination(req, file, function (err, path) {
if (err) return cb(err);
var outStream = fs.createWriteStream(path);
var transform = sharp().resize(200, 200).background('white').embed().jpeg();
file.stream.pipe(transform).pipe(outStream);
outStream.on('error', cb);
outStream.on('finish', function () {
cb(null, {
path: path,
size: outStream.bytesWritten
});
});
});
};
customStorage.prototype._removeFile = function _removeFile(req, file, cb) {
fs.unlink(file.path, cb);
};
module.exports = function (opts) {
return new customStorage(opts);
};
The error Error: EISDIR: illegal operation on a directory in this context indicates that you are setting Multer's destination to a directory when it should be the name of the destination file.
The destination is set in the line cb(null, path.join(__dirname, 'uploads')); in Routes.js. If you change this line to something like cb(null, path.join(__dirname, 'myDirectory\\mySubdirectory\\', myFilename + '.jpg')), it will work.

How to resize image size in nodejs using multer

Multer have already limit size property. This property only restrict the image. Not resize the image. My question is suppose image is greater than "limit size", how to resize that image ?
var storageOptions = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, 'useravatars/')
},
filename: function (req, file, cb) {
cb(null, file.fieldname + '-' + Date.now())
}
});
var avatarUpload = multer({
storage: storageOptions,
limits: {
fileSize: 1000000
}
}).single("avatar");
It depends on whether you want to store the resized image as well.
In any case, you'll use a library to handle the resize operation. sharp is a very good option.
Resize in a route handler(after file is stored to disk):
sharp(req.file).resize(200, 200).toBuffer(function(err, buf) {
if (err) return next(err)
// Do whatever you want with `buf`
})
Other option would be creating your own storage engine, in this case you'll receive the file data, resize, then store to disk (copied from https://github.com/expressjs/multer/blob/master/StorageEngine.md):
var fs = require('fs')
function getDestination(req, file, cb) {
cb(null, '/dev/null')
}
function MyCustomStorage(opts) {
this.getDestination = (opts.destination || getDestination)
}
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)
var resizer = sharp().resize(200, 200).png()
file.stream.pipe(resizer).pipe(outStream)
outStream.on('error', cb)
outStream.on('finish', function() {
cb(null, {
path: path,
size: outStream.bytesWritten
})
})
})
}
MyCustomStorage.prototype._removeFile = function _removeFile(req, file, cb) {
fs.unlink(file.path, cb)
}
module.exports = function(opts) {
return new MyCustomStorage(opts)
}
const path = require("path");
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, path.join(__dirname, "/uploads"));
},
filename: function (req, file, cb) {
cb(null, uuid.v4() + `${path.extname(file.originalname)}`);
}
});
const limits = {
fields: 10,
fileSize: 500 * 1024,
files: 1,
};
const upload = multer({ storage, limits });
const baseUrl = "http://localhost:3000/files/";
router.post("/upload", upload.single("file"), async (ctx, next) => {
ctx.body = {
code: 1,
data: baseUrl + ctx.file.filename,
};
});

Resources