Uploading Image with Multer - additional blob created alongside image - node.js

const upload = multer({ dest: `${__dirname}/uploads/images` });
app.post(
"/api/users/:id/uploadProfilePic",
upload.single("image"),
updateProfilePic
);
const updateProfilePic = async (req, res) => {
const userId = req.param("id");
if (userId && isNumber(userId)) {
// When using the "single"
// data come in "req.file" regardless of the attribute "name". *
const tmpPath = req.file.path;
// The original name of the uploaded file
// stored in the variable "originalname". *
const targetPath = `uploads/images/${req.file.originalname}`;
/** A better way to copy the uploaded file. **/
const src = fs.createReadStream(tmpPath);
const dest = fs.createWriteStream(targetPath);
src.pipe(dest);
src.on("end", () => {
res.status(200).send("complete");
});
src.on("error", err => {
res.status(500).send(err);
});
}
};
In my express app, I have the following code for uploading an image - this seems to upload the image successfully, but it also creates this data blob in my uploads folder -

You can do something like
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, 'uploads/')
},
filename: function (req, file, cb) {
cb(null, file.originalname)
}
})
const upload = multer({storage: storage})

Related

How to create folder automatically before files upload via multer so that those files get stored in that created folder in nodejs?

This is my multer code to upload multiple files.
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, './public/files/'+ req.user.id)
},
filename: function (req, file, cb) {
x = file.originalname; //+path.extname(file.originalname);
cb(null,x);
}
});
var upload = multer({storage: storage});
This is the post request where files get submitted on click submit.
router.post(upload.array("FileUpload",12), function(req, res, next) {
//Here accessing the body datas.
})
So what I want is that, I want to create a folder first with the name of the ID generated which can be access from the req.body and then upload those files into that folder respectively.
But since I cannot access the body first before upload I am unable to create that respective folder directory. Is there any other way around which I can think of and implement this?
Updated Solution using fs-extra package.
const multer = require('multer');
let fs = require('fs-extra');
var storage = multer.diskStorage({
destination: function (req, file, cb) {
let Id = req.body.id;
fs.mkdirsSync('./public/files/'+ req.user.id + '/' + Id);
cb(null, './public/files/'+ req.user.id + '/' + Id)
},
filename: function (req, file, cb) {
x = file.originalname; //+path.extname(file.originalname);
cb(null,x);
}
});
var upload = multer({storage: storage});
This is the post request where files get submitted on click submit.
router.post(upload.array("FileUpload",12), function(req, res, next) {
//Here accessing the body datas.
})
you have to install first the fs-extra which will create folder
create seprate folder for multer like multerHelper.js
const multer = require('multer');
let fs = require('fs-extra');
let storage = multer.diskStorage({
destination: function (req, file, cb) {
let Id = req.body.id;
let path = `tmp/daily_gasoline_report/${Id}`;
fs.mkdirsSync(path);
cb(null, path);
},
filename: function (req, file, cb) {
// console.log(file);
let extArray = file.mimetype.split("/");
let extension = extArray[extArray.length - 1];
cb(null, file.fieldname + '-' + Date.now() + "." + extension);
}
})
let upload = multer({ storage: storage });
let createUserImage = upload.array('images', 100);
let multerHelper = {
createUserImage,
}
module.exports = multerHelper;
in your routes import multerhelper file
const multerHelper = require("../helpers/multer_helper");
router.post(multerHelper , function(req, res, next) {
//Here accessing the body datas.
})

How to define multer storage in different file?

I have a node application with express.
The server is at server.js and I have routers set up like the following:
app.use('/xyz', xyz);
app.use('/abc', abc);
The routers xyz and abc are in different route modules in /routes.
I want to use multer to upload images to MongoDB. The endpoint for uploading files is /xyz/upload
storage = new GridFsStorage({
url: process.env.DB_URL,
file: (req, file) => {
return new Promise((resolve, reject) => {
const filename = file.originalname;
const fileInfo = {
filename: filename,
bucketName: 'uploads'
};
resolve(fileInfo);
});
}
});
How can I define this const upload = multer({ storage }); in the xyz router file?
All the examples on the internet show multer being defined in server.js and app.post(). What to do if I have a router defined in a different module?
If you are looking for a cleaner architecture then I would suggest following the separation of concerns principle (SoC) and treat the file handling middleware in a separate file as follows:
const multer = require("multer");
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, "./public/uploads");
},
filename: function (req, file, cb) {
const uniqueSuffix = Date.now() + "-" + Math.round(Math.random() * 1e9);
cb(
null,
new Date().getTime() + "-" + uniqueSuffix + "-" + file.originalname
);
},
});
const fileFilter = (req, file, cb) => {
// reject all files except jpeg
if (file.mimetype === "image/jpeg") {
cb(null, true);
} else {
cb(null, false);
}
};
module.exports = multer({
storage: storage,
limits: {
fileSize: 1024 * 1024 * 15, // 15mb max size,
},
fileFilter: fileFilter,
});
then, in your routes, a simple require if you are working with CommonJS should be enough:
const upload = require("./fileHandling");
server.post(
`/route`,
upload.array('Photos', 6),
controller,
);
It did the trick for me, hope it helps!

