Image file upload with node and express - node.js

Hi i am trying to do an image upload with ajax.so this are my files.
//index.html
<!DOCTYPE HTML>
<html lang="en-US">
<head>
<meta charset="UTF-8">
<title>File Upload showing Upload Progress</title>
<style>
* {
font-family: Verdana;
font-size: 12px;
}
</style>
</head>
<body>
<form action="/upload" method="post" enctype="multipart/form-data" id="MyUploadForm">
<input name="ImageFile" id="imageInput" type="file" />
<input type="submit" id="submit-btn" value="Upload" />
<img src="images/ajax-loader.gif" id="loading-img" style="display:none;" alt="Please Wait"/>
</form>
<div id="output"></div>
<script type='text/javascript' src='http://code.jquery.com/jquery-1.7.1.min.js'></script>
<script type='text/javascript' src='main.js'></script>
</body>
<script type="text/javascript" src="js/jquery.form.min.js"></script>
<script type="text/javascript">
$(document).ready(function() {
var options = {
target: '#output', // target element(s) to be updated with server response
beforeSubmit: beforeSubmit, // pre-submit callback
resetForm: true // reset the form after successful submit
};
$('#MyUploadForm').submit(function() {
$(this).ajaxSubmit(options); //Ajax Submit form
// return false to prevent standard browser submit and page navigation
return false;
});
});
//function to check file size before uploading.
function beforeSubmit(){
//check whether browser fully supports all File API
if (window.File && window.FileReader && window.FileList && window.Blob)
{
if( !$('#imageInput').val()) //check empty input filed
{
$("#output").html("Are you kidding me?");
return false
}
var fsize = $('#imageInput')[0].files[0].size; //get file size
var ftype = $('#imageInput')[0].files[0].type; // get file type
//allow only valid image file types
switch(ftype)
{
case 'image/png': case 'image/gif': case 'image/jpeg': case 'image/pjpeg':
break;
default:
$("#output").html("<b>"+ftype+"</b> Unsupported file type!");
return false
}
//Allowed file size is less than 1 MB (1048576)
if(fsize>1048576)
{
$("#output").html("<b>"+fsize +"</b> Too big Image file! <br />Please reduce the size of your photo using an image editor.");
return false
}
$('#submit-btn').hide(); //hide submit button
$('#loading-img').show(); //hide submit button
$("#output").html("");
}
else
{
//Output error to older unsupported browsers that doesn't support HTML5 File API
$("#output").html("Please upgrade your browser, because your current browser lacks some new features we need!");
return false;
}
}
</script>
</html>
this is my app.js
var express = require('express'); //Express Web Server
var bodyParser = require('body-parser'); //connects bodyParsing middleware
var formidable = require('formidable');
var path = require('path'); //used for file path
var fs =require('fs-extra'); //File System-needed for renaming file etc
var app = express();
app.use(express.static(path.join(__dirname, 'public')));
app.set('views', __dirname + '/views');
app.engine('html', require('ejs').renderFile);
/* ==========================================================
bodyParser() required to allow Express to see the uploaded files
============================================================ */
app.use(bodyParser({defer: true}));
app.route('/').get(function(req,res)
{
console.log("Hello world");
res.render('index.html');
res.end('done');
});
app.post('/upload', function(req, res) {
res.send('fileinfo: ' + req.files);
});
var server = app.listen(3030, function() {
console.log('Listening on port %d', server.address().port);
});
But I am getting req.files undefined.Can anybody tell why? can anybody have solution for my scnario.Am i do everything correctly.

Here is a quotation from the express-formidable-demo page:
Currently broken due to unknown bug
But, you may parse request body explicitly:
app.post('/upload', function(req, res) {
var form = new formidable.IncomingForm();
form.parse(req, function(err, fields, files) {
console.log(files);
res.send('fileinfo: ' + files);
});
});

Related

How to handle plupload in expressjs using multer with chunking?

