The principle of least knowledge and duck typing tell us what programming against interfaces is all about. One of my first challenges is to design a new transport layer for our website deployment system. The old system just allowed deployment via FTP (PEAR FTP Class). This was slow and had no good error checking.
The new system must be very stable with a strict error checking and has to support several ways of file transports (FTP, SCP/SFTP). SCP is faster then FTP and secure by nature. It’s going to be the standard way for deployment.
So I looked for a rsync/scp like pecl extension and found ssh2 developed by Sara Golemon, a well known PHP core developer. It supports PHP stream wrappers - cool!
A word about stream wrappers: You can use common file system functions like read/write/copy/dirlisting over any connection that supports the stream wrappers. Some examples are HTTP and FTP, for further info consider looking at the manual.
So I get excatly what i searched for. An abstraction layer for the deployment system without the need of userland third party libraries. The underlying architecture doesn’t matter at all. I wrote a little POC-script that copies a whole directory over an scp layer:
$session = ssh2_connect('localhost', 22);
ssh2_auth_password($session, 'xxx', 'xxx');
$sftp = ssh2_sftp($session);
$remoteDir = 'ssh2.sftp://' . $sftp;
$localDir = '/home/soenke/webs/soenke-dev/cms/webseitendaten';
$remoteDir .= '/home/soenke/tests';
$it = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($localDir), RecursiveIteratorIterator::SELF_FIRST);
$bytes = 0;
$time = microtime(true);
foreach ($it as $e) {
$remoteFile = $remoteDir . substr($e->getPathname(), strlen($localDir));
echo '.';
if ($e->isDir() && !is_dir($remoteFile)) {
mkdir($remoteFile, 0775);
}
if ($e->isFile()) {
copy($e->getPathname(), $remoteFile);
$bytes += filesize($e->getPathname());
}
}
$time = microtime(true) - $time;
echo "n";
printf('Size: %01.2f MB - time: %01.2f secs' . "n", $bytes / (1024 * 1024), $time);
Wow! That’s the whole script. The SPL helped me for copying the whole directory. And now switching to FTP? No problem, I just have to change the code that generates the destionaion directory and the following code works without any change. This is being outsourced into a Transport_Strategy Class (with _SFTP and _FTP subclasses) which is reponsible for setting up the connection.
I also tested the remote directory listing via SPL DirectoryIterator. It works but I got a warning, asked the guys from ircnet#php.de but noone had any clue, too. So I filed a bug report. But, as said before, it works though the warning.
I hope my english is not as bad so nobody understands this post *g. Comments are appreciated.


November 18th, 2006 at 23:03
That’s awesome. :) Thanks for sharing.
November 20th, 2006 at 20:43
[…] Dans son un post sur le blog NorthClick, Soenke nous parle des wrappers de streams disponibles dans php5 et de la magie qui peut transparaitre quand ils sont utilisés correctement. […]
November 21st, 2006 at 14:19
[quote]SCP is faster then FTP and …[/quote]
This seems very doubtful, with all the encryption overhead. Isn’t it the other way around? Because I’ve always experienced the exact opposite.
Nonetheless, its pretty ‘neat’. Good to see the SPL being used somewhere :)
November 21st, 2006 at 22:25
grmlock, I’ll do some benchmarks when the project is ready. I guess SCP is faster because there is no overhead with control/data channels, on the other hand I guess SCP is one level below FTP and this could be some benefit. But you’re right, encrypted connection are always slower than unencrypted. But this all has to be proven in practice.
June 19th, 2010 at 10:00
This seems very doubtful, with all the encryption overhead. Isn’t it the other way around? Because I’ve always experienced the exact opposite.