file upload with multer that contains input name array - node.js

i am uploading files with multer nodejs. Everything Works fine but when input type="file" contains name="warranty[][warantycopy]" i am unable to access this file.
Below is my code in index.js:
var multer = require('multer');
var invoice_copies = '';
var storage_Copies = multer.diskStorage({
destination: function (req, file, cb) {
// console.log("fileefefef");
// console.log(file);
cb(null, 'uploads/'+file.fieldname)
},
filename: function (req, file, cb) {
invoice_copies=(file.originalname).replace(/ /g,"_")
cb(null, invoice_copies)
}
});
var uploadCopies = multer({ storage: storage_Copies })
post request contains this code
router.post('/vehicle-battery',uploadCopies.fields([{name:'invoice_copy1'},
{name:'warrantyDetails'}]), function(req, res) {
//my code
}
my jade file is :
form#formAddUser(name="addVehicle",method="post",action="/vehicle-battery",enctype="multipart/form-data")
input(type="file", name="invoice_copy1",class="form-control")
input#warrantyCard(type="text", placeholder="warranty Card Number", name="warrantyDetails[0][warrantyCardNumber]",class="form-control")
input#warrantyCardExpiry(type="text", placeholder="warranty Card Expiry in Month", name="warrantyDetails[0][warrantyCardExpiry]",class="form-control")
input#warrantyCardCopy(type="file", placeholder="warranty Card Expiry copy", name="warrantyDetails[0][warrantyCardCopy]",class="form-control")
textarea(placeholder="Particulars" name="battery_paticulars")
button#btnSubmit(type="submit",class="form-control") submit
if i am using
input#warrantyCardCopy(type="file", placeholder="warranty Card Expiry copy", name="warrantyDetails",class="form-control")
this code working fine.

From a comment above:
after working for research for so long time i solved it . I am providing my solution so that it can help someone else. i have used
router.post('/vehicle-battery',uploadCopies.any(), function(req, res) { //my code }

Related

Unable to upload file image using Ajax and Multer

While uploading a file from ajax request Multer is giving an error that is given below.
TypeError [ERR_INVALID_ARG_TYPE]: The first argument must be one of
type string or Buffer. Received type object
at rite_ (_http_outgoing.js:595:11)
// code block for multer start
var Storage = multer.diskStorage({
destination: function(req, file, callback) {
callback(null, "./uploads/posts");
},
filename: function(req, file, callback) {
callback(null, file.fieldname + "_" + Date.now() + "_" + file.originalname);
}
});
var upload = multer({
storage: Storage
}).single('imgData');
//route Ajax Rquest URL Start
router.post('/blog/saveUploadImage',urlencoderParser,(req,res)=>{
upload(req, res, function(err) {
if (err) {
return res.end({UplaodStatus:true,type:'success',text:' šŸ“· Image Uploaded Now Saving Your Data It will take just a sec.'});
}
return res.end({UplaodStatus:false,type:'error',text:' ā˜¹ Sorry There was some Problem Uploading Image '});
});
});
//route Ajax Rquest URL End
//JS code
// code for geting file
let fileUpload = document.getElementById('uploadFile').files;
//appending the file to formdata
var formData = new FormData();
formData.append('imgData', fileUpload);
//AJAX Request
$.ajax({
enctype:'multipart/form-data',
data:formData,
url:'/admin/blog/saveUploadImage',
type:'POST',
cache:false,
contentType:false,
processData:false,
timeout:10000,
});
You're passing an array of files to formData.append(...), instead you should pick just the first element from this array:
let fileUpload = document.getElementById('uploadFile').files[0];
The issue was I Imported this package ( Look Below ) because of this multer was not working.
const fileUpload = require('express-fileupload');
So I removed it now it works fine.
Thank you for ur help.
The issue was I Imported this package ( Look Below ) because of this multer was not working.
const fileUpload = require('express-fileupload');
So I removed it now it works fine.

Node: multer change destination folder for fields

I have simple multer image uploading.
// Multer settings
// STORAGE FOR USER AVATAR
var storageAvatar = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, 'public/uploads/avatars/')
},
filename: function (req, file, cb) {
cb(null, req.user.id + '.jpg')
}
})
// STORAGE FOR ARTICLE THUMBNAILS
var storageThumbnail = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, 'public/uploads/thumbnails/')
},
filename: function (req, file, cb) {
cb(null, "clanok" + '.jpg')
}
})
// SETTING UPLOAD FOLDER
var upload = multer({
storage: storageAvatar
})
// Multer BEFORE CSRF!!!
app.use(upload.fields([{
name: 'avatar',
maxCount: 1,
}, {
name: 'thumbnail',
maxCount: 1,
}]));
my problem is that i am unable to set different folder for avatars and thumbnails. I can set only one folder for both :/ Anything else i tried ends with invalid CSRF. Thanks for anny suggestions.
EDIT: in one form i am using only one thing. So for example in profile update i have only possibility to change avatar in article adding i have only ability to change thumbnail of article. They not need to bey in upload fields can be seperate but dont know how.
I found on forum way how to go over csrf problem by adding ?_csrf={{csrfToken}} to the end of action in form so i can use official way of using multer :)

