I am using MongoDB, nodeJS, express, multer, jimp and gridFS to upload an image. I first uploaded the image with multer then resized it with jimp then uploaded the jimp buffer to MongoDB now when I delete the multer image an error comes that the file is probably corrupt as the chunks file is not written(i don't know why but it is actually not written when I want to delete it) can any one tell how to achieve this and what is the error in my code.
here is my post route
app.post('/upload', upload.single("file"), (req, res) => {
if(req.file === undefined || req.file === 0 || req.file === ""){
res.redirect("/");
}
console.log(req.file);
filename = req.file.filename;
Jimp.read( "http://localhost:3000/image/" + req.file.filename, (err, image) => {
if (err) {
console.log(err);
}
// .then(lenna => (tpl.clone().write(imgActive)))
image
.resize(500, Jimp.AUTO)
// console.log(img);
image.getBase64(Jimp.AUTO, (error1, base64Image) => {
if(error1){
console.log(error1);
}
const image1 = new Image({
image: base64Image,
User: "Avichal",
forTest: "Hindi1"
});
image1.save(function(error){
if(error){
console.log(error);
}
})
})
})
gfs.remove({ _id: req.file.id, root: 'uploads' }, (err, gridStore) => {
if (err) {
console.log(err);
}
});
res.redirect('/');
});
here is the error:
MongoError: no chunks found for file, possibly corrupt
just a small error I have to put the remove function In the jimp read function the corrected code is:
app.post('/upload', upload.single("file"), (req, res) => {
if(req.file === undefined || req.file === 0 || req.file === ""){
res.redirect("/");
}
console.log(req.file);
filename = req.file.filename;
Jimp.read( "http://localhost:3000/image/" + req.file.filename, (err, image) => {
if (err) {
console.log(err);
}
// .then(lenna => (tpl.clone().write(imgActive)))
image
.resize(500, Jimp.AUTO)
// console.log(img);
image.getBase64(Jimp.AUTO, (error1, base64Image) => {
if(error1){
console.log(error1);
}
const image1 = new Image({
image: base64Image,
User: "Avichal",
forTest: "Hindi1"
});
image1.save(function(error){
if(error){
console.log(error);
}
})
})
gfs.remove({ _id: req.file.id, root: 'uploads' }, (err, gridStore) => {
if (err) {
console.log(err);
}
res.redirect('/');
});
})
});
Related
I'm developing this server based on this tutorial, https://www.bezkoder.com/angular-12-node-js-express-mysql/ now I'm in need of add some file upload functionalities, using Multer. but each time I try to us it, I get this error:
/home/miguel/Documents/angular_projs/examples/server/node_modules/multer/lib/make-middleware.js:45
next(err)
^
TypeError: next is not a function
at done (/home/miguel/Documents/angular_projs/examples/server/node_modules/multer/lib/make-middleware.js:45:7)
when i use it here:
//File upload configuration
const maxSize = 2 * 1024 * 1024;
let storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, "/resources/static/assets/uploads/");
},
filename: (req, file, cb) => {
console.log(file.originalname);
cb(null, file.originalname);
},
});
let uploadFile = multer({
storage: storage,
limits: { fileSize: maxSize },
}).single("file");
/* ---------------------------------------------------------------------------------------------------- */
//Upload Files
exports.file_upload = async (req, res) => {
let number = req.params.number;
try {
await uploadFile(req, res);
if (req.file == undefined) {
return res.status(400).send({ message: "Please upload a file!" });
}
res.status(200).send({
message: "Uploaded the file successfully: " + req.file.originalname,
});
} catch (err) {
if (err.code == "LIMIT_FILE_SIZE") {
return res.status(500).send({
message: "File size cannot be larger than 2MB!",
});
}
res.status(500).send({
message: `Could not upload the file: ${req.file.originalname}. ${err}`,
});
}
//Check if empty
//res.status(200).json({msg:`${s03}`});
};
I've checked other tutorial and it's suppose to work
Try passing in next as a parameter.
...
exports.file_upload = async (req, res, next) => {
let number = req.params.number;
try {
await uploadFile(req, res, next);
...
I have a problem with express.js and multer when I try to upload 2 valid images and 1 example pdf to validate is all images, it will upload that two images into a folder, and then it will throw the error for pdf that is an invalid format, can I somehow validate first all images and then do the upload to folder or throw the error is something is wrong here is my code
const fileStorageEngine = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, './images');
},
filename: (req, file, cb) => {
cb(null, Date.now()+ '--' +file.originalname);
}
});
const fileFilter = (req, file, cb) => {
// Reject a file
if (file.mimetype === 'image/jpeg' || file.mimetype === 'image/jpg' || file.mimetype === 'image/png') {
cb(null, true);
} else {
req.fileValidationError = 'File type not supported';
cb(null, false);
}
};
const upload = multer({
storage: fileStorageEngine,
limits: {
fileSize: 1024 * 1024 * 5 // Accept files to 5mb only
},
fileFilter: fileFilter
});
app.post('/multiple', upload.array('images', 3), async(req, res, next) => {
try {
console.log("POST Multiple Files: ", req.files);
if (await req.fileValidationError) {
throw new Error(req.fileValidationError);
} else {
for (let i = 0; i < req.files.length; i++) {
let storeImage = await StoreImages.create({
images: req.files[i].path
});
if (!storeImage) {
throw new Error('Sorry, something went wrong while trying to upload the image!');
}
}
res.status = 200;
res.render("index", {
success: true,
message: "Your images successfully stored!"
});
}
} catch(err) {
console.log("POST Multiple Error: ", err);
res.status = 406;
return res.render('index', {
error: true,
message: err.message
})
}
});
I want to validate all uploaded files before insert to a folder, server, etc...
I found a solution by throwing the error in cb function in fileFilter function
const fileFilter = (req, file, cb) => {
// Reject a file
if(file.mimetype === 'image/jpeg' || file.mimetype === 'image/jpg' || file.mimetype === 'image/png'){
cb(null, true);
}else{
cb(new Error('File type not supported'));
}
};
For error handling multer suggest
const multer = require('multer')
const upload = multer().single('avatar')
app.post('/profile', 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.
})
})
I wrote a custom middleware for uploading different types of file.
const { check } = require("express-validator")
const multer = require('multer')
const mime = require('mime-types')
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, 'uploads/')
},
filename: function (req, file, cb) {
const filename = Date.now()+"-"+file.originalname
cb(null, filename)
}
})
const upload = multer({ storage: storage })
const uploadFile = (fieldname,filetypes,fileSize)=>{
return (req,res,next)=>{
let file = upload.single(fieldname)
file(req,res,function(err){
if (err instanceof multer.MulterError) {
req.fileError = {
param: "image",
msg: "Unable to process request"
}
return next()
} else if (filetypes.includes(mime.extension(req.file.mimetype)) === false) {
req.fileError = {
param: "image",
msg: `Only ${filetypes.toString()} allowed`
}
return next()
} else if (req.file.size > fileSize) {
req.fileError = {
param: "image",
msg: `File size should not exceed ${formatBytes(req.file.size)}`
}
return next()
}
})
}
}
course_validator = [
check("name")
.trim()
.isLength({min:3,max:100})
.withMessage("Course name should be between 3 to 100 characters")
]
app.get("/create/post",uploadFile("image",["jpeg","jpg"],122880),(req,res)=>{
const errors = validationResult(req)
if(!errors.isEmpty()){
return res.json({
status: false,
error: req.fileError ? [...errors.array(),req.fileError] : errors.array()
})
}
})
If there is no error then only I need to upload the file to uploads folder. When I upload a other than jpeg or jpg I am getting error with message that Only jpeg,jpg allowed. This is what I need. But the problem is the file is also getting uploaded to uploads folder.
For custom error messages you can go through this controller here I'm checking to file type when uploading an image and in the controller, if there is no file selected at that time I'm sending a custom message with simple if the condition after passing all if image and the products will be saved in DB
exports.postProduct = (req, res, next) => {
const title = req.body.title;
const image = req.file;
const price = req.body.price;
const description = req.body.description;
if (!image) {
return res.status(422).render("admin/add-product", {
pageTitle: "Add Product",
path: "/adminproducts",
hasError: true,
product: {
title: title,
price: price,
description: description,
},
errorMessage: "Atteched file is not an image!!!",
validationErrors: [],
});
}
const imageUrl = image.path;
const product = new Product({
title: title,
imageUrl: imageUrl,
price: price,
description: description,
userId: req.user,
});
product
.save()
.then((results) => {
console.log("Product Created Successfully");
res.redirect("/admin/products");
})
.catch((err) => {
console.log(err);
});
};
I'm trying to create a photo album app in MEVN.
The req.body.ALBUM will become the folder's name then for the req.body.DESCRIPTION is just its description.
What my code accomplished was just it can create the folder but it creates an undefined folder then save the images inside it.
NOTE: I tried to create an empty folder and change the directory to my sample folder and it can successfully save the images there.
Here is my full code that can only create the folder but not saves the images inside it rather it saves the image in the undefined folder.
router.post('/album', (req, res) => {
let sql = "INSERT INTO GALLERY SET ALBUM = ?, DESCRIPTION = ?";
let body = [req.body.ALBUM, req.body.DESCRIPTION]
myDB.query(sql, body, (error, results) => {
if (error) {
console.log(error);
} else {
let directory = `C:\\Users\\user\\Desktop\\project\\myproject\\public\\${req.body.ALBUM}`;
fse.mkdirp(directory, err => {
if (err) {
console.log(err);
} else {
console.log("Success");
}
});
const myStorage = multer.diskStorage({
destination: directory,
filename: function (req, file, cb) {
cb(null, file.originalname + path.extname(file.originalname))
}
});
const myUploads = multer({
storage: myStorage, limits: {
//10 Million
fileSize: 10e6
}
}).array('files', 15);
if (fse.exists(directory)) {
myUploads(req, res, (error) => {
if (error) {
console.log(error);
} else {
res.send("Success")
}
});
}
else {
console.log(false);
}
}
})
})
When it comes to this part, the req.body.ALBUM becomes undefined therefore the images were saved inside undefined folder.
const myStorage = multer.diskStorage({
destination: directory,
filename: function (req, file, cb) {
cb(null, file.originalname + path.extname(file.originalname))
}
});
try this
fse.mkdirp(directory, err => {
if (err) {
console.log(err);
} else {
const myStorage = multer.diskStorage({
destination: directory,
filename: function (req, file, cb) {
cb(null, file.originalname + path.extname(file.originalname))
}
});
}
});
Here you are waiting for first operation to complete
I have a dashboard that generates JSON data and saves it as a .json file. This was initially written in PHP but for various reasons we have re-written the application in node. The code below takes the post data and then should check to see if the file exists then if it does update it if not it should create the file and directory.
However it only seems to create the first file and I cannot fathom why it doesn't create the subsequent files as this post route is called once for each post.
the post method looks like this
$.ajax({
type : "POST",
url : '/save/',
dataType : 'json',
data : {
category : settings.category_id,
name : settings.campaignId,
json : JSON.stringify(settings)
}
});
I have debugged and when called all the correct file paths are passed but its almost as if the file isn't being written with the data.
During debugging using node-inspector and nodemon the code loops through all the requested new file names and gives me the error code ENOENT, so it should then follow the create file path.
If you know anything about node and the file system module and feel like helping me out that would be amazing even if it's just pointing me in the direction of some more tutorials, ... anything would be great!
-
'use strict'
const fs = require('fs');
const path = require('path');
const express = require('express');
const router = express.Router();
/* Save Data */
router.post('/', function(req, res) {
if (!(req.body.json && req.body.name && req.body.category)) {
res.sendStatus(400);
return;
}
let dir = 'public/savedData/' + req.body.category;
let filepath = dir + '/' + req.body.name + '.json';
fs.access(filepath, function(error) {
console.log(filepath);
console.log(error.code);
if (error) {
if (error.code == 'ENOENT') {
console.log(error.code);
//debugger;
// Create file since it doesn't exist
createFile(req, res, filepath);
} else {
//debugger;
console.log('access error:', error);
res.sendStatus(500);
}
} else {
//debugger;
// Update file since it already exists
updateFile(req, res, filepath);
}
});
});
function createFile(req, res, filepath) {
try {
let json = JSON.parse(req.body.json);
let output = JSON.stringify([json], null, 4);
fs.mkdir(path.dirname(filepath), function(error) {
if (error) {
if (error.code == 'EEXIST') {
updateFile(req, res, filepath);
} else {
res.sendStatus(500);
console.log('create file error :', error);
}
} else {
fs.writeFile(filepath, output, function(error) {
if (error) {
res.sendStatus(500);
console.log('write file error :', error);
} else {
res.sendStatus(200);
console.log('Data successfully saved');
}
});
}
});
} catch (error) {
res.sendStatus(500);
console.log(error);
}
}
function updateFile(req, res, filepath) {
try {
fs.readFile(filepath, 'utf-8', function(error, data) {
if (error) {
res.sendStatus(500);
console.log('update error:', error);
} else {
try {
let newJSON = JSON.parse(req.body.json);
let jsonArray = JSON.parse(data);
let output;
jsonArray.push(newJSON);
output = JSON.stringify(jsonArray, null, 4);
fs.writeFile(filepath, output, function(error) {
if (error) {
res.sendStatus(500);
console.log(error);
} else {
res.sendStatus(200);
console.log('Data successfully saved');
}
});
} catch (error) {
res.sendStatus(500);
console.log(error);
}
}
});
} catch (error) {
res.sendStatus(500);
console.log(error);
}
}
module.exports = router;
Instead of checking if the file exists, you should try to write with flags wx, which creates a file but fails if it does already exist. That way you won't be subjecting yourself to race conditions. I would also suggest the package mkdirp, which does not emit an error if the directory already exists.
router.post('/', (req, res) => {
if (!(req.body.json && req.body.name && req.body.category)) {
res.sendStatus(400);
return;
}
const dirpath = `public/savedData/${req.body.category}`;
const filepath = `${dirpath}/${req.body.name}.json`;
mkdirp(dirpath, err => {
if (err) {
console.error('mkdirp failed', err);
return res.sendStatus(500);
}
const output = JSON.stringify([JSON.parse(req.body.json)]);
fs.writeFile(filepath, output, { flags: 'wx' }, err => {
if (err) {
console.error('writeFile failed', err);
return res.sendStatus(500);
}
console.log('Data successfully saved');
res.sendStatus(200);
});
);
});
Make sure you sanitize the req.body.name and req.body.category parameters, since you could expose your filesystem to unintentional overwrites.
Thanks to #Iso this is my solution
router.post('/', (req, res) => {
if (!(req.body.json && req.body.name && req.body.category)) {
res.sendStatus(400);
return;
}
const dirpath = 'public/savedData/' + req.body.category;
const filepath = dirpath + '/' + req.body.name + '.json';
mkdirp(dirpath, err => {
if (err) {
console.error('mkdirp failed', err);
return res.sendStatus(500);
}
const output = JSON.stringify([
JSON.parse(req.body.json)
]);
fs.readFile(filepath, 'utf-8', function(error, data) {
if(error) {
fs.writeFile(filepath, output, err => {
if (err) {
console.error('writeFile failed', err);
return res.sendStatus(500);
}
console.log('Data successfully saved');
res.sendStatus(200);
});
} else {
let newJSON = JSON.parse(req.body.json);
let jsonArray = JSON.parse(data);
let output;
jsonArray.push(newJSON);
output = JSON.stringify(jsonArray, null, 4);
fs.writeFile(filepath, output, err => {
if (err) {
console.error('writeFile failed', err);
return res.sendStatus(500);
}
console.log('Data successfully saved');
res.sendStatus(200);
});
}
});
});
});