Skip to main content

Setting Up SFTP From PHP

PHP's ftp_ssl_connect() function is for SSL-FTP, where as what I need for a client's application is SFTP. Isn't life grand! Well, it's not really too much trouble... PHP can handle that too with functions from the ssh2 PECL extension. I'm just glad I caught it early on instead of at the 11th hour. I figured though I might as well continue my previous post about setting up this project with a brief description on installing ssh2 and testing it to ensure everything is in working order.

Installation

The ssh2 extension provides bindings to libssh2 which must be installed first on the system. My target platform is CentOS 5.3, so I was able to install libssh2 and libssh2-devel via yum (using the RPMForge repository).
yum install libssh2 libssh2-devel
The ssh2 extension is available from the pecl.php.net website. There is a minor bug in the current version (0.11.0) which prevents it from compiling against PHP 5.3 so I needed to apply this patch.
wget http://remi.fedorapeople.org/ssh2-php53.patch
tar zxf ssh2-0.11.0.tgz
cd ssh2-0.11.0
patch < ../ssh2-php53.patch
I compiled and installed the extension after the code was patched.
phpize
./configure --with-ssh2
make
cp modules/ssh2.so /usr/local/php/lib/php/extensions/
Adding module=ssh2.so to php.ini and restarting Apache completed the installation. I was then ready to move on and test it to make sure it worked as it should.

Testing the Extension

Using the extension to upload and retrieve files programmatically over an SFTP connection is relatively simple. First, a secure shell connection is established with the SFTP server using ssh2_connect(), and then a login is authenticated with ssh2_auth_password(). Both functions return false if they fail:
$sess = @ssh2_connect(SFTP_SERVER, SFTP_PORT);
if ($sess === false) {
echo "Connection failed.";
exit(-1);
}
$result = @ssh2_auth_password($sess, SFTP_USERNAME,
SFTP_PASSWORD);
if ($result === false) {
echo "Unable to authenticate.";
exit(-1);
}
Once a session has been established, the ssh2_sftp() function is used to retrieve an SFTP resource.
$sftp = @ssh2_sftp($sess);
if ($sftp === false) {
echo "Unable to initialize SFTP subsystem.";
exit(-1);
}
From that point on, the SFTP resource is used with the ssh2.sftp filestream to read and write files.
file_put_contents("ssh2.sftp://" . $sftp . "/tmp/test.txt",
$data);
In writing my short automated test case, I dumped some bytes from /dev/urandom to generate a test file, wrote the data to the SFTP server, read it back, and compared the results to make sure they matched after the round-trip.
// generate random data for test file
$data = file_get_contents("/dev/urandom", FILE_BINARY, null,
0, 512);
$data = substr(convert_uuencode($data), 0, 512);

// write data to file on SFTP server
file_put_contents("ssh2.sftp://" . $sftp . "/tmp/test.txt",
$data);

// retrieve file from SFTP server
$retrieved = file_get_contents("ssh2.sftp://" . $sftp .
"/tmp/test.txt");

// compare original data with retrieve data
echo ($data == $retrieved) ? "Success!" : "Corruption!";

