summaryrefslogtreecommitdiff
path: root/src/Connection.php
blob: 2cddeb478942c6d16f6eeada429f84c1b4e0432a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
<?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");
    }
}