I am implementing a file upload using Plupload in the frontend and express nodejs in the backend with multer middleware for multipart/form upload. There is currently no example available, so this is what I got so far:
HTML frontend:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Test</title>
</head>
<ul id="filelist"></ul>
<br />
<div id="container">
<a id="browse" href="javascript:;">[Browse...]</a>
<a id="start-upload" href="javascript:;">[Start Upload]</a>
<br />
<pre id="console"></pre>
</div>
<script src="/plupload/js/plupload.full.min.js"></script>
<script type="text/javascript">
var uploader = new plupload.Uploader({
browse_button: 'browse', // this can be an id of a DOM element or the DOM element itself
url: '/upload'
});
uploader.init();
uploader.bind('FilesAdded', function(up, files) {
var html = '';
plupload.each(files, function(file) {
html += '<li id="' + file.id + '">' + file.name + ' (' + plupload.formatSize(file.size) + ') <b></b></li>';
});
document.getElementById('filelist').innerHTML += html;
});
uploader.bind('UploadProgress', function(up, file) {
document.getElementById(file.id).getElementsByTagName('b')[0].innerHTML = '<span>' + file.percent + "%</span>";
});
uploader.bind('Error', function(up, err) {
document.getElementById('console').innerHTML += "\nError #" + err.code + ": " + err.message;
});
document.getElementById('start-upload').onclick = function() {
uploader.start();
};
</script>
</html>
It basically just the plupload quickstart guide: http://www.plupload.com/docs/v2/Getting-Started
Backend using node express. I trimmed my code down to a minimum working version for use here on SO:
const path = require('path');
const express = require('express');
var multer = require('multer');
var upload = multer({ dest: 'uploads/' });
// Create express
const app = express();
app.use(express.static('public'));
app.post('/upload', upload.array('file'), function(req, res){
console.log(req.files);
})
app.listen(3000, function () {
console.log('App running...');
});
Basically, just a regular express app with multer package and serving static files.
Question:
How do I upload files using Plupload in the front-end and NodeJS (using express, multer) in the backend? It should also support chunking.
You can use the fileFilter function to validate your files before they are getting uploaded, this function enables you to validate filenames, extensions and which files should be uploaded and which should be skipped.
For, eg, Let's assume that you want the user to upload only "PDF" files, you can write a filter like this,
multer({
fileFilter: function (req, file, cb) {
if (file.mimetype !== 'application/pdf') {
req.fileValidationError = 'Only PDF files can be uploaded';
return cb(null, false, new Error('Only PDF files can be uploaded'));
}
cb(null, true);
}
});
Just in case if you want to restrict the user to upload files within certain MB, you can make use of the limits property which can be set as,
limits: { fileSize: the_file_size_which_you_want_to_allow }
And finally if you want to have a common file naming pattern in your destination directory (where the files gets uploaded) you can make use of the fileName function like this, (in the below example we are appending a hyphen and timestamp to the filename).
filename: function (req, file, cb) {
cb(null, file.fieldname + '-' + Date.now())
}
UPDATE
You can make use of the plupload node module which will take care of the express-plupload communication which you're trying to sort out.
Hope this helps!

Uploading file with express-fileupload

