Pro_grammer
Pro_grammer

Reputation: 356

Uploading File to FTP Server with node.js requires full directory path to file which isn't available

I am new to js/reactjs/nodejs and I am implementing a feature to allow a user to choose a file manually and upload it to a test local ftp server (in directory /test). The issue i am having is that the ftp.upload function takes a String for the full path of the file being uploaded, but I am not explicitly giving the path because the file is chosen via a "Browse files" button.

It works perfectly if I test without ftp (locally), but I can't seem to upload the file from the request onto a FTP-Server. If I add a full path to the file which I want to upload, it seems to work but that ruins the purpose of choosing a file to upload and uploading after clicking on Upload

This is the server.js

const express = require("express");
const fileUpload = require("express-fileupload");
const app = express();
var EasyFtp = require("easy-ftp");
var ftp = new EasyFtp();

app.use(fileUpload());

var config = {
  host: "127.0.0.1",
  type: "FTP",
  port: "",
  username: "admin",
  password: "",
};

ftp.connect(config);

app.post("/upload", (req, res) => {
  console.log(req.files);
  if (req.files === null) {
    return res.status(400).json({ msg: "No file was uploaded" }); //no file uploaded
  }
  const file = req.files.file;

  ftp.upload(file, "/test", function (err) {
    if (err) {
      console.log(err);
      return res.status(500).send(err);
    } else {
      console.log("finished:", res);
      res.json({ fileName: file.name, filePath: `/upload/${file.name}` });
    }
  });

  //   res.json({ fileName: file.name, filePath: `/uploads/${file.name}` });
});
  ftp.mv(
`/test/(${
  (file.tempFilePath.split("/").at(-1),
  file.name,
  function (err, newPath) {})
})`
  );

ftp.close();
const PORT = process.env.PORT || 5000;
app.listen(PORT, () => console.log(`server started on port ${PORT}`));

This is the FileUpload file

import React, { Fragment, useState } from "react";
import axios from "axios";
import Message from "./Message";
import Progress from "./Progress";

const FileUpload = () => {
  //actual file and filename should go into state because the label "Choose File" needs to be replaced with the actual filename

  const [files, setFile] = useState("");
  const [filename, setFilename] = useState("Choose File...");
  const [uploadedFiles, setUploadedFiles] = useState({});
  const [message, setMessage] = useState("");
  const [uploadPercent, setUploadPercent] = useState(0);

  const onChange = (e) => {
    setFile(e.target.files[0]);
    let x = [];
    for (let file of e.target.files) {
      x.push(file.name);
    }
    setFilename(x);
  };

  const onSubmit = async (e) => {
    e.preventDefault();
    //add the file to form data
    const formData = new FormData();
    formData.append("file", files);
    try {
      const response = await axios.post("/upload", formData, {
        headers: {
          "Content-Type": "multipart/form-data",
        },

        //progress bar for upload
        onUploadProgress: (progressEvent) => {
          setUploadPercent(
            parseInt(
              //get rid of progress bar after 10 seconds of finished upload
              Math.round((progressEvent.loaded * 100) / progressEvent.total)
            )
          );
          setTimeout(() => setUploadPercent(0), 1000);
        },
        //clear loaded percentage bar
      });
      const { fileName, filePath } = response.data;

      setUploadedFiles({ fileName, filePath });
      setMessage("File uploaded successfully");
    } catch (error) {
      if (error.response.status === 500) {
        setMessage("There was a problem with the server, please try again.");
      } else {
        setMessage(error.response.data.msg);
      }
    }
  };

  return (
    <Fragment>
      {message ? <Message msg={message} /> : null}
      <form onSubmit={onSubmit}>
        <div className="custom-file">
          <input
            type="file"
            className="custom-file-input"
            id="customFile"
            onChange={onChange}
            multiple
          />
          <label className="custom-file-label" htmlFor="customFile">
            {filename}
          </label>
        </div>
        <Progress percentage={uploadPercent} />
        <input
          type="submit"
          value="Upload"
          className="btn btn-primary btn-block mt-4"
        />
      </form>
    </Fragment>
  );
};

export default FileUpload;

Is there any way to correct this? What am I missing? If more code snippets are required please let me know!

UPDATE!!


ftp.mv not doing anything

app.post("/upload", (req, res) => {
  console.log(req.files);
  if (req.files === null) {
    return res.status(400).json({ msg: "No file was uploaded" }); //error message if no file was uploaded
  }

  const file = req.files.file;
  const tempFileName = file.tempFilePath.split("/").at(-1);

  ftp.upload(file.tempFilePath, "/test", function (err) {
    if (err) {
      console.log(err);
      return res.status(500).send(err);
    } else {
      console.log("finished:", res);
      res.json({
        fileName: file.name,
        filePath: `/uploads/${file.name}`,
      });
    }
  });
  ftp.mv(`/test/${tempFileName}`, "abc", function (err, newPath) {});
  ftp.close();
});

Upvotes: 1

Views: 4223

Answers (1)

Mike
Mike

Reputation: 342

You are sending a file to the server, you need to save it momentarily and upload it from there, start by changing your fileUpload configuration to this:

    app.use(fileUpload({
      useTempFiles : true,
      tempFileDir : '/tmp/'
    }));

Then you can upload the file by accessing its temporary file path:

app.post("/upload", (req, res) => {
  console.log(req.files);
  if (req.files === null) {
    return res.status(400).json({ msg: "No file was uploaded" }); //no file uploaded
  }
  const file = req.files.file;
  // here we access the temporary file path
  ftp.upload(file.tempFilePath, "/test", function (err) {
    if (err) {
      console.log(err);
      return res.status(500).send(err);
    } else {
      console.log("finished:", res);
      res.json({ fileName: file.name, filePath: `/upload/${file.name}` });
    }
    ftp.close();
  });

 });
});

    

Upvotes: 1

Related Questions