Comments

  1. Very cool Tim! Nice, thorough explanation. Is there a function to read the contents of the directory on the remote server?

    ReplyDelete
  2. Sure you can list the directory contents. You can use any file functions that work with wrappers.

    $files = scandir("ssh2.sftp://" . $sftp . "/home/tboronczyk");
    print_r($files);

    ReplyDelete
  3. The PECL ssh2 extension is crap. If you want SFTP support, try phpseclib:

    http://phpseclib.sourceforge.net/

    ReplyDelete
  4. Perhaps, Anonymous... but generally a user-land implemented solution is going to execute slower than an extension where the bulk of its code is compiled C. Plus, the ssh2 extension gives a handle that can be used with wrappers, giving a more consistent API. I think I'll stick with the ssh2 extension for now, but thanks for the heads up!

    ReplyDelete
  5. I agree with anonymous. PECL's solution may be faster but that extra speed isn't going to amount to much if you can't even install it.

    And as for stream wrappers... you do realize you can write your own?:

    http://php.net/stream.streamwrapper.example-1

    Personally, I think stream wrappers are overrated. Sure, you get a more consistent API, but you also get a more limited one. And, honestly, I don't think it's even as consistent as you're alleging. Check out the first (and only) example on this page:

    http://php.net/wrappers.ssh2

    They call ssh2_connect() and ssh2_auth_pubkey_file() and then pass the active handle to the stream. And yet that's consistent? Show me another stream wrapper that does that.

    ReplyDelete
  6. Who said I couldn't install the Pecl extension? ssh2 installed just fine.

    ReplyDelete
  7. I meant "you" in the generic sense. If someone (not necessarily you) can't install the Pecl extension then the speed boost one might gain from using it becomes moot.

    ReplyDelete
  8. Hi,

    I am not get working ssh2_scp_recv function. Here is my program:



    I am getting "Unable to get remote file" error. I have tried with "sftp://some_remote_server.com" and "sftp.some_remote_server.com" as $RemoteServer value, but no luck.

    For your information I am sure, I have enough read permissions at remote server and write permissions in local server.

    Can't we copy a remote file into our server without $sftp = @ssh2_sftp($sess) like function?

    Please let me know error in my code and how to fix it? Thanks in advance..

    Regards,
    N Naresh Kumar

    ReplyDelete
  9. It looks like you're forgetting the ssh. before sftp. The destination needs to be ssh2.sftp://some_remote_server.com

    ReplyDelete
  10. newbie sorry:
    what You mean when You write:
    patch < ../ssh2-php53.patch ?
    also:
    what You mean when You write:
    phpize ??
    ./configure --with-ssh2

    can You explaine better ?
    Thanks

    ReplyDelete
  11. Im a newbie.
    How am I going to set up this in xampp.

    ReplyDelete

Post a Comment

Popular posts from this blog

Writing a Minimal PSR-0 Autoloader

An excellent overview of autoloading in PHP and the PSR-0 standard was written by Hari K T over at PHPMaster.com , and it's definitely worth the read. But maybe you don't like some of the bloated, heavier autoloader offerings provided by various PHP frameworks, or maybe you just like to roll your own solutions. Is it possible to roll your own minimal loader and still be compliant? First, let's look at what PSR-0 mandates, taken directly from the standards document on GitHub : A fully-qualified namespace and class must have the following structure \<Vendor Name>\(<Namespace>\)*<Class Name> Each namespace must have a top-level namespace ("Vendor Name"). Each namespace can have as many sub-namespaces as it wishes. Each namespace separator is converted to a DIRECTORY_SEPARATOR when loading from the file system. Each "_" character in the CLASS NAME is converted to a DIRECTORY_SEPARATOR . The "_" character has no special ...

What's Wrong with OOP

Proponents of Object Oriented Programming feel the paradigm yields code that is better organized, easier to understand and maintain, and reusable. They view procedural programming code as unwieldy spaghetti and embrace OO-centric design patterns as the "right way" to do things. They argue objects are easier to grasp because they model how we view the world. If the popularity of languages like Java and C# is any indication, they may be right. But after almost 20 years of OOP in the mainstream, there's still a large portion of programmers who resist it. If objects truly model the way people think of things in the real world, then why do people have a hard time understanding and working in OOP? I suspect the problem might be the focus on objects instead of actions. If I may quote from Steve Yegge's Execution in the Kingdom of Nouns : Verbs in Javaland are responsible for all the work, but as they are held in contempt by all, no Verb is ever permitted to wander about ...

Learning Prolog

I'm not quite sure exactly I was searching for, but somehow I serendipitously stumbled upon the site learnprolognow.org a few months ago. It's the home for an introductory Prolog programming course. Logic programming offers an interesting way to think about your problems; I've been doing so much procedural and object-oriented programming in the past decade that it really took effort to think at a higher level! I found the most interesting features to be definite clause grammars (DCG), and unification. Difference lists are very powerful and Prolog's DCG syntax makes it easy to work with them. Specifying a grammar such as: s(s(NP,VP)) --> np(NP,X,Y,subject), vp(VP,X,Y). np(np(DET,NBAR,PP),X,Y,_) --> det(DET,X), nbar(NBAR,X,Y), pp(PP). np(np(DET,NBAR),X,Y,_) --> det(DET,X), nbar(NBAR,X,Y). np(np(PRO),X,Y,Z) --> pro(PRO,X,Y,Z). vp(vp(V),X,Y) --> v(V,X,Y). vp(vp(V,NP),X,Y) --> v(V,X,Y), np(NP,_,_,object). nbar(nbar(JP),X,3) --> jp(JP,X). pp(pp(PREP,N...