Fetching from SFTP with Phpseclib

I recently had a customer who needed to fetch and import files from a remote SFTP server on a scheduled basis. The import process was handled nicely by WP All Import, so no need to do any custom code there. The only part missing the was actual SFTP fetching. Here is how I accomplish using Phpseclib within a WordPress plugin. First, I’ll start by generating a new WordPress plugin from wppb.me. Let’s call it SFTP Fetcher.

Install and activate the new plugin. Within the newly generated plugin we’ll use composer to add the phpseclib library. Add a composer.json file to the plugin folder with the following.

{
    "require": {
        "phpseclib/phpseclib": "~2.0"
    }
}

Next, tell composer to install the package.

cd wp-content/plugins/sftp-fetcher
composer install

Within the main sftp-fetcher.php file, let’s add a few required files. The first will hook into composer’s autoloading and the second file will be where we write custom code.

require __DIR__ . '/vendor/autoload.php';
require __DIR__ . '/app/Fetcher.php';

The remote SFTP credentials need to be stored safely somewhere. We can add them to the wp_options table directly via WP-CLI like so.

update_site_option( 'sftp_fetcher_credentials', array( "address" => "XXXXXXX", "username" => "XXXXXX", "password" => "XXXXXX" ) );

Add a file app/Fetcher.php with the following code.

<?php

use phpseclib\Net\SFTP;

function sftp_fetch() {

    $credentials      = (object) get_site_option( 'sftp_fetcher_credentials' );
    $upload_directory = wp_get_upload_dir()['basedir'] . "/wpallimport/files";

    $sftp = new SFTP( $credentials->address );
    if ( ! $sftp->login( $credentials->username, $credentials->password ) ) {
        exit('Login Failed');
    }

    // Check for upload directory
    if ( ! file_exists( $upload_directory ) ) {
        mkdir( $upload_directory, 0777, true);
    }

    // Fetch files
    $content_file_1   = $sftp->get( 'file_1.xml' );

    // Store copy locally
    echo "Downloading file_1.xml to {$upload_directory}/file_1.xml\n";
    $sftp->get( 'file_1.xml', "{$upload_directory}/file_1.xml");

    // Trigger WP All Import
    $response = wp_remote_get( home_url(). '/wp-load.php?import_key=########&import_id=###&action=trigger' );

    // Check the response code
    $response_code    = wp_remote_retrieve_response_code( $response );
    $response_message = wp_remote_retrieve_response_message( $response );

    if ( 200 != $response_code && ! empty( $response_message ) ) {
		echo "Error code: $response_code message: $response_message\n";
	} elseif ( 200 != $response_code ) {
		echo "Error code: $response_code\n";
	} else {
		echo wp_remote_retrieve_body( $response );
    }
    
    $response = wp_remote_get( home_url(). '/wp-load.php?import_key=########&import_id=###&action=processing' );
    
    // Check the response code
	$response_code    = wp_remote_retrieve_response_code( $response );
    $response_message = wp_remote_retrieve_response_message( $response );

    if ( 200 != $response_code && ! empty( $response_message ) ) {
		echo "Error code: $response_code message: $response_message\n";
	} elseif ( 200 != $response_code ) {
		echo "Error code: $response_code\n";
	} else {
		echo wp_remote_retrieve_body( $response );
    }

}

Within WP All Import select “Manage Imports” then “Scheduling Options” next to saved imports. That will reveal special URLs which can be used to trigger and start processing each import task. These links will need to be inserted in the code above.

Within the import settings for the import job, simply have it import a local file.

The last part is to schedule this to run on a daily basis. That can be handled with the WP Crontrol plugin. Simply add it as a PHP cron event as shown here.

And that’s it. Each day Phpseclib will connect to a remote SFTP server, download a file locally, and trigger WP All Import to run. 😅