Connect to SFTP using PHP and private key
Asked Answered
G

4

19

I have read article after article and just cannot find "the solution" that works for what I have.

I am trying to upload files via SFTP using php scripting. I have connected using CyberDuck successfully, but I need to do this programatically.

I have a .PPK file from the vendor that I used in CyberDuck. I have a username. I have the hostname. If I open the PPK file I see some Public Lines, Private Lines and Private-MAC.

Is there anyway I can access the server to do what I need to do using the information I have?

Here is the code I was playing with:

<?php if (!function_exists("ssh2_connect")) die("function ssh2_connect doesn't exist");
?>
<?php
$conn = ssh2_connect('hostname.com', 22);
echo $conn;
ssh2_auth_pubkey_file($conn,'USERNAME','/var/www/html/FILENAME.PPK');

// send a file
ssh2_scp_send($conn, '/var/www/html/FILETOSEND.TXT', 'FILETOSEND.TXT', 0644);
?>

I don't receive any errors but the file doesn't show up on the server. I can confirm that SSH2 is installed on my webhost.

Thanks for any help you can provide.

Gam answered 31/1, 2015 at 21:21 Comment(5)
I would strongly recommend to use phpseclib for what you want to achieve. It's way better than php's build in ssh2 functions and very easy to useSordid
You don't seem to know that ssh2_auth_pubkey_file expects 4 arguments and not 3. php.net/manual/en/function.ssh2-auth-pubkey-file.phpBuffon
@charlotte, I did see that which is why I assume I am having issues. Can I break apart the PPK file into the missing elements?Gam
The ppk extension indicates that the key is a PuTTY formatted private key. libssh2 only works with PKCS1 formatted private keys. phpseclib - as recommend by michael - supports both. See phpseclib.sourceforge.net/ssh/compare.html#pubkeyFundament
Have a look at andy-carter.com/blog/connecting-to-sftp-with-php it explains how to do itTsuda
S
30

The question is quite old, but as I was looking for exactly the same answer, here is what I managed to gather.

First: Change key format from .ppk to .pem

.pkk keys are PuTTY format private key.

If you want to change that to .pem format, you need to install putty-tools with:

sudo apt install putty-tools

(On a Mac, install putty package with homebrew. For Windows, I have no clue.)

Then you can change the format of the key:

puttygen privatekey.ppk -O private-openssh -o privatekey.pem