I am trying to upload a file with express-fileupload and am having no luck getting it to work. I can get the file (in this case an image) to 'upload' in the sense that I can get the console to show an image uploaded with the correct folder.
startup.js
router.get('/upload', function(req, res) {
res.render('upload');
});
router.post('/upload', function(req, res) {
// The name of the input field (i.e. "sampleFile") is used to retrieve the uploaded file
let startup_image = req.files.image;
// Use the mv() method to place the file somewhere on your server
startup_image.mv('/images' , function(err) {
if (err) {
console.log(err);
}
});
});
Then my html form is
<form ref='uploadForm'
id='uploadForm'
action='/upload'
method='post'
encType="multipart/form-data">
<input type="file" name="image" />
<input type='submit' value='Upload!' />
</form>
You are pointing the directory where the file would go to, but you are not giving it a file name. I would say let the user decide the file name for the client side and add it to the path.
<input name="userFileName" type="text">//userFilename Here</input>
var myFILENAME = req.body.userFilename
startup_image.mv('/images/'+myFILENAME+'.jpg', ..) //myFILENAME needs to be added here
Also please see Full Example in how to upload files with express-fileupload
UPDATE
I found solution to your problem you need to add __dirname to this line which will let the program know your current directory to your source code.
startup_image.mv(__dirname + '/images' , function(err) {..
UPDATE 2
Here is my source code, if you want you can try it with this.
my html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<form ref='uploadForm' encType="multipart/form-data" class="" action="/upload" method="post">
<input type="text" name="fileName" value=""><br>
<input type="file" name="foo" value=""><br>
<input type="submit" name="" value="upload!">
</form>
</body>
</html>
my main source
var express = require("express);
var app = express();
const fileUpload = require('express-fileupload');
//npm install ejs, express, express-fileupload
//middleware
app.use(express.static(__dirname));
app.set('view engine', 'ejs');
app.use(fileUpload());
app.get('/inputFile', function(req, res){
res.render('inputt');
});
app.post('/upload', function(req, res) {
// The name of the input field (i.e. "sampleFile") is used to retrieve the uploaded file
var startup_image = req.files.foo;
var fileName = req.body.fileName;
// Use the mv() method to place the file somewhere on your server
startup_image.mv(__dirname + '/images/' + fileName + '.jpg' , function(err) {
if(err){
console.log(err);
}else{
console.log("uploaded");
}
});
});
app.listen(7777);
using async/await style
in your server file do this
const fileUpload = require('express-fileupload');
app.use(
fileUpload({
limits: { fileSize: 50 * 1024 * 1024 },
useTempFiles: true,
// dir for windows PC
tempFileDir: path.join(__dirname, './tmp'),
}),
);
then in your controllers, do this
const file = req.files.filename;
await file.mv(file.name);
if (!file || Object.keys(req.files).length === 0) {
return res.status(400).console.error('No files were uploaded.');
}
This solution is for non ejs and exporting modules solution:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>File Upload</title>
</head>
<body>
<form ref='uploadForm' encType="multipart/form-data" class="" action="/path/to/nodejs/upload/file" method="post">
<input type="file" name="my_file"><br>
<input type="submit" name="" value="upload">
</form>
</body>
</html>
Now here is the NodeJS
const express = require("express");
const app = express();
const fileUpload = require('express-fileupload');
app.use(fileUpload({ safeFileNames: true, preserveExtension: true }))
app.post('/', function(req, res) {
// The name of the input field (i.e. "sampleFile") is used to retrieve the uploaded file
let the_file = req.files.my_file;
the_file.mv('/path/to/html/uploads/up/' + the_file.name , function(err) {
res.writeHead(200, {"Content-Type": "text/plain"});
if(err){
console.log(err);
res.write(err);
res.end();
} else {
console.log("uploaded");
res.write("upload of file "+the_file.name+" complete");
res.end();
}
});
});
module.exports = app;
You have to create folder images!
//install path module
const path = require('path');
// remaining code
let startup_image = req.files.image;
startup_image.mv(path.resolve(__dirname,'/images',startup_image.name), function(error){
//remaining code
})
this way
file.mv(path.resolve(__dirname, '../public/images', filename)

MULTER: How to let user upload a photo and add additional information (e.g. name) to post request

I have a basic multer app working here:
https://github.com/EngineeredTruth/multer
Here's the HTML
<html>
<head>
<title>File upload Node.</title>
</head>
<body>
<form id="uploadForm" enctype="multipart/form-data" action="/api/photo" method="post">
<input type="file" name="userPhoto" multiple />
<input type="submit" value="Upload Image" name="submit">
<select name="carlist" form="carform">
<option value="volvo">Volvo</option>
<option value="saab">Saab</option>
<option value="opel">Opel</option>
<option value="audi">Audi</option>
</select>
<input type="text" value="title" name="title">
</br><span id="status"></span>
</form>
</body>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery.form/3.51/jquery.form.min.js"></script>
<script>
$(document).ready(function() {
$('#uploadForm').submit(function() {
$("#status").empty().text("File is uploading...");
$(this).ajaxSubmit({
error: function(xhr) {
status('Error: ' + xhr.status);
},
success: function(response) {
console.log(response)
$("#status").empty().text(response);
}
});
return false;
});
});
</script>
</html>
Here's the Node/Express server
var express = require("express");
var bodyParser = require("body-parser");
var multer = require('multer');
var app = express();
app.use(bodyParser.json());
var storage = multer.diskStorage({
destination: function (req, file, callback) {
callback(null, './uploads');
},
filename: function (req, file, callback) {
if( file.mimetype === 'image/jpeg'){
var name = Date.now() + "." + 'jpg'
} else if (file.mimetype === 'image/png'){
var name = Date.now() + "." + 'png'
}
callback(null, name);
}
});
var limits = {
fileSize: 10000000
}
var upload = multer({ storage : storage, limits : limits }).array('userPhoto',10)
// console.log(upload());
app.get('/',function(req,res){
res.sendFile(__dirname + "/index.html");
});
app.post('/api/photo', function(req,res){
// console.log('post request: ',req);
upload(req,res,function(err) {
console.log('after upload');
//console.log(req.body);
//console.log(req.files);
if(err) {
return res.end("Error uploading file: ", err);
}
res.end("File is uploaded");
});
});
app.listen(3000,function(){
console.log("Working on port 3000");
});
Everything works and the user can upload a picture. However, I want the user to be able to title the photo and also select the type of car is in the picture by selecting one of the cars from the select (dropdown) menu.
I can't seem to find a way to access 'carlist' and 'title' from my node server where the post request is received. When I console.log 'req', I don't see carlist or title anywhere. Is there a way I can get this information to my node server from the form post action?
Taken from: https://github.com/expressjs/multer/issues/381
if your file input element is in the top of form then every data below
that gets assigned to req.body after your image is uploaded, in the
result of which body remains empty while you upload photo.. So take
file input element to very bottom of your form so that req.body will
have data from other input elements
So basically have the file input at the bottom of the form. Also req.body doesn't appear in the '/api/photo' section, but suddenly appears in the 'destination and 'filename' middleware, which is inside the upload function

Upload image to html

i'm trying to upload my image and saves it automatically to my database (mongodb). But i'm stuck with uploading the image. Here's my server.js:
var express = require("express");
var multer = require('multer');
var app = express();
var storage = multer.diskStorage({
destination: function (req, file, callback) {
callback(null, './uploads');
},
filename: function (req, file, callback) {
callback(null, file.fieldname + '-' + Date.now());
}
});
var upload = multer({ storage : storage}).single('userPhoto');
app.get('/',function(req,res){
res.sendFile(__dirname + "/index.html");
});
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");
});
});
app.listen(3000,function(){
console.log("Working on port 3000");
});
And here's my index.html:
<!DOCTYPE html>
<html>
<head>
<title>File upload Node.</title>
</head>
<body>
<form id="uploadForm"
enctype="multipart/form-data"
action="/api/photo"
method="post">
<input type="file" name="userPhoto" />
<input type="submit" value="Upload Image" name="submit">
<span id = "status"></span>
</form>
</body>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery.form/3.51/jquery.form.min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery.form/3.51/jquery.form.min.js"></script>
<script>
$(document).ready(function() {
$('#uploadForm').submit(function() {
$("#status").empty().text("File is uploading...");
$(this).ajaxSubmit({
error: function(xhr) {
status('Error: ' + xhr.status);
},
success: function(response) {
$("#status").empty().text(response);
console.log(response);
}
});
//Very important line, it disable the page refresh.
return false;
});
});
</script>
</html>
I got this error when i try to run it
POST http://localhost:8051/api/photo 404 ()
send # jquery.min.js:4
ajax # jquery.min.js:4
o # jquery.form.min.js:1
e.fn.ajaxSubmit # jquery.form.min.js:1
(anonymous function) # (index):25
dispatch # jquery.min.js:3
i # jquery.min.js:3
(index):28
Uncaught TypeError: status is not a function(…)
error # (index):28
t.error # jquery.form.min.js:1
n # jquery.min.js:2
fireWith # jquery.min.js:2
w # jquery.min.js:4
d # jquery.min.js:4
My question is, how do i fix the error and how do i save the image to mongodb? Thankyou.
You're getting an error on line 28:
status('Error: ' + xhr.status);
You probably want to change that line to:
$("#status").empty().text('Error: ' + xhr.status);
That won't fix your problem, but it should show the upload error you're getting so you can take the next step. Good luck!