How can i use multer with react?

I am build a web app with Node.js and React and I am trying to store some files at my backend.
For some reason i cant access to my req.path , although I configured all multer strategies.
const multer = require('multer')
const config = require('config')
const auth = require('../../middleware/auth')
const {check , validationResult } = require('express-validator');
const storage = multer.diskStorage({
destination: function(req, file , cb){
cb(null,'uploads/')
},
filename: function(req, file, cb){
cb(null, req.user.id)
}
});
const fileFilter = (req, file , cb) =>{
if(file.mimetype === 'image/jpeg' || file.mimetype === 'image/jpg' || file.mimetype === 'image/png')
cb(null,false);
else
cb(null,true);
}
my route:
router.post('/' , [auth,upload.single('image'),
[
check('status','Status is required').not().isEmpty(),
check('skills','Skills is required').not().isEmpty(),
check('gender','Gender is required').not().isEmpty()
]],
async (req,res) => {// cant access to req.file.....}
and my react form:
<div className="form-group">
<input type="text" placeholder="Choose profile image" name="profileImage" value={image}/>
<input type="file" placeholder="Upload" enctype="multipart/form-data" name="image" onChange={(e) => onChange(e)}/>
<small className="form-text">The image must not be bigger then 5MB and only JPG\JPEG\PNG types</small>
</div>
Please , what am i doing wrong?
I have used multer in my backend application and this is how I have configured it and it works properly and stores required files in server file directory.
First, installing multer
npm i multer --save
Second, initialize it at the top of required .js file
const multer = require("multer");
Now, configuring storage (storage location and filename)
const storage = multer.diskStorage({
destination: "./public/uploads/postimages/",
filename: function (req, file, cb) {
cb(
null,
file.fieldname + "-" + Date.now() + path.extname(file.originalname)
);
},
});
Init multer function, (configure own file size)
Use array if you want to upload multiple files at once, 10 is the number of files, you can modify it as needed.
const upload = multer({
storage: storage,
limits: { fileSize: 10000000000 },
}).array("image", 10);
// Use .single("image"); if you want to upload a single file.
// image is the name/key that is sent from frontend with the file(s).
If you are using array, you can create an api that stores file, which will look like this.
try {
let imagePath = "abc";
let postId = req.params.postId;
let imagesLinks = [];
await upload(req, res, (err) => {
if (err) {
console.log(err);
} else {
if (req.files == undefined) {
console.log("File not found.");
} else {
//image uploaded successfully
req.files.map(function (file) {
imagePath = "uploads/postimages/" + file.filename;
imagesLinks.push(tmp);
});
}
}
res.status(201).send(imagesLinks);
});
}
For a single file, it looks as simple as this
try {
let imagePath = "abc";
upload(req, res, (err) => {
if (err) {
res.status(300).send(err);
console.log(err);
} else {
if (req.file == undefined) {
res.status(301).send("image upload failed.");
} else {
//image uploaded successfully
imagePath = "uploads/" + req.file.filename;
storeImageLink(res, imagePath);
}
}
});
}
Look at these examples. They will be help you:
File Upload With Multer in Node.js and Express
Multer Storage:
// SET STORAGE
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, 'uploads')
},
filename: function (req, file, cb) {
cb(null, file.fieldname + '-' + Date.now())
}
})
var upload = multer({ storage: storage })
Handling File Uploads:
app.post('/uploadfile', upload.single('myFile'), (req, res, next) => {
const file = req.file
if (!file) {
const error = new Error('Please upload a file')
error.httpStatusCode = 400
return next(error)
}
res.send(file)
})
Reactjs nodejs upload image — How to upload image using reactjs and nodejs (multer)
Node.js:
const path = require("path");
const multer = require("multer");
const storage = multer.diskStorage({
destination: "./public/uploads/",
filename: function(req, file, cb){
cb(null,"IMAGE-" + Date.now() + path.extname(file.originalname));
}
});
const upload = multer({
storage: storage,
limits:{fileSize: 1000000},
}).single("myImage");
const router = express.Router();
router.post("/upload", {
upload(req, res, (err) => {
console.log("Request ---", req.body);
console.log("Request file ---", req.file);//Here you get file.
/*Now do where ever you want to do*/
if(!err)
return res.send(200).end();
});
};);

Multer fileFilter is not getting called and req.body is empty