Just in case you want to extract the public key from that private key, (you won't need for the rest of that answer, but just in case) it is quite easy:

openssl rsa -in privatekey.pem -pubout > publickey.pub

Second: Login with sFTP

Now that you have the privatekey.pem, you can use phpseclib to connect via SFTP. First, install phpseclib with Composer:

composer require phpseclib/phpseclib

Then in PHP:

require "vendor/autoload.php";

use phpseclib\Crypt\RSA;
use phpseclib\Net\SFTP;

$sftp = new SFTP('sftp.server.com');

// create new RSA key
$privateKey = new RSA();

// in case that key has a password
$privateKey->setPassword('private key password');

// load the private key
$privateKey->loadKey(file_get_contents('/path/to/privatekey.pem'));

// login via sftp
if (!$sftp->login('username', $privateKey)) {
    throw new Exception('sFTP login failed');
}

// now you can list what's in here
$filesAndFolders = $sftp->nlist();

// you can change directory
$sftp->chdir('coolstuffdir');

// get a file
$sftp->get('remoteFile', 'localFile');

// create a remote new file with defined content
$sftp->put('newfile.txt', 'new file content');

// put a local file
$sftp->put('remote.txt', 'local.txt', NET_SFTP_LOCAL_FILE);

If you want more info, go to the phpseclib sFTP feature list.

Susannasusannah answered 6/12, 2017 at 14:59 Comment(2)
If you're using phpseclib you don't need to convert ppk formatted keys to pem. phpseclib has built-in support for ppk formatted keys.Fundament
if you have an error on NET_SFTP_LOCAL_FILE, try SFTP::SOURCE_LOCAL_FILEIulus
C
4

if i may share my findings based on the code sample answered by Stéphane Le Solliec, you guys have to check your phpseclib version. to check the phpseclib version by composer (windows), you just have to type in the command prompt composer require phpseclib/phpseclib, the result will show the version if installed.

If the phpseclib version is 1.0, i suggest that you modify the line $sftp = new SFTP('sftp.server.com'); into $sftp = new NET_SFTP('sftp.server.com');

If the phpseclib version is 2.0, i suggest that you modify the line $sftp->put('remote.txt', 'local.txt', NET_SFTP_LOCAL_FILE); into $sftp->put('remote.txt', 'local.txt', SFTP::SOURCE_LOCAL_FILE);.

Thank you.

Caravan answered 22/8, 2019 at 4:4 Comment(0)
G
2

You can use Flysystem sftp adaptor for php. You can use this in any framework using composer installation. Flysystem Filesystem Abstraction for PHP (PHP library).

https://flysystem.thephpleague.com/v2/docs/

install the library using command.

composer require league/flysystem-sftp:^2.0

use below code to connect with SFTP using Filesystem.

<?php
require_once('vendor/autoload.php');
use League\Flysystem\Filesystem;
use League\Flysystem\PhpseclibV2\SftpConnectionProvider;
use League\Flysystem\PhpseclibV2\SftpAdapter;
use League\Flysystem\UnixVisibility\PortableVisibilityConverter;
use League\Flysystem\DirectoryAttributes;
use League\Flysystem\FileAttributes;
$private_key='sftp_keys/new_private.ppk';

$filesystem = new Filesystem(new SftpAdapter(
    new SftpConnectionProvider(
        'host', // host (required)
        'username', // username (required)
        null, // password (optional, default: null) set to null if privateKey is used
        $private_key, // private key (optional, default: null) can be used instead of password, set to null if password is set
        null, // passphrase (optional, default: null), set to null if privateKey is not used or has no passphrase
        22, // port (optional, default: 22)
        false, // use agent (optional, default: false)
        30, // timeout (optional, default: 10)
        10, // max tries (optional, default: 4)
        null, // host fingerprint (optional, default: null),
        null // connectivity checker (must be an implementation of 'League\Flysystem\PhpseclibV2\ConnectivityChecker' to check if a connection can be established (optional, omit if you don't need some special handling for setting reliable connections)
    ),
    '/', // root path (required)
    PortableVisibilityConverter::fromArray([
        'file' => [
            'public' => 0640,
            'private' => 0604,
        ],
        'dir' => [
            'public' => 0740,
            'private' => 7604,
        ],
    ])
));
$allFiles = $filesystem->listContents('Outbound')->toArray();
$response = $filesystem->write('Outbound/info.txt', 'Hello How are you',array());
if($response){
    echo "Success";
}else echo "Error";
print_r($allFiles );
?>

Composer.json looks like

{
    "name": "league/flysystem-sftp",
    "description": "Flysystem adapter for SFTP",
    "license": "MIT",
    "authors": [
        {
            "name": "Frank de Jonge",
            "email": "[email protected]"
        }
    ],
    "require": {
        "php": ">=5.6.0",
        "league/flysystem-sftp": "^2.1",
        "phpseclib/phpseclib": "~2.0"
    },
    "require-dev": {
        "mockery/mockery": "0.9.*",
        "phpunit/phpunit": "^5.7.25"
    },
    "autoload": {
        "psr-4": {
            "League\\Flysystem\\Sftp\\": "src/"
        }
    }
}
Gee answered 13/8, 2021 at 5:19 Comment(0)
I
0

Using phpseclib version 3, you could use the SSH private key directly:

//Use version 3 of phpseclib
use phpseclib3\Crypt\PublicKeyLoader;


//Load the SSH key
$privateKey = PublicKeyLoader::loadPrivateKey(file_get_contents('your-key.pk'));

//Connect
$sftp = new SFTP('your-host');
$sftp->login('your-username', $privateKey);
Indulge answered 13/8 at 8:8 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.