В современном мире, где так много сторонних компонентов и программ для создания совместного доступа, важно понимать и использовать протоколы SCP и SFTP. Для PHP есть расширение-оболочка для библиотеки libssh2, которая реализует протокол SSH2. Она обеспечивает несколько функций, которые можно использовать для безопасной передачи файлов.
Перед тем как приступить к использованию этих функций, нужно установить пакет SSH2. Поскольку это PECL-компонент, процесс установки будет зависеть от вашей операционной системы. Следуйте инструкциям на php.net.
Установление соединения
Давайте начнем с подключения к службе SSH. Установление соединения выглядит просто:
$conn = ssh2_connect('example.com', 22);
ssh2_auth_password($conn, 'username', 'password');
Некоторые администраторы предпочитают использовать открытые и закрытые ключи для аутентификации входа в систему. Если вы хотите подключиться таким образом, нужно использовать следующий код:
$conn = ssh2_connect('example.com', 22);
ssh2_auth_pubkey_file(
$conn,
'username',
'/home/username/.ssh/id_rsa.pub',
'/home/username/.ssh/id_rsa'
);
Если при аутентификации вы используете имя пользователя или пароль, открытый или закрытый ключ, функции ssh2_auth_password () и ssh2_auth_pubkey_file () возвращают логическое значение, указывающее на то, была ли осуществлена проверка подлинности успешно.
Выполнение основных команд
После того как вы успешно прошли аутентификацию с сервером, вы можете совершить операцию передачи файлов. Функция SCP позволяет вам отправлять или получать файлы следующим образом:
// 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 () можно установить права доступа.
Большей функциональности можно добиться с использованием функции SFTP. Вы можете изменять права к файлу или директории, получать информацию о файле, создавать каталоги, переименовывать элементы, удалять элементы и т.д. Функция SFTP очень похожа на SCP, но дополнительное подключение через ssh2_sftp () должно быть сделано до начала использования функции:
$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 () устанавливается подключение к ресурсу, и затем все операции проходят через SFTP-соединение, которое использует вызовы различных ssh2_sftp_* функций. Вызов функции возвращает логическое значение, что позволяет определить, было ли действие успешным.
Использование функции-оболочки
Когда определенной функции управления файлами для SFTP или SCP-протокола не существует, на помощь приходит оболочка. Ниже приведено несколько примеров:
// 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');
Перед выполнением любой из этих операций соединение с сервером SSH и SFTP должно быть установлено, так как используется ранее созданная переменная $sftp.
Собираем все вместе
Теперь, когда вы научились подключаться, проверять аутентификацию и выполнять команды на сервере SSH, мы можем создать несколько вспомогательных классов для упрощения процесса выполнения этих команд: один — для выполнения SCP вызовов, один — для вызовов SFTP, родительский класс для общей функциональности и пару классов для инкапсуляции идентификационной информации (паролей и ключей).
Давайте создадим класс аутентификации первым, так как он будет использоваться другими классами:
abstract class SSH2Authentication
{
protected $connect;
protected $username;
public function setConnect($connect){
$this->connect = $connect;
}
public function authenticate(){
throw new Exception('Method "authenticate" must be defined.');
}
}
class SSH2Password extends SSH2Authentication
{
protected $password;
public function __construct($username, $password) {
$this->username = $username;
$this->password = $password;
}
public function authenticate(){
return ssh2_auth_password(
$this->connect,
$this->username,
$this->password
);
}
}
class SSH2Key extends SSH2Authentication
{
protected $publicKey;
protected $privateKey;
public function __construct($username, $publicKey, $privateKey) {
$this->username = $username;
$this->publicKey = $publicKey;
$this->privateKey = $privateKey;
}
public function authenticate($passphrase=''){
return ssh2_auth_pubkey_file(
$this->connect,
$this->username,
$this->publicKey,
$this->privateKey,
$passphrase
);
}
}
SSH2Password и SSH2Key просто оборачивают соответствующие им данные аутентификации. Они имеют общий базовый класс, поэтому мы можем воспользоваться PHP для перехода от источника к получателю.
Двигаемся дальше. Давайте создадим протокол SSH2 для подключения и аутентификации на SSH сервере.
class SSH2
{
protected $connect;
public function __construct($host, SSH2Authentication $auth, $port = 22) {
$this->connect = ssh2_connect($host, $port);
$auth->setConnect($this->connect);
if ($auth->authenticate() === false) {
throw new Exception('SSH2 login is invalid.');
}
}
}
Будет создан очень простой SCP-класс, который расширяет функционал SSH2 и использует метод __call(). Это позволяет нам сделать две важные вещи: автоматически предварять «ssh_scp_» при вызове функции и поддерживать связь с переменной.
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.');
}
}
}
Класс SFTP схож в плане конструкции, хотя и перегружен вызовом функции ssh2_sftp (). Результаты будут храниться в защищенной переменной и автоматически добавляться ко всем вызовам SFTP-функции.
class SSH2SFTP extends SSH2
{
protected $sftp;
public function __construct($host, SSH2Authentication $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.');
}
}
}
Эти классы могут быть использованы для вызова SCP- и SFTP-функций. Благодаря полезному методу __call в обоих классах нет необходимости заново открывать соединение или повторно вводить «ssh2_scp_» либо «ssh2_ftp_» при каждом вызове.
// 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';
}
Заключение
Установка расширения SSH2 для PHP нужна для того, чтобы обеспечить выполнение скриптов с возможностью подключения к SSH2-серверу. У вас есть выбор: либо опираться на удобные классы, которые упрощают код создания SFTP- или SCP-функций, либо, если конкретная функция не предусмотрена библиотекой, пользоваться функциональностью SSH2-оболочки. При этом вам доступно большинство основных операций с файловой системой.