POST multipart/form-data using file path


#1

Hello
Is there a way to do POST request with multipart/form-data without selecting the file manually by using file input, but giving already known local file path? As I’ve read - because of security measures you cannot specify the local path without using file input. Are there alternative ways to deliver the file with other form data with one request?


#2

Hi Reinis,

Did you solve this problem ? Because I had a same issue and seems to I got stuck here :pensive:


#3

Use cordova file transfer plugin:

url = “http://mysite.com/upload.php”;
filepath = "file://…/image.jpg"
var options = {
fileKey: “myImage”,
httpMethod: “POST”,
mimeType: “image/jpeg”,
params: {myDescription: “bla bla”, rating: 5},
chunkedMode: true
}

$cordovaFileTransfer.upload(url, filepath, options, true).then(function(…){…});


#4

Hi Reinis,

Thanks for your help.This way I can push image to web service but this time I cannot take params values at server side. I am using node.js and express.js based web service. All data of image can come with request but params field never came. I tried one up object (I mean req.body or req.file even req) and params at nowhere.

Which server side technology you are using and how can get params value field ?

Thanks.


#5

you can get the file via cordova file plugin and add it with the javascript FormData-API


#6

Ok, how can I combine these two things. You are saying, put form Data object to cordova file plugin params values ?


#7

nope if you are using file-transfer plugin you do not need the FormData --> but you need the valid path to the local file, which you can get via file-plugin (requestLocalFileSystem --> getFile):

//mobile upload
var ft = new FileTransfer(),
    ftOptions = new FileUploadOptions();

ftOptions.fileKey = 'file';
ftOptions.fileName = PATH.substr(params.lastIndexOf('/') + 1); // extract file name from PATH
ftOptions.mimeType = 'image/jpeg';
ftOptions.httpMethod = 'POST';

ft.upload(PATH, UPLOADURL, function (res) {
  //upload success
}, function () {
  //upload failed
}, ftOptions);

If you want to upload files via a direct POST-Request your need to create formData-object set contenttype to ‘application/x-www-form-urlencoded’. But i think this will only work on non-mobile environment


#8
//DEVICE: cordova-plugin-file-transfer // camera FILE_URI 
function win() {
   console.log("uploaded");
}
function fail() {
   console.log("not uploaded");
}

let filename = result.nativeURL.substr(result.nativeURL.lastIndexOf("/") + 1); 
let options = new FileUploadOptions();
options.fileKey = "myfile";
options.fileName = filename;
options.mimeType = "image/jpeg";

let params = {
      filename: "myfilename.jpg",
      folder: "myFolder"
};
options.params = params;

let ft = new FileTransfer();
ft.upload(result.nativeURL, "http://SERVERIP:PORT/file/upload", win, fail, options);


//BROWSER camera-api-mock for browser
private getPicture(successCallback: any, errorCallback: any, options: any): void {
   var callDialog = function(dialog, callback) {
      dialog.addEventListener("change", function() {
         callback(dialog);
      }, false);
      dialog.click();
   };
   var acceptTypes: any = ".jpg";
   var dialog = document.createElement("input");
   dialog.type = "file";
   if (angular.isArray(acceptTypes)) {
      dialog.accept = acceptTypes.join(",");
   } else if (angular.isString(acceptTypes)) {
      dialog.accept = acceptTypes;
   }
  callDialog(dialog, successCallback);
}
//and then:
let formData = new FormData();
formData.append("filename", "myVarFilename.jpg"); //filename first, otherwise req.body is empty in multer
formData.append("folder", "myFolder");
formData.append("myfile", dialog.files[0]); //dialog is the result from camera-api-mock
$http({
   url: "http://SERVERIP:PORT/file/upload", 
   method: "POST",
   data: formData,
   headers: {"Content-Type": undefined}
}).then(() => {
   console.log("success");
}).catch(() => {
   console.log("error");
});


//SERVERSIDE Nodejs/express 4 with multer
let multer = require ("multer");
let mkdirp = require ("mkdirp");
....
app.use(bodyparser.json());
app.use(bodyparser.urlencoded({extended: false}));
app.use(cors());

let imagestorage = multer.diskStorage({
  destination: (req, file, cb) => {
    let newDestination = path.resolve(__dirname, "uploads", "images", req.body.folder);
    mkdirp.sync(newDestination);
    cb (null, newDestination);
  },
  filename: (req, file, cb) => {
    let getFileExt = (fileName) => {
        var fileExt = fileName.split(".");
        if ( fileExt.length === 1 || ( fileExt[0] === "" && fileExt.length === 2 ) ) {
            return "";
        }
        return fileExt.pop();
    };
    cb(null, req.body.filename); // + "_" + Date.now() + "." + getFileExt(file.originalname));
  }
});
let multerUpload = multer({ storage: imagestorage }).single("myfile");
app.use(multerUpload);
...
app.post("file/upload", (req: any, res: any) => {
   console.log("look into uploads-folder ;-)");
   console.log(req.body); //params in here...
   console.log(req.file); //saved file information
   res.status(200).send(req.file);
});

#9

Yes U r right it will work only in non-mobile environment.


#10

Solutions to this? I’m with the same problem. Using http://ngcordova.com/docs/plugins/fileTransfer/ I get error 3


#11

hi can u please suggest me something on this below code

 this.camera.getPicture(options).then((imagePath) => {
      if (this.platform.is('android') && sourceType === this.camera.PictureSourceType.PHOTOLIBRARY) {
        this.filePath.resolveNativePath(imagePath)
          .then(filePath => {                  
            this.formData.append('general_canvas',imagePath);                 
          });
      

the below is upload

 let body: string = JSON.stringify({'formData': this.formData});
    // type: 'application/json',        
    let headers: any = new Headers({'Content-Type': 'multipart/form-data'}),
      options: any = new RequestOptions({ headers: headers }),
      url: any = this.uploadUrl;

    this.http.post(url,this.formData, options).map(res => res.json())
      .subscribe((data) => {