for some reason the fileFilter on multer is not getting called.
here is my Controller (i am using express routers)
const express = require('express');
const router = express.Router();
const UploadController = require('../controllers/UploadController');
router.route('/upload').post(UploadController.upload);
module.exports = router;
and this is the controller
const multer = require('multer');
const fs = require('fs');
module.exports = {
upload: function (req, res) {
let storage = multer.diskStorage({
destination: function (req, file, cb) {
console.log('here');
const filesDir = './uploads/' + req.body.ref;
if (!fs.existsSync(filesDir)) {
fs.mkdirSync(filesDir);
}
cb(null, filesDir);
},
filename: function (req, file, cb) {
let extArray = file.mimetype.split("/");
let extension = extArray[extArray.length - 1];
cb(null, req.body.type + '-' + Date.now() + '.' + extension);
},
fileFilter : function (req, file, cb) {
if (!file.originalname.match(/\.(jpg|jpeg|png|gif)$/)) {
return cb(new Error('Only image files are allowed!'), false);
}
cb(null, true);
}
})
const upload = multer({ storage: storage }).single('file');
upload(req, res, function (err) {
if (err instanceof multer.MulterError) {
res.send({
error: err
});
} else if (err) {
res.send({
error: err
});
}else{
res.send({
file: req.file,
body: req.body
});
}
});
}
}
I have following issues:
The fileFilter function is not even called so its not validating files
the req.body on the upload function (upload: function (req, res)) is empty it is only available in diskStorage and last upload function (upload(req, res, function (err)) so i cannot validate the body data also.
I had the same problem. the fileFilter function has to be defined inside multer, not inside the diskStorage function.
To make it a bit more readable I defined the storage and filter in variables instead of making everything inside the multer call.
// storage settings
const multerStorage = multer.diskStorage({
destination: function(req, file, next) {
next(null, './public/files');
},
filename: function(req, file, next) {
const sanitizedName = file.originalname
.replace('/[^a-z0-9\./gi', '-')
.replace('/-{2,}/g', '-')
.toLowerCase();
const name = Date.now() + '-' + sanitizedName;
// sending the file name to be stored in the database
req.body.filename = name;
next(null, name);
},
limits: {
fileSize: 25000000
}
});
// filter function
const multerFilter = function(req, file, cb) {
const ext = path.extname(file.originalname).toLowerCase();
if (ext !== '.pdf') {
cb(new Error('File must be in PDF format.'));
}
cb(null, true);
}
And then applying the storage settings and filter function to multer:
const upload = multer({
storage: multerStorage,
fileFilter: multerFilter
});

Same Image not uploading in express

I am trying to upload an image using express but I am facing two problems, first, whenever I upload the same image again it's not getting uploaded and secondly after uploading any single image a file with image also uploading. Here is my code.
var multer = require('multer');
var uploads = multer({dest: './images'});
app.post('/uploading', uploads.single("file"), function (req, res) {
var file = __dirname +"/images" + "/" + req.file.originalname;
fs.readFile( req.file.path, function (err, data) {
fs.writeFile(file, data, function (err,data) {
if( err ){
console.error( err );
response = {
message: 'Sorry, file couldn\'t be uploaded.',
filename: req.file.originalname
};
}else{
response = {
message: 'File uploaded successfully',
filename: req.file.originalname
};
}
res.end( JSON.stringify( response ) );
});
});
})
The uploads.single("file") middleware Will handle the file upload. You don't have to specifically fs.read and fs.write the file.
var multer = require('multer');
var uploads = multer({dest: './images'});
app.post('/uploading', uploads.single("file"), function (req, res) {
//the file is uploaded automatically
})
EDIT: The above code will upload the file with hex string as filename without any extension.
In order to add rename function you need to use diskStorage. Here is the code taken from this github issue page.
var multer = require('multer');
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, './images/')
},
filename: function (req, file, cb) {
crypto.pseudoRandomBytes(16, function (err, raw) {
cb(null, raw.toString('hex') + Date.now() + '.' + mime.extension(file.mimetype)); //this is the rename func
});
}
});
var uploads = multer({ storage: storage });
app.post('/uploading', uploads.single("file"), function (req, res) {
//the file is uploaded automatically
})
Now you can use the uploads variable as middleware as shown in the above snippet.
you can edit the filename: function (req, file, cb) { .. } according to your needs. Now the filename will be, <16characterhexstring>.ext
another way to handle it will be not using middleware and using multer manually with below options :
try {
var storage = multer.diskStorage({
destination: function(request, file, callback) {
//define folder here by fs.mkdirSync(anyDirName);
},
filename: function(req, file, callback) {
callback(null, anyFileName);
},
limits: self.limits
});
var upload = multer({
storage: storage,
fileFilter: function(request, file, callback) {
// here you can filter out what not to upload..
}
}).any();
upload(request, response, callback);
} catch (e) {
}
hope this helps!

Resources