<?php namespace PHPIAC; use phpseclib3\Crypt\PublicKeyLoader; use phpseclib3\Net\SFTP; use phpseclib3\Net\SSH2; /** * Class Connection * * @method static string exec(string $command, callback $callback = null) * @method static string|bool|null read(string $expect = '', int $read = 1) * @method static bool write(string $cmd) * @method static enablePty() * @method static disablePty() */ class Connection { private static SSH2 $ssh; private static SFTP $sftp; private static string $host; private static string $user; private static mixed $key; /** * Connection constructor. * * @param string $host * @param string $user * @param string $keyFile * * @throws \Exception */ public static function initialize(string $host, string $user, string $keyFile) { self::$host = $host; self::$user = $user; self::$key = PublicKeyLoader::load(file_get_contents($keyFile)); self::connect(); } /** * @throws \Exception */ private static function connect() { self::$ssh = new SSH2(self::$host); if (! self::$ssh->login(self::$user, self::$key)) { throw new \Exception('SSH Login failed'); } self::$sftp = new SFTP(self::$host); if (! self::$sftp->login(self::$user, self::$key)) { throw new \Exception('SFTP Login failed'); } } /** * @throws \Exception */ private static function ensureConnection() { if (! self::$ssh->isConnected() || ! self::$sftp->isConnected()) { self::connect(); } } /** * Calls SSH2 methods statically * * @param string $name * @param array $arguments * * @return mixed */ public static function __callStatic(string $name, array $arguments): mixed { self::ensureConnection(); if (! method_exists(self::$ssh, $name)) { return self::$sftp->$name(...$arguments); } return self::$ssh->$name(...$arguments); } /** * @see SFTP::put */ public static function put($remote_file, $data, $mode = SFTP::SOURCE_STRING, $start = -1, $local_start = -1, $progressCallback = null): bool { self::ensureConnection(); $tmp = bin2hex(random_bytes(10)); # work around sftp sudo put restrictions return self::$sftp->put("/tmp/$tmp", $data, $mode, $start, $local_start, $progressCallback) && self::$ssh->exec("sudo mv /tmp/$tmp $remote_file"); } }