Completed
Pull Request — master (#145)
by Vitaly
02:41
created

Sftp   A

Complexity

Total Complexity 17

Size/Duplication

Total Lines 152
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 7

Test Coverage

Coverage 56.59%

Importance

Changes 0
Metric Value
wmc 17
lcom 1
cbo 7
dl 0
loc 152
ccs 30
cts 53
cp 0.5659
rs 10
c 0
b 0
f 0

7 Methods

Rating   Name   Duplication   Size   Complexity  
A setup() 0 12 3
A checkRequirements() 0 6 2
A getProtocolName() 0 4 1
B sync() 0 25 4
B login() 0 30 5
A getRemoteDirectoryList() 0 4 1
A createCollector() 0 4 1
1
<?php
2
namespace phpbu\App\Backup\Sync;
3
4
use phpbu\App\Backup\Collector;
5
use phpbu\App\Backup\Target;
6
use phpbu\App\Result;
7
use phpbu\App\Util;
8
use phpseclib;
9
10
/**
11
 * Sftp sync
12
 *
13
 * @package    phpbu
14
 * @subpackage Backup
15
 * @author     Sebastian Feldmann <[email protected]>
16
 * @copyright  Sebastian Feldmann <[email protected]>
17
 * @license    https://opensource.org/licenses/MIT The MIT License (MIT)
18
 * @link       http://phpbu.de/
19
 * @since      Class available since Release 1.0.0
20
 */
21
class Sftp extends Xtp
22
{
23
    /**
24
     * @var phpseclib\Net\SFTP
25
     */
26
    protected $sftp;
27
28
    /**
29
     * @var string
30
     */
31
    protected $privateKey;
32
33
    /**
34
     * @var string
35
     */
36
    protected $privateKeyPassword;
37
38
    /**
39
     * (non-PHPDoc)
40
     *
41
     * @see    \phpbu\App\Backup\Sync::setup()
42
     * @param  array $config
43
     * @throws \phpbu\App\Backup\Sync\Exception
44
     * @throws \phpbu\App\Exception
45
     */
46 8
    public function setup(array $config)
47
    {
48 8
        if (!Util\Arr::isSetAndNotEmptyString($config, 'password') && !Util\Arr::isSetAndNotEmptyString($config, 'private_key')) {
49 4
            throw new Exception('\'password\' or \'private_key\' must be presented');
50
        }
51 4
        parent::setup($config);
52
53 4
        $this->privateKey = Util\Arr::getValue($config, 'private_key', '');
54 4
        $this->privateKeyPassword = Util\Arr::getValue($config, 'private_key_password', '');
55
56 4
        $this->setUpClearable($config);
57 4
    }
58
59
    /**
60
     * Check for required loaded libraries or extensions.
61
     *
62
     * @throws \phpbu\App\Backup\Sync\Exception
63
     */
64 4
    protected function checkRequirements()
65
    {
66 4
        if (!class_exists('\\phpseclib\\Net\\SFTP')) {
67
            throw new Exception('phpseclib not installed - use composer to install "phpseclib/phpseclib" version 2.x');
68
        }
69 4
    }
70
71
    /**
72
     * Return implemented (*)TP protocol name.
73
     *
74
     * @return string
75
     */
76 1
    protected function getProtocolName()
77
    {
78 1
        return 'SFTP';
79
    }
80
81
    /**
82
     * (non-PHPDoc)
83
     *
84
     * @see    \phpbu\App\Backup\Sync::sync()
85
     * @param  \phpbu\App\Backup\Target $target
86
     * @param  \phpbu\App\Result        $result
87
     * @throws \phpbu\App\Backup\Sync\Exception
88
     */
89 1
    public function sync(Target $target, Result $result)
90
    {
91 1
        $this->sftp     = $this->login();
92 1
        $remoteFilename = $target->getFilename();
93 1
        $localFile      = $target->getPathname();
94
95 1
        foreach ($this->getRemoteDirectoryList() as $dir) {
96 1
            if (!$this->sftp->is_dir($dir)) {
97 1
                $result->debug(sprintf('creating remote dir \'%s\'', $dir));
98 1
                $this->sftp->mkdir($dir);
99
            }
100 1
            $result->debug(sprintf('change to remote dir \'%s\'', $dir));
101 1
            $this->sftp->chdir($dir);
102
        }
103
104 1
        $result->debug(sprintf('store file \'%s\' as \'%s\'', $localFile, $remoteFilename));
105 1
        $result->debug(sprintf('last error \'%s\'', $this->sftp->getLastSFTPError()));
106
107 1
        if (!$this->sftp->put($remoteFilename, $localFile, phpseclib\Net\SFTP::SOURCE_LOCAL_FILE)) {
108
            throw new Exception(sprintf('error uploading file: %s - %s', $localFile, $this->sftp->getLastSFTPError()));
109
        }
110
111
        // run remote cleanup
112 1
        $this->cleanup($target, $result);
113 1
    }
114
115
    /**
116
     * Create a sftp handle.
117
     *
118
     * @return \phpseclib\Net\SFTP
119
     * @throws \phpbu\App\Backup\Sync\Exception
120
     */
121
    protected function login() : phpseclib\Net\SFTP
122
    {
123
        // silence phpseclib
124
        $old  = error_reporting(0);
125
        $sftp = new phpseclib\Net\SFTP($this->host);
126
        if ($this->privateKey) {
127
            $auth = new phpseclib\Crypt\RSA();
128
            $auth->loadKey(file_get_contents($this->privateKey));
129
            if ($this->privateKeyPassword) {
130
                $auth->setPassword($this->privateKeyPassword);
131
            }
132
        } else {
133
            $auth = $this->password;
134
        }
135
        if (!$sftp->login($this->user, $auth)) {
136
            error_reporting($old);
137
            throw new Exception(
138
                sprintf(
139
                    'authentication failed for %s@%s%s',
140
                    $this->user,
141
                    $this->host,
142
                    empty($this->password) ? '' : ' with password ****'
143
                )
144
            );
145
        }
146
        // restore old error reporting
147
        error_reporting($old);
148
149
        return $sftp;
150
    }
151
152
    /**
153
     * Return list of remote directories to travers.
154
     *
155
     * @return array
156
     */
157 1
    private function getRemoteDirectoryList() : array
158
    {
159 1
        return Util\Path::getDirectoryListFromAbsolutePath($this->remotePath);
160
    }
161
162
    /**
163
     * Creates collector for SFTP
164
     *
165
     * @param \phpbu\App\Backup\Target $target
166
     * @return \phpbu\App\Backup\Collector
167
     */
168
    protected function createCollector(Target $target): Collector
169
    {
170
        return new Collector\Sftp($target, $this->sftp, $this->remotePath);
171
    }
172
}
173