Node.js: how to use the FTP protocol

Node.js allows us to use the FTP protocol in a simple but effective way.

Basically a FTP session between a client (here Node) and a server (a FTP service handled and managed by the server) takes place by sending FTP commands and waiting for the server's responses.

Unlike PHP, in Node.js there's no built-in support to the FTP protocol that instead can be achieved by installing a specific NPM package.

npm install basic-ftp --save

Now we can implement a base FTP client class that uploads files to the server and changes their permissions properly.

'use strict';

const ftp = require('basic-ftp');
const fs = require('fs');

class FTPClient {
    constructor(host = 'localhost', port = 21, username = 'anonymous', password = 'guest', secure = false) {
        this.client = new ftp.Client();
        this.settings = {
            host: host,
            port: port,
            user: username,
            password: password,
            secure: secure
        };
    }

    upload(sourcePath, remotePath, permissions) {
        let self = this;
        (async () => {
            try {
                let access = await self.client.access(self.settings);
                let upload = await self.client.upload(fs.createReadStream(sourcePath), remotePath);
                let permissions = await self.changePermissions(permissions.toString(), remotePath);
            } catch(err) {
                console.log(err);
            }
            self.client.close();
        })();
    }

    close() {
        this.client.close();
    }

    changePermissions(perms, filepath) {
        let cmd = 'SITE CHMOD ' + perms + ' ' + filepath;
        return this.client.send(cmd, false);
    }
}

module.exports = FTPClient;

After logging in to the remote host by providing our username and password, we can start to send FTP commands to the remote server.

The tricky part with FTP sessions is how we specify a path on the remote server. There are two kind of paths: relative and absolute. The relative paths don't start with a forward slash, while absolute ones do.

Let's say that a user FTP account has its home directory located under /home/username. So when we log in, our current working directory is /home/username. Then a FTP command such as:

mkdir public_html/images

will work as expected, namely creating a directory under the specified location by using a relative path.

Instead, by using:

mkdir /public_html/images

our command will be interpreted as an attempt to access a directory located just under the root filesystem directory, thus generating an error.

basic-ftp sends FTP commands through the send() command. The boolean parameter enables or disables the error output in the returned results. This module makes use of Promises, so the recommended way to use it is with the async/await model.

Example:

'use strict';

const ftp = require('./FTPClient');
const client = new ftp('192.168.1.4', 21, 'username', 'password', false);

client.upload('./upload.txt', 'public_html/upload.txt', 755);

In this case, after uploading a text file from the local current directory to the remote public_html directory, we've changed its permissions to 755. This practice can be used to avoid the default permission settings applied by the remote server.

Articles