In today’s world with so many third-party integrations and content-sharing, it’s important to understand and make use of protocols like SCP and SFTP. PHP’s SSH2 extension, a wrapper for libssh2 which implements the SSH2 protocol, provides several functions you can use to securely transfer files.
在当今拥有如此众多的第三方集成和内容共享的世界中,理解和利用SCP和SFTP等协议非常重要。 PHP的SSH2扩展程序是libssh2的包装器,它实现了SSH2协议,它提供了一些可用于安全传输文件的功能。
To begin leveraging these functions, it’s obvious the SSH2 package needs to be installed. As it’s a PECL extension, the installation process will depend based on your operating system of choice. Follow the guidelines on php.net.
要开始利用这些功能,很明显,需要安装SSH2软件包 。 由于它是PECL扩展,因此安装过程将取决于您选择的操作系统。 遵循php.net上的准则 。
建立连接 (Establishing a Connection)
Let’s begin by connecting to an SSH service. Establishing a connection is as simple as:
让我们从连接到SSH服务开始。 建立连接非常简单:
<?php
$conn = ssh2_connect('example.com', 22);
ssh2_auth_password($conn, 'username', 'password');
Some administrators prefer using public and private keys to authenticate logins. If the service is configured and you want to connect in this way, you would use the following instead:
一些管理员更喜欢使用公钥和私钥对登录进行身份验证。 如果已配置服务,并且您想以这种方式连接,则应使用以下内容:
<?php
$conn = ssh2_connect('example.com', 22);
ssh2_auth_pubkey_file(
$conn,
'username',
'/home/username/.ssh/id_rsa.pub',
'/home/username/.ssh/id_rsa'
);
Whether you use username/password or public/private key authentication, ssh2_auth_password()
and ssh2_auth_pubkey_file()
both return a Boolean value indicating whether authentication was successful.
无论您使用用户名/密码还是公用/专用密钥身份验证, ssh2_auth_password()
和ssh2_auth_pubkey_file()
都返回一个布尔值,指示身份验证是否成功。
执行基本命令 (Performing Basic Commands)
Once you have successfully authenticated with the server, you can perform your file transfer operations. The SCP functions let you send or receive a file(s) like so:
成功通过服务器验证后,即可执行文件传输操作。 通过SCP函数,您可以像这样发送或接收文件:
<?php
// send a file
ssh2_scp_send($conn, '/local/filename', '/remote/filename', 0644);
// fetch file
ssh2_scp_recv($conn, '/remote/filename', '/local/filename');
ssh2_scp_send()
has an additional parameter which you can specify what the file permission should be on the remote server when the file is copied.
ssh2_scp_send()
有一个附加参数,您可以指定复制文件时在远程服务器上应具有的文件许可权。
More functionality is available with the SFTP functions; you can change file or directory permissions, fetch information about a file, create directories, rename items, remove items, etc. They work quite similar to the SCP functions above, but an additional connect via ssh2_sftp()
must be made prior to using the functions:
SFTP功能提供更多功能; 您可以更改文件或目录的权限,获取有关文件的信息,创建目录,重命名项目,删除项目等。它们的工作原理与上述SCP函数非常相似,但是必须在使用ssh2_sftp()
之前进行额外的连接。功能:
<?php
$sftp = ssh2_sftp($conn);
// Create a new folder
ssh2_sftp_mkdir($sftp, '/home/username/newdir');
// Rename the folder
ssh2_sftp_rename($sftp, '/home/username/newdir', '/home/username/newnamedir');
// Remove the new folder
ssh2_sftp_rmdir($sftp, '/home/username/newnamedir');
// Create a symbolic link
ssh2_sftp_symlink($sftp, '/home/username/myfile', '/var/www/myfile');
// Remove a file
ssh2_sftp_unlink($sftp, '/home/username/myfile');
ssh2_sftp()
accepts the connection resource and returns an SFTP resource which is used in future ssh2_sftp_
* calls. The calls then return a Boolean which allows you to determine whether the action was successful.
ssh2_sftp()
接受连接资源并返回一个SFTP资源,该资源将在以后的ssh2_sftp_
*调用中使用。 然后,调用将返回一个布尔值,该布尔值使您可以确定操作是否成功。
使用包装函数 (Using Wrapper Functions)
When a specific file management function doesn’t exist for SFTP or SCP, generally the core file system function will work using a stream wrapper. Below are a few examples:
当SFTP或SCP不存在特定的文件管理功能时,通常,核心文件系统功能将使用流包装器工作。 以下是一些示例:
<?php
// Create a new folder
mkdir('ssh2.sftp://' . $sftp . '/home/username/newdir');
// Remove the new folder
rmdir('ssh2.sftp://' . $sftp . '/home/username/newdir');
// Retrieve a list of files
$files = scandir('ssh2.sftp://' . $sftp . '/home/username');
Before performing any of these calls, the connection to the SSH and SFTP server must be made as it uses the previously created $sftp
variable.
在执行任何这些调用之前,必须使用先前创建的$sftp
变量建立与SSH和SFTP服务器的连接。
汇集全部 (Bring It All Together)
Now that you are able to connect, authenticate, and run commands on an SSH server, we can create a few helper classes to simplify the process of executing these commands: one for performing SCP calls and one for SFTP calls, a parent class for common functionality, and a couple classes for encapsulating authentication information (password and keys).
现在您已经能够在SSH服务器上连接,认证和运行命令,我们可以创建一些帮助程序类来简化执行这些命令的过程:一个用于执行SCP调用,一个用于SFTP调用,一个用于通用的父类。功能,以及用于封装身份验证信息(密码和密钥)的几个类。
Let’s create the authentication classes first since they will be used the other classes.
首先创建身份验证类,因为它们将用于其他类。
<?php
class SSH2Authentication
{
}
<?php
class SSH2Password extends SSH2Authentication
{
protected $username;
protected $password;
public function __construct($username, $password) {
$this->username = $username;
$this->password = $password;
}
public function getUsername() {
return $this->username;
}
public function getPassword() {
return $this->password;
}
}
<?
class SSH2Key extends SSH2Authentication
{
protected $username;
protected $publicKey;
protected $privateKey;
public function __construct($username, $publicKey, $privateKey) {
$this->username = $username;
$this->password = $password;
}
public function getUsername() {
return $this->username;
}
public function getPublicKey() {
return $this->publicKey;
}
public function getPrivateKey() {
return $this->privateKey;
}
}
SSH2Password
and SSH2Key
simply wrap their respective authentication information. They share a common base class so we can take advantage of PHP’s type hinting when we pass instances to their consumers.
SSH2Password
和SSH2Key
仅包装它们各自的身份验证信息。 它们共享一个通用的基类,因此当我们将实例传递给它们的使用者时,我们可以利用PHP的类型提示。
Moving on, let’s create an SSH2
to connect and authenticate with the SSH server.
继续,让我们创建一个SSH2
来连接SSH服务器并对其进行身份验证。
<?php
class SSH2
{
protected $conn;
public function __construct($host, SSH2Authentication $auth, $port = 22) {
$this->conn = ssh2_connect($host, $port);
switch(get_class($auth)) {
case 'SSH2Password':
$username = $auth->getUsername();
$password = $auth->getPassword();
if (ssh2_auth_password($this->conn, $username, $password) === false) {
throw new Exception('SSH2 login is invalid');
}
break;
case 'SSH2Key':
$username = $auth->getUsername();
$publicKey = $auth->getPublicKey();
$privateKey = $auth->getPrivateKey();
if (ssh2_auth_pubkey_file($this->conn, $username, $publicKey, $privateKey) === false) {
throw new Exception('SSH2 login is invalid');
}
break;
default:
throw new Exception('Unknown SSH2 login type');
}
}
}
A very simple SCP class will be created that extends SSH2
and will make use of the magic method __call()
. This allows us to do two important things: automatically prepend “ssh_scp_” to the function call and supply the connection variable to the call.
将创建一个非常简单的SCP类,该类扩展SSH2
并将使用魔术方法__call()
。 这使我们可以做两件重要的事情:在函数调用之前自动添加“ ssh_scp_”,并为该调用提供连接变量。
<?php
class SSH2SCP extends SSH2
{
public function __call($func, $args) {
$func = 'ssh2_scp_' . $func;
if (function_exists($func)) {
array_unshift($args, $this->conn);
return call_user_func_array($func, $args);
}
else {
throw new Exception(
$func . ' is not a valid SCP function');
}
}
}
The SFTP class is quite similar, although its constructor is overloaded to also execute the ssh2_sftp()
function. The results are stored in a protected variable and automatically prepended to all SFTP function calls.
SFTP类非常相似,尽管其构造函数被重载以同时执行ssh2_sftp()
函数。 结果存储在受保护的变量中,并自动添加到所有SFTP函数调用之前。
<?php
class SSH2SFTP extends SSH2 {
protected $sftp;
public function __construct($host, ISSH2Authentication $auth, $port = 22) {
parent::__construct($host, $auth, $port);
$this->sftp = ssh2_ftp($this->conn);
}
public function __call($func, $args) {
$func = 'ssh2_sftp_' . $func;
if (function_exists($func)) {
array_unshift($args, $this->sftp);
return call_user_func_array($func, $args);
}
else {
throw new Exception(
$func . ' is not a valid SFTP function');
}
}
}
Once these classes are created they can be used to execute SCP and SFTP function calls. Thanks to the useful __call
methods in both classes, we don’t need to pass the open connection or repeatedly type “ssh2_scp_” or “ssh2_ftp_” with each call.
一旦创建了这些类,就可以将它们用于执行SCP和SFTP函数调用。 由于这两个类都有有用的__call
方法,我们不需要传递打开的连接,也不必在每次调用时重复键入“ ssh2_scp_”或“ ssh2_ftp_”。
<?php
// Create SCP connection using a username and password
$scp = new SCP(
'example.com',
new SSH2Password('username', 'password')
);
// Receive a file via SCP
if ($scp->recv('remote/file', 'local/file')) {
echo 'Successfully received file';
}
// Create SFTP connection using a public/private key
$sftp = new SSH2SFTP(
'example.com',
new SSH2Key('username', 'public_key', 'private_key')
);
// Create a directory via SFTP
if ($sftp->mkdir('directory/name')) {
echo 'Successfully created directory';
}
摘要 (Summary)
Installing the SSH2 PHP extension, it provides your scripts with the ability to connect to SSH2 servers. You can either leverage the handy classes that simplify the code for performing SFTP or SCP calls, or if a specific function isn’t provided by the library, most core file system operations can be used by leveraging the SSH2 wrapper functionality.
安装SSH2 PHP扩展,它为您的脚本提供了连接到SSH2服务器的能力。 您可以利用方便的类简化执行SFTP或SCP调用的代码,或者如果库未提供特定功能,则可以利用SSH2包装器功能来使用大多数核心文件系统操作。
Image via Fotolia
图片来自Fotolia