How to upload images to GCS bucket with multer and NodeJS?

I'm facing issues for uploading local images to my google cloud storage.
I've already tried two methods. The first one is uploading with multer
var storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, './uploads/')
},
filename: (req, file, cb) => {
cb(null, file.fieldname + '-' + Date.now())
}
});
var upload = multer({storage: storage}).single('image');
app.post('/upload',function(req,res,next){
upload(req,res,(err) => {
if(err){
console.log(err)
}else{
console.log(req.file)
}
})
})
Then, i've tried directly with GCS
var bucket = admin.storage().bucket('mybucket')
app.post('/upload',function(req,res,next){
bucket
.save(file)
.then(() => {
})
for both of these solutions , req.files is always undefined whereas req.body is a buffer like this :
<Buffer 2d 2d 2d 2d ...>
when i try to save this buffer on my GCS bucket, i the .jpg/png file is created in my bucket but it is corrupted.
I'm browsing the web seeking for a solution but i found nothing that helped me to overcome this situation.
Any advice ?
You need multer, multer-google-storage and ofcourse bodyParser if you have additional form values. You need to sent data in multipart/form-data
In your .env file
GCS_BUCKET = <bucket name>
GCLOUD_PROJECT = <project id>
GCS_KEYFILE = <key file location>
You can download key file from GCP Console>Your Project>I AM & Admin>Service Accounts
In your route
const multer = require('multer');
const multerGoogleStorage = require("multer-google-storage");
var uploadHandler = multer({
storage: multerGoogleStorage.storageEngine()
});
router.post('/', uploadHandler.single('image'), function (req, res, next) {
const body = req.body;
res.json({fileName: req.file.filename});
res.end();
}
This will store file on to GCS with name [random-string-generated-by-gcs]_[YOUR FILE NAME WITH EXTENTION]. The same can be access under the route via req.file.filename.
Documentation
Make sure you have added enctype="multipart/form-data" attribute to your form. A probable reason for req.files being undefined.

Multer isn't saving to specified destination

I'm fairly new to nodejs/ express, but no matter what I seem to do I cant seem to get multer to save to the specified destination, it seems to completely ignore the parameter all together. The code is shown below
//app.js
var multer = require('multer');
var fs = require('fs');
var apiRouter = express.Router();
var app = express();
var store = multer.diskStorage({
filename: function(req,file,cb){
console.log("filename");
cb(null, Date.now()+'.'+file.originalname);
},
desitnation: function(req,file,cb){
console.log("storage");
cb(null,'./public/');
}
});
var upload = multer({storage:store}).single('file');
apiRouter.post('/upload', function(req, res){
upload(req, res, function (err) {
if (err) {
return res.end(err.toString());
}
console.log(req.file);
return res.json({originalname:req.file.originalname, uploadname:req.file.filename});
});
});
The response I get when uploading is shown below:
GET /vendor.js.map 200 3.916 ms - 6636755
filename
{ fieldname: 'file',
originalname: 'Desert.jpg',
encoding: '7bit',
mimetype: 'image/jpeg',
destination: 'C:\\Users\\Dwyer\\AppData\\Local\\Temp',
filename: '1538979138829.Desert.jpg',
path:
'C:\\Users\\Dwyer\\AppData\\Local\\Temp\\1538979138829.Desert.jpg',
size: 845941 }
POST /api/upload 200 70.031 ms - 69
It seems to be setting the file correctly, but I'm not sure where it gets the destination from, no3 do I understand why the destination parameter isn't being read.
Its actually "destination" (not desitnation). You should also make sure that you have a folder ,with the specified name, at the specified destination.
Do you try using physical address in destination? I guess destination in multer document is physical address in linux os.
but no matter what I seem to do I cant seem to get multer to save to the specified destination, it seems to completely ignore the parameter all together.
This is because there seem to be a typo in the configuration.
'use strict';
var store = multer.diskStorage({
filename: function (req, file, cb) {
console.log("filename");
cb(null, Date.now() + '.' + file.originalname);
},
destination: function (req, file, cb) { // it is destination not desitnation :)
console.log("storage");
cb(null, './public/');
}
});

Combine multer and tinypng API in node

does anyone know how to use tinyPNG's API with multer? The docs seem deceptively simple:
var source = tinify.fromFile("unoptimized.jpg");
source.toFile("optimized.jpg");
though there's no clear indication of where this is meant to go, especially in something as convoluted as this:
var storage = multer.diskStorage(
{
destination: function (req, file, callback) {
callback(null, './uploads');
},
filename: function (req, file, callback) {
//use date to guarantee name uniqueness
callback(null, file.originalname + '-' + Date.now());
}
}
);
//.any() allows multiple file uploads
var upload = multer({ storage : storage}).any()
app.post('/api/photo', function(req,res){
upload(req,res,function(err) {
if(err) {
return res.end("Error uploading file.");
}
res.end("File is uploaded");
});
});
Where am I meant to "intercept" the file uploaded by multer so that I can compress it with tinyPNG?
Thanks in advance for the help!
Use following basic sample that changes uploaded photo/gallery files:
// Import express and multer.
var express = require('express');
var multer = require('multer');
// Setup upload.
var upload = multer({ dest: 'uploads/' });
var multipleFiles = upload.fields([{ name: 'photo', maxCount: 1 },
{ name: 'gallery', maxCount: 8 }]);
// Setup tinify.
var tinify = require("tinify");
tinify.key = "YOUR_API_KEY";
// Get request handler for '/' path.
var app = express();
app.get('/', function (req, res) {
res.setHeader("Content-Type", "text/html");
res.end(
"<form action='/api/photo' method='post' enctype='multipart/form-data'>" +
"<input type='file' name='photo' />" +
"<input type='file' name='gallery' multiple/>" +
"<input type='submit' />" +
"</form>"
);
});
// Upload file handler with '/api/photo' path.
app.post('/api/photo', multipleFiles, function (req, res) {
req.files['gallery'].forEach(function(file) {
// Your logic with tinify here.
var source = tinify.fromFile(file.path);
source.toFile(file.path + "_optimized.jpg");
});
res.end("UPLOAD COMPLETED!");
});
Feel free to change express middleware how you need it, just make sure you use upload.fields and authenticate using tinify.key = "YOUR_API_KEY";
https://github.com/expressjs/multer
https://tinypng.com/developers/reference/nodejs#compressing-images
I recently worked out a similar problem for myself using the tinify package and found the docs to be somewhat lacking.
I have a Vue front end collecting file uploads from the user using vue2dropzone. These are sent to a node / Express back end.
I have a need to compress the file and upload it to an S3 instance without storing on disk. That means using multer memory storage.
As a result there wonā€™t be an ability to use tinify.fromFile() as there is no file stored locally.
In my images middleware:
Const multer = require(ā€œmulterā€);
const tinify = require("tinify");
tinify.key = "your_key";
exports.singleFile = multer({ storage: multer.memoryStorage() }).fields([{ name: "file", maxCount: 1 }]);
exports.uploadCompImage = async (req, res, next) => {
try {
const fileName = `${req.params.name}${path.extname(req.files.file[0].originalname)}`;
const source = tinify.fromBuffer(req.files.file[0].buffer);
source.store({
service: "s3",
aws_access_key_id: "your_id",
aws_secret_access_key: "your_key
region: "your_region",
headers: {
"Cache-Control": "public"
},
path: `your_bucket/your_folder/${fileName}`
});
return res.status(200).send(`path_to_file/${fileName}`)
} catch (err) {
console.log(err);
next(err);
}
}
Then in my routes file:
Const images = require(ā€œ../middleware/imagesā€);
// skipped several lines for brevity
productRouter
.route("/images/:name")
.post(images.singleFile, images.uploadCompImage)
This process creates a multer singleFile upload to memoryStorage, making the file available at req.files.file[0] (req.files[ā€œfileā€] because I specified ā€œfileā€ as the name in multer fields, loop through this array if uploading multiple).
After setting that up I get the file name, set the source by using tinify to read from req.files.file[0].buffer as a buffer.
Then I set the source to my s3 instance and send back a public link to the file.
Hopefully this answer helps you. I could definitely see altering the process to change where the file goes or even write it to disk by altering the multer options.

Resources