How to capture streaming results with Prototype Ajax.request

High Level Overview:
I have a nodejs expressjs server that makes use of the PostgreSQL nodejs driver called pg. I have a html file served to the client browser that when you click a button invokes a expressjs route on my expressjs server. This route will select data out of a PostgreSQL database and return it to the client html file. The problem is the route emits a response for every row selected in the query to the database. All the client (html browser) gets is the first row. I can write to the nodejs console server side and get all the rows to be displayed, but obviously that does me know good on my webpage.
Question:
How do I get my client html file to write to console on the client for every row emitted out of my expressjs route /pg? My assumption was on the client that the onSuccess would be fired for every row emitted out of my expressJS route.
NodeJS\ExpressJS Server File:
var express = require('express');
var pg = require('pg');
var app = express();
var MemoryStore = express.session.MemoryStore;
var conString = "postgres://joe_user:password#localhost/dev_db";
var client = new pg.Client(conString);
client.connect();
app.get('/home', function(req,res){
res.sendfile(__dirname + '/views/index.html');
});
app.use(express.bodyParser());
app.use(express.cookieParser());
app.use
(
express.session
(
{
key: 'some-key',
secret: 'some-We1rD sEEEEEcret!',
cookie: { secure: true },
store: new MemoryStore({ reapInterval: 60000 * 10 })
}
)
);
app.use
(
function(err, req, res, next)
{
// logic
console.error(err.stack);
res.send(500, 'Something broke!');
}
);
app.get('/pg', function(req, res)
{
var query = client.query("SELECT * FROM junk_data;"); //Returns 7000 rows with 8 columns total
query.on('row', function(row)
{
res.send(row);
console.log(row);
}
);
}
);
process.on('uncaughtException', function (err) {
console.log(err);
});
app.listen(4000);
HTML File:
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Demo: dojo/request/xhr</title>
<!--<link rel="stylesheet" href="style.css" media="screen">-->
<!--<link rel="stylesheet" href="../../../resources/style/demo.css" media="screen">-->
</head>
<body>
<h1>Demo: dojo/request/xhr</h1>
<p>Click the button below to see dojo/request/xhr in action.</p>
<div>
<button id="textButton2" onclick="SubmitPGRequest();">Call Express Route For PostgreSQL</button>
<!--<input type="button" value="Submit" onclick="SubmitRequest();"/> -->
</div>
<br /><br />
<div id="resultDiv">
</div>
<!-- load dojo and provide config via data attribute -->
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/prototype/1.7/prototype.js"></script>
<script>
function SubmitPGRequest()
{
new Ajax.Request( '/pg', {
method: 'get',
onSuccess: function(response){
<!--alert(response.responseText); -->
if(response.done) {
alert('Done!');
}else {
console.log(response.responseText);}
},
onFailure: function(){
alert('ERROR');
}
});
}
</script>
<
/body>
Ok so I figured out an answer to my question.
With the nodejs pg driver you can just send all the rows in the result object once the query has completed(end) and send them in one go. Below is what I ended up having in my expressjs server route to send all rows back the client.
//fired once the function above has completed firing.
query.on('end',(result)
{
res.send(result.rows);//send all rows back to client.
}

Resources