author | ymh <ymh.work@gmail.com> |
Mon, 14 Oct 2019 17:39:30 +0200 | |
changeset 7 | cf61fcea0001 |
parent 5 | 5e2f62d02dcd |
child 9 | 177826044cd9 |
permissions | -rw-r--r-- |
0 | 1 |
<?php |
2 |
/** |
|
3 |
* WordPress Filesystem Class for implementing SSH2 |
|
4 |
* |
|
5 |
* To use this class you must follow these steps for PHP 5.2.6+ |
|
6 |
* |
|
7 |
* @contrib http://kevin.vanzonneveld.net/techblog/article/make_ssh_connections_with_php/ - Installation Notes |
|
8 |
* |
|
9 |
* Complie libssh2 (Note: Only 0.14 is officaly working with PHP 5.2.6+ right now, But many users have found the latest versions work) |
|
10 |
* |
|
11 |
* cd /usr/src |
|
12 |
* wget http://surfnet.dl.sourceforge.net/sourceforge/libssh2/libssh2-0.14.tar.gz |
|
13 |
* tar -zxvf libssh2-0.14.tar.gz |
|
14 |
* cd libssh2-0.14/ |
|
15 |
* ./configure |
|
16 |
* make all install |
|
17 |
* |
|
18 |
* Note: Do not leave the directory yet! |
|
19 |
* |
|
20 |
* Enter: pecl install -f ssh2 |
|
21 |
* |
|
22 |
* Copy the ssh.so file it creates to your PHP Module Directory. |
|
23 |
* Open up your PHP.INI file and look for where extensions are placed. |
|
24 |
* Add in your PHP.ini file: extension=ssh2.so |
|
25 |
* |
|
26 |
* Restart Apache! |
|
27 |
* Check phpinfo() streams to confirm that: ssh2.shell, ssh2.exec, ssh2.tunnel, ssh2.scp, ssh2.sftp exist. |
|
28 |
* |
|
29 |
* Note: as of WordPress 2.8, This utilises the PHP5+ function 'stream_get_contents' |
|
30 |
* |
|
31 |
* @since 2.7.0 |
|
32 |
* |
|
33 |
* @package WordPress |
|
34 |
* @subpackage Filesystem |
|
35 |
*/ |
|
36 |
class WP_Filesystem_SSH2 extends WP_Filesystem_Base { |
|
37 |
||
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
38 |
/** |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
39 |
*/ |
5 | 40 |
public $link = false; |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
41 |
|
5 | 42 |
/** |
43 |
* @var resource |
|
44 |
*/ |
|
45 |
public $sftp_link; |
|
46 |
public $keys = false; |
|
0 | 47 |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
48 |
/** |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
49 |
* |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
50 |
* @param array $opt |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
51 |
*/ |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
52 |
public function __construct( $opt = '' ) { |
0 | 53 |
$this->method = 'ssh2'; |
54 |
$this->errors = new WP_Error(); |
|
55 |
||
56 |
//Check if possible to use ssh2 functions. |
|
57 |
if ( ! extension_loaded('ssh2') ) { |
|
58 |
$this->errors->add('no_ssh2_ext', __('The ssh2 PHP extension is not available')); |
|
5 | 59 |
return; |
0 | 60 |
} |
61 |
if ( !function_exists('stream_get_contents') ) { |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
62 |
$this->errors->add( |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
63 |
'ssh2_php_requirement', |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
64 |
sprintf( |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
65 |
/* translators: %s: stream_get_contents() */ |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
66 |
__( 'The ssh2 PHP extension is available, however, we require the PHP5 function %s' ), |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
67 |
'<code>stream_get_contents()</code>' |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
68 |
) |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
69 |
); |
5 | 70 |
return; |
0 | 71 |
} |
72 |
||
73 |
// Set defaults: |
|
74 |
if ( empty($opt['port']) ) |
|
75 |
$this->options['port'] = 22; |
|
76 |
else |
|
77 |
$this->options['port'] = $opt['port']; |
|
78 |
||
79 |
if ( empty($opt['hostname']) ) |
|
80 |
$this->errors->add('empty_hostname', __('SSH2 hostname is required')); |
|
81 |
else |
|
82 |
$this->options['hostname'] = $opt['hostname']; |
|
83 |
||
84 |
// Check if the options provided are OK. |
|
85 |
if ( !empty ($opt['public_key']) && !empty ($opt['private_key']) ) { |
|
86 |
$this->options['public_key'] = $opt['public_key']; |
|
87 |
$this->options['private_key'] = $opt['private_key']; |
|
88 |
||
89 |
$this->options['hostkey'] = array('hostkey' => 'ssh-rsa'); |
|
90 |
||
91 |
$this->keys = true; |
|
92 |
} elseif ( empty ($opt['username']) ) { |
|
93 |
$this->errors->add('empty_username', __('SSH2 username is required')); |
|
94 |
} |
|
95 |
||
96 |
if ( !empty($opt['username']) ) |
|
97 |
$this->options['username'] = $opt['username']; |
|
98 |
||
99 |
if ( empty ($opt['password']) ) { |
|
5 | 100 |
// Password can be blank if we are using keys. |
101 |
if ( !$this->keys ) |
|
0 | 102 |
$this->errors->add('empty_password', __('SSH2 password is required')); |
103 |
} else { |
|
104 |
$this->options['password'] = $opt['password']; |
|
105 |
} |
|
106 |
} |
|
107 |
||
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
108 |
/** |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
109 |
* |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
110 |
* @return bool |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
111 |
*/ |
5 | 112 |
public function connect() { |
0 | 113 |
if ( ! $this->keys ) { |
114 |
$this->link = @ssh2_connect($this->options['hostname'], $this->options['port']); |
|
115 |
} else { |
|
116 |
$this->link = @ssh2_connect($this->options['hostname'], $this->options['port'], $this->options['hostkey']); |
|
117 |
} |
|
118 |
||
119 |
if ( ! $this->link ) { |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
120 |
$this->errors->add( 'connect', |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
121 |
/* translators: %s: hostname:port */ |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
122 |
sprintf( __( 'Failed to connect to SSH2 Server %s' ), |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
123 |
$this->options['hostname'] . ':' . $this->options['port'] |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
124 |
) |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
125 |
); |
0 | 126 |
return false; |
127 |
} |
|
128 |
||
129 |
if ( !$this->keys ) { |
|
130 |
if ( ! @ssh2_auth_password($this->link, $this->options['username'], $this->options['password']) ) { |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
131 |
$this->errors->add( 'auth', |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
132 |
/* translators: %s: username */ |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
133 |
sprintf( __( 'Username/Password incorrect for %s' ), |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
134 |
$this->options['username'] |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
135 |
) |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
136 |
); |
0 | 137 |
return false; |
138 |
} |
|
139 |
} else { |
|
140 |
if ( ! @ssh2_auth_pubkey_file($this->link, $this->options['username'], $this->options['public_key'], $this->options['private_key'], $this->options['password'] ) ) { |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
141 |
$this->errors->add( 'auth', |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
142 |
/* translators: %s: username */ |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
143 |
sprintf( __( 'Public and Private keys incorrect for %s' ), |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
144 |
$this->options['username'] |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
145 |
) |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
146 |
); |
0 | 147 |
return false; |
148 |
} |
|
149 |
} |
|
150 |
||
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
151 |
$this->sftp_link = ssh2_sftp( $this->link ); |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
152 |
if ( ! $this->sftp_link ) { |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
153 |
$this->errors->add( 'connect', |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
154 |
/* translators: %s: hostname:port */ |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
155 |
sprintf( __( 'Failed to initialize a SFTP subsystem session with the SSH2 Server %s' ), |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
156 |
$this->options['hostname'] . ':' . $this->options['port'] |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
157 |
) |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
158 |
); |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
159 |
return false; |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
160 |
} |
0 | 161 |
|
162 |
return true; |
|
163 |
} |
|
164 |
||
5 | 165 |
/** |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
166 |
* Gets the ssh2.sftp PHP stream wrapper path to open for the given file. |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
167 |
* |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
168 |
* This method also works around a PHP bug where the root directory (/) cannot |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
169 |
* be opened by PHP functions, causing a false failure. In order to work around |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
170 |
* this, the path is converted to /./ which is semantically the same as / |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
171 |
* See https://bugs.php.net/bug.php?id=64169 for more details. |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
172 |
* |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
173 |
* |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
174 |
* @since 4.4.0 |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
175 |
* |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
176 |
* @param string $path The File/Directory path on the remote server to return |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
177 |
* @return string The ssh2.sftp:// wrapped path to use. |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
178 |
*/ |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
179 |
public function sftp_path( $path ) { |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
180 |
if ( '/' === $path ) { |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
181 |
$path = '/./'; |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
182 |
} |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
183 |
return 'ssh2.sftp://' . $this->sftp_link . '/' . ltrim( $path, '/' ); |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
184 |
} |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
185 |
|
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
186 |
/** |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
187 |
* |
5 | 188 |
* @param string $command |
189 |
* @param bool $returnbool |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
190 |
* @return bool|string True on success, false on failure. String if the command was executed, `$returnbool` |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
191 |
* is false (default), and data from the resulting stream was retrieved. |
5 | 192 |
*/ |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
193 |
public function run_command( $command, $returnbool = false ) { |
0 | 194 |
if ( ! $this->link ) |
195 |
return false; |
|
196 |
||
197 |
if ( ! ($stream = ssh2_exec($this->link, $command)) ) { |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
198 |
$this->errors->add( 'command', |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
199 |
/* translators: %s: command */ |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
200 |
sprintf( __( 'Unable to perform command: %s'), |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
201 |
$command |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
202 |
) |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
203 |
); |
0 | 204 |
} else { |
205 |
stream_set_blocking( $stream, true ); |
|
206 |
stream_set_timeout( $stream, FS_TIMEOUT ); |
|
207 |
$data = stream_get_contents( $stream ); |
|
208 |
fclose( $stream ); |
|
209 |
||
210 |
if ( $returnbool ) |
|
211 |
return ( $data === false ) ? false : '' != trim($data); |
|
212 |
else |
|
213 |
return $data; |
|
214 |
} |
|
215 |
return false; |
|
216 |
} |
|
217 |
||
5 | 218 |
/** |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
219 |
* |
5 | 220 |
* @param string $file |
221 |
* @return string|false |
|
222 |
*/ |
|
223 |
public function get_contents( $file ) { |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
224 |
return file_get_contents( $this->sftp_path( $file ) ); |
0 | 225 |
} |
226 |
||
5 | 227 |
/** |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
228 |
* |
5 | 229 |
* @param string $file |
230 |
* @return array |
|
231 |
*/ |
|
232 |
public function get_contents_array($file) { |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
233 |
return file( $this->sftp_path( $file ) ); |
0 | 234 |
} |
235 |
||
5 | 236 |
/** |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
237 |
* |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
238 |
* @param string $file |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
239 |
* @param string $contents |
5 | 240 |
* @param bool|int $mode |
241 |
* @return bool |
|
242 |
*/ |
|
243 |
public function put_contents($file, $contents, $mode = false ) { |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
244 |
$ret = file_put_contents( $this->sftp_path( $file ), $contents ); |
0 | 245 |
|
246 |
if ( $ret !== strlen( $contents ) ) |
|
247 |
return false; |
|
248 |
||
249 |
$this->chmod($file, $mode); |
|
250 |
||
251 |
return true; |
|
252 |
} |
|
253 |
||
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
254 |
/** |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
255 |
* |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
256 |
* @return bool |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
257 |
*/ |
5 | 258 |
public function cwd() { |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
259 |
$cwd = ssh2_sftp_realpath( $this->sftp_link, '.' ); |
5 | 260 |
if ( $cwd ) { |
261 |
$cwd = trailingslashit( trim( $cwd ) ); |
|
262 |
} |
|
0 | 263 |
return $cwd; |
264 |
} |
|
265 |
||
5 | 266 |
/** |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
267 |
* |
5 | 268 |
* @param string $dir |
269 |
* @return bool|string |
|
270 |
*/ |
|
271 |
public function chdir($dir) { |
|
0 | 272 |
return $this->run_command('cd ' . $dir, true); |
273 |
} |
|
274 |
||
5 | 275 |
/** |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
276 |
* |
5 | 277 |
* @param string $file |
278 |
* @param string $group |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
279 |
* @param bool $recursive |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
280 |
* |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
281 |
* @return bool |
5 | 282 |
*/ |
283 |
public function chgrp($file, $group, $recursive = false ) { |
|
0 | 284 |
if ( ! $this->exists($file) ) |
285 |
return false; |
|
286 |
if ( ! $recursive || ! $this->is_dir($file) ) |
|
287 |
return $this->run_command(sprintf('chgrp %s %s', escapeshellarg($group), escapeshellarg($file)), true); |
|
288 |
return $this->run_command(sprintf('chgrp -R %s %s', escapeshellarg($group), escapeshellarg($file)), true); |
|
289 |
} |
|
290 |
||
5 | 291 |
/** |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
292 |
* |
5 | 293 |
* @param string $file |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
294 |
* @param int $mode |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
295 |
* @param bool $recursive |
5 | 296 |
* @return bool|string |
297 |
*/ |
|
298 |
public function chmod($file, $mode = false, $recursive = false) { |
|
0 | 299 |
if ( ! $this->exists($file) ) |
300 |
return false; |
|
301 |
||
302 |
if ( ! $mode ) { |
|
303 |
if ( $this->is_file($file) ) |
|
304 |
$mode = FS_CHMOD_FILE; |
|
305 |
elseif ( $this->is_dir($file) ) |
|
306 |
$mode = FS_CHMOD_DIR; |
|
307 |
else |
|
308 |
return false; |
|
309 |
} |
|
310 |
||
311 |
if ( ! $recursive || ! $this->is_dir($file) ) |
|
312 |
return $this->run_command(sprintf('chmod %o %s', $mode, escapeshellarg($file)), true); |
|
313 |
return $this->run_command(sprintf('chmod -R %o %s', $mode, escapeshellarg($file)), true); |
|
314 |
} |
|
315 |
||
316 |
/** |
|
317 |
* Change the ownership of a file / folder. |
|
318 |
* |
|
319 |
* |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
320 |
* @param string $file Path to the file. |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
321 |
* @param string|int $owner A user name or number. |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
322 |
* @param bool $recursive Optional. If set True changes file owner recursivly. Default False. |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
323 |
* @return bool True on success or false on failure. |
0 | 324 |
*/ |
5 | 325 |
public function chown( $file, $owner, $recursive = false ) { |
0 | 326 |
if ( ! $this->exists($file) ) |
327 |
return false; |
|
328 |
if ( ! $recursive || ! $this->is_dir($file) ) |
|
329 |
return $this->run_command(sprintf('chown %s %s', escapeshellarg($owner), escapeshellarg($file)), true); |
|
330 |
return $this->run_command(sprintf('chown -R %s %s', escapeshellarg($owner), escapeshellarg($file)), true); |
|
331 |
} |
|
332 |
||
5 | 333 |
/** |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
334 |
* |
5 | 335 |
* @param string $file |
336 |
* @return string|false |
|
337 |
*/ |
|
338 |
public function owner($file) { |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
339 |
$owneruid = @fileowner( $this->sftp_path( $file ) ); |
0 | 340 |
if ( ! $owneruid ) |
341 |
return false; |
|
342 |
if ( ! function_exists('posix_getpwuid') ) |
|
343 |
return $owneruid; |
|
344 |
$ownerarray = posix_getpwuid($owneruid); |
|
345 |
return $ownerarray['name']; |
|
346 |
} |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
347 |
|
5 | 348 |
/** |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
349 |
* |
5 | 350 |
* @param string $file |
351 |
* @return string |
|
352 |
*/ |
|
353 |
public function getchmod($file) { |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
354 |
return substr( decoct( @fileperms( $this->sftp_path( $file ) ) ), -3 ); |
0 | 355 |
} |
356 |
||
5 | 357 |
/** |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
358 |
* |
5 | 359 |
* @param string $file |
360 |
* @return string|false |
|
361 |
*/ |
|
362 |
public function group($file) { |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
363 |
$gid = @filegroup( $this->sftp_path( $file ) ); |
0 | 364 |
if ( ! $gid ) |
365 |
return false; |
|
366 |
if ( ! function_exists('posix_getgrgid') ) |
|
367 |
return $gid; |
|
368 |
$grouparray = posix_getgrgid($gid); |
|
369 |
return $grouparray['name']; |
|
370 |
} |
|
371 |
||
5 | 372 |
/** |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
373 |
* |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
374 |
* @param string $source |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
375 |
* @param string $destination |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
376 |
* @param bool $overwrite |
5 | 377 |
* @param int|bool $mode |
378 |
* @return bool |
|
379 |
*/ |
|
380 |
public function copy($source, $destination, $overwrite = false, $mode = false) { |
|
0 | 381 |
if ( ! $overwrite && $this->exists($destination) ) |
382 |
return false; |
|
383 |
$content = $this->get_contents($source); |
|
384 |
if ( false === $content) |
|
385 |
return false; |
|
386 |
return $this->put_contents($destination, $content, $mode); |
|
387 |
} |
|
388 |
||
5 | 389 |
/** |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
390 |
* |
5 | 391 |
* @param string $source |
392 |
* @param string $destination |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
393 |
* @param bool $overwrite |
5 | 394 |
* @return bool |
395 |
*/ |
|
396 |
public function move($source, $destination, $overwrite = false) { |
|
397 |
return @ssh2_sftp_rename( $this->sftp_link, $source, $destination ); |
|
0 | 398 |
} |
399 |
||
5 | 400 |
/** |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
401 |
* |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
402 |
* @param string $file |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
403 |
* @param bool $recursive |
5 | 404 |
* @param string|bool $type |
405 |
* @return bool |
|
406 |
*/ |
|
407 |
public function delete($file, $recursive = false, $type = false) { |
|
0 | 408 |
if ( 'f' == $type || $this->is_file($file) ) |
409 |
return ssh2_sftp_unlink($this->sftp_link, $file); |
|
410 |
if ( ! $recursive ) |
|
411 |
return ssh2_sftp_rmdir($this->sftp_link, $file); |
|
412 |
$filelist = $this->dirlist($file); |
|
413 |
if ( is_array($filelist) ) { |
|
414 |
foreach ( $filelist as $filename => $fileinfo) { |
|
415 |
$this->delete($file . '/' . $filename, $recursive, $fileinfo['type']); |
|
416 |
} |
|
417 |
} |
|
418 |
return ssh2_sftp_rmdir($this->sftp_link, $file); |
|
419 |
} |
|
420 |
||
5 | 421 |
/** |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
422 |
* |
5 | 423 |
* @param string $file |
424 |
* @return bool |
|
425 |
*/ |
|
426 |
public function exists($file) { |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
427 |
return file_exists( $this->sftp_path( $file ) ); |
0 | 428 |
} |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
429 |
|
5 | 430 |
/** |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
431 |
* |
5 | 432 |
* @param string $file |
433 |
* @return bool |
|
434 |
*/ |
|
435 |
public function is_file($file) { |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
436 |
return is_file( $this->sftp_path( $file ) ); |
0 | 437 |
} |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
438 |
|
5 | 439 |
/** |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
440 |
* |
5 | 441 |
* @param string $path |
442 |
* @return bool |
|
443 |
*/ |
|
444 |
public function is_dir($path) { |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
445 |
return is_dir( $this->sftp_path( $path ) ); |
0 | 446 |
} |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
447 |
|
5 | 448 |
/** |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
449 |
* |
5 | 450 |
* @param string $file |
451 |
* @return bool |
|
452 |
*/ |
|
453 |
public function is_readable($file) { |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
454 |
return is_readable( $this->sftp_path( $file ) ); |
0 | 455 |
} |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
456 |
|
5 | 457 |
/** |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
458 |
* |
5 | 459 |
* @param string $file |
460 |
* @return bool |
|
461 |
*/ |
|
462 |
public function is_writable($file) { |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
463 |
// PHP will base it's writable checks on system_user === file_owner, not ssh_user === file_owner |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
464 |
return true; |
0 | 465 |
} |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
466 |
|
5 | 467 |
/** |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
468 |
* |
5 | 469 |
* @param string $file |
470 |
* @return int |
|
471 |
*/ |
|
472 |
public function atime($file) { |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
473 |
return fileatime( $this->sftp_path( $file ) ); |
0 | 474 |
} |
475 |
||
5 | 476 |
/** |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
477 |
* |
5 | 478 |
* @param string $file |
479 |
* @return int |
|
480 |
*/ |
|
481 |
public function mtime($file) { |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
482 |
return filemtime( $this->sftp_path( $file ) ); |
0 | 483 |
} |
484 |
||
5 | 485 |
/** |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
486 |
* |
5 | 487 |
* @param string $file |
488 |
* @return int |
|
489 |
*/ |
|
490 |
public function size($file) { |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
491 |
return filesize( $this->sftp_path( $file ) ); |
0 | 492 |
} |
493 |
||
5 | 494 |
/** |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
495 |
* |
5 | 496 |
* @param string $file |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
497 |
* @param int $time |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
498 |
* @param int $atime |
5 | 499 |
*/ |
500 |
public function touch($file, $time = 0, $atime = 0) { |
|
0 | 501 |
//Not implemented. |
502 |
} |
|
503 |
||
5 | 504 |
/** |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
505 |
* |
5 | 506 |
* @param string $path |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
507 |
* @param mixed $chmod |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
508 |
* @param mixed $chown |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
509 |
* @param mixed $chgrp |
5 | 510 |
* @return bool |
511 |
*/ |
|
512 |
public function mkdir($path, $chmod = false, $chown = false, $chgrp = false) { |
|
0 | 513 |
$path = untrailingslashit($path); |
514 |
if ( empty($path) ) |
|
515 |
return false; |
|
516 |
||
517 |
if ( ! $chmod ) |
|
518 |
$chmod = FS_CHMOD_DIR; |
|
519 |
if ( ! ssh2_sftp_mkdir($this->sftp_link, $path, $chmod, true) ) |
|
520 |
return false; |
|
521 |
if ( $chown ) |
|
522 |
$this->chown($path, $chown); |
|
523 |
if ( $chgrp ) |
|
524 |
$this->chgrp($path, $chgrp); |
|
525 |
return true; |
|
526 |
} |
|
527 |
||
5 | 528 |
/** |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
529 |
* |
5 | 530 |
* @param string $path |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
531 |
* @param bool $recursive |
5 | 532 |
* @return bool |
533 |
*/ |
|
534 |
public function rmdir($path, $recursive = false) { |
|
0 | 535 |
return $this->delete($path, $recursive); |
536 |
} |
|
537 |
||
5 | 538 |
/** |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
539 |
* |
5 | 540 |
* @param string $path |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
541 |
* @param bool $include_hidden |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
542 |
* @param bool $recursive |
5 | 543 |
* @return bool|array |
544 |
*/ |
|
545 |
public function dirlist($path, $include_hidden = true, $recursive = false) { |
|
0 | 546 |
if ( $this->is_file($path) ) { |
547 |
$limit_file = basename($path); |
|
548 |
$path = dirname($path); |
|
549 |
} else { |
|
550 |
$limit_file = false; |
|
551 |
} |
|
552 |
||
553 |
if ( ! $this->is_dir($path) ) |
|
554 |
return false; |
|
555 |
||
556 |
$ret = array(); |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
557 |
$dir = @dir( $this->sftp_path( $path ) ); |
0 | 558 |
|
559 |
if ( ! $dir ) |
|
560 |
return false; |
|
561 |
||
562 |
while (false !== ($entry = $dir->read()) ) { |
|
563 |
$struc = array(); |
|
564 |
$struc['name'] = $entry; |
|
565 |
||
566 |
if ( '.' == $struc['name'] || '..' == $struc['name'] ) |
|
567 |
continue; //Do not care about these folders. |
|
568 |
||
569 |
if ( ! $include_hidden && '.' == $struc['name'][0] ) |
|
570 |
continue; |
|
571 |
||
572 |
if ( $limit_file && $struc['name'] != $limit_file ) |
|
573 |
continue; |
|
574 |
||
575 |
$struc['perms'] = $this->gethchmod($path.'/'.$entry); |
|
576 |
$struc['permsn'] = $this->getnumchmodfromh($struc['perms']); |
|
577 |
$struc['number'] = false; |
|
578 |
$struc['owner'] = $this->owner($path.'/'.$entry); |
|
579 |
$struc['group'] = $this->group($path.'/'.$entry); |
|
580 |
$struc['size'] = $this->size($path.'/'.$entry); |
|
581 |
$struc['lastmodunix']= $this->mtime($path.'/'.$entry); |
|
582 |
$struc['lastmod'] = date('M j',$struc['lastmodunix']); |
|
583 |
$struc['time'] = date('h:i:s',$struc['lastmodunix']); |
|
584 |
$struc['type'] = $this->is_dir($path.'/'.$entry) ? 'd' : 'f'; |
|
585 |
||
586 |
if ( 'd' == $struc['type'] ) { |
|
587 |
if ( $recursive ) |
|
588 |
$struc['files'] = $this->dirlist($path . '/' . $struc['name'], $include_hidden, $recursive); |
|
589 |
else |
|
590 |
$struc['files'] = array(); |
|
591 |
} |
|
592 |
||
593 |
$ret[ $struc['name'] ] = $struc; |
|
594 |
} |
|
595 |
$dir->close(); |
|
596 |
unset($dir); |
|
597 |
return $ret; |
|
598 |
} |
|
599 |
} |