~canonical-sysadmins/wordpress/4.7.2

« back to all changes in this revision

Viewing changes to wp-admin/includes/class-wp-filesystem-ssh2.php

  • Committer: Jacek Nykis
  • Date: 2015-01-05 16:17:05 UTC
  • Revision ID: jacek.nykis@canonical.com-20150105161705-w544l1h5mcg7u4w9
Initial commit

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 
 
38
        public $link = false;
 
39
        public $sftp_link = false;
 
40
        public $keys = false;
 
41
        public $errors = array();
 
42
        public $options = array();
 
43
 
 
44
        public function __construct($opt='') {
 
45
                $this->method = 'ssh2';
 
46
                $this->errors = new WP_Error();
 
47
 
 
48
                //Check if possible to use ssh2 functions.
 
49
                if ( ! extension_loaded('ssh2') ) {
 
50
                        $this->errors->add('no_ssh2_ext', __('The ssh2 PHP extension is not available'));
 
51
                        return false;
 
52
                }
 
53
                if ( !function_exists('stream_get_contents') ) {
 
54
                        $this->errors->add('ssh2_php_requirement', __('The ssh2 PHP extension is available, however, we require the PHP5 function <code>stream_get_contents()</code>'));
 
55
                        return false;
 
56
                }
 
57
 
 
58
                // Set defaults:
 
59
                if ( empty($opt['port']) )
 
60
                        $this->options['port'] = 22;
 
61
                else
 
62
                        $this->options['port'] = $opt['port'];
 
63
 
 
64
                if ( empty($opt['hostname']) )
 
65
                        $this->errors->add('empty_hostname', __('SSH2 hostname is required'));
 
66
                else
 
67
                        $this->options['hostname'] = $opt['hostname'];
 
68
 
 
69
                if ( ! empty($opt['base']) )
 
70
                        $this->wp_base = $opt['base'];
 
71
 
 
72
                // Check if the options provided are OK.
 
73
                if ( !empty ($opt['public_key']) && !empty ($opt['private_key']) ) {
 
74
                        $this->options['public_key'] = $opt['public_key'];
 
75
                        $this->options['private_key'] = $opt['private_key'];
 
76
 
 
77
                        $this->options['hostkey'] = array('hostkey' => 'ssh-rsa');
 
78
 
 
79
                        $this->keys = true;
 
80
                } elseif ( empty ($opt['username']) ) {
 
81
                        $this->errors->add('empty_username', __('SSH2 username is required'));
 
82
                }
 
83
 
 
84
                if ( !empty($opt['username']) )
 
85
                        $this->options['username'] = $opt['username'];
 
86
 
 
87
                if ( empty ($opt['password']) ) {
 
88
                        // Password can be blank if we are using keys.
 
89
                        if ( !$this->keys )
 
90
                                $this->errors->add('empty_password', __('SSH2 password is required'));
 
91
                } else {
 
92
                        $this->options['password'] = $opt['password'];
 
93
                }
 
94
 
 
95
        }
 
96
 
 
97
        public function connect() {
 
98
                if ( ! $this->keys ) {
 
99
                        $this->link = @ssh2_connect($this->options['hostname'], $this->options['port']);
 
100
                } else {
 
101
                        $this->link = @ssh2_connect($this->options['hostname'], $this->options['port'], $this->options['hostkey']);
 
102
                }
 
103
 
 
104
                if ( ! $this->link ) {
 
105
                        $this->errors->add('connect', sprintf(__('Failed to connect to SSH2 Server %1$s:%2$s'), $this->options['hostname'], $this->options['port']));
 
106
                        return false;
 
107
                }
 
108
 
 
109
                if ( !$this->keys ) {
 
110
                        if ( ! @ssh2_auth_password($this->link, $this->options['username'], $this->options['password']) ) {
 
111
                                $this->errors->add('auth', sprintf(__('Username/Password incorrect for %s'), $this->options['username']));
 
112
                                return false;
 
113
                        }
 
114
                } else {
 
115
                        if ( ! @ssh2_auth_pubkey_file($this->link, $this->options['username'], $this->options['public_key'], $this->options['private_key'], $this->options['password'] ) ) {
 
116
                                $this->errors->add('auth', sprintf(__('Public and Private keys incorrect for %s'), $this->options['username']));
 
117
                                return false;
 
118
                        }
 
119
                }
 
120
 
 
121
                $this->sftp_link = ssh2_sftp($this->link);
 
122
 
 
123
                return true;
 
124
        }
 
125
 
 
126
        public function run_command( $command, $returnbool = false) {
 
127
 
 
128
                if ( ! $this->link )
 
129
                        return false;
 
130
 
 
131
                if ( ! ($stream = ssh2_exec($this->link, $command)) ) {
 
132
                        $this->errors->add('command', sprintf(__('Unable to perform command: %s'), $command));
 
133
                } else {
 
134
                        stream_set_blocking( $stream, true );
 
135
                        stream_set_timeout( $stream, FS_TIMEOUT );
 
136
                        $data = stream_get_contents( $stream );
 
137
                        fclose( $stream );
 
138
 
 
139
                        if ( $returnbool )
 
140
                                return ( $data === false ) ? false : '' != trim($data);
 
141
                        else
 
142
                                return $data;
 
143
                }
 
144
                return false;
 
145
        }
 
146
 
 
147
        public function get_contents( $file ) {
 
148
                $file = ltrim($file, '/');
 
149
                return file_get_contents('ssh2.sftp://' . $this->sftp_link . '/' . $file);
 
150
        }
 
151
 
 
152
        public function get_contents_array($file) {
 
153
                $file = ltrim($file, '/');
 
154
                return file('ssh2.sftp://' . $this->sftp_link . '/' . $file);
 
155
        }
 
156
 
 
157
        public function put_contents($file, $contents, $mode = false ) {
 
158
                $ret = file_put_contents( 'ssh2.sftp://' . $this->sftp_link . '/' . ltrim( $file, '/' ), $contents );
 
159
 
 
160
                if ( $ret !== strlen( $contents ) )
 
161
                        return false;
 
162
 
 
163
                $this->chmod($file, $mode);
 
164
 
 
165
                return true;
 
166
        }
 
167
 
 
168
        public function cwd() {
 
169
                $cwd = $this->run_command('pwd');
 
170
                if ( $cwd )
 
171
                        $cwd = trailingslashit($cwd);
 
172
                return $cwd;
 
173
        }
 
174
 
 
175
        public function chdir($dir) {
 
176
                return $this->run_command('cd ' . $dir, true);
 
177
        }
 
178
 
 
179
        public function chgrp($file, $group, $recursive = false ) {
 
180
                if ( ! $this->exists($file) )
 
181
                        return false;
 
182
                if ( ! $recursive || ! $this->is_dir($file) )
 
183
                        return $this->run_command(sprintf('chgrp %s %s', escapeshellarg($group), escapeshellarg($file)), true);
 
184
                return $this->run_command(sprintf('chgrp -R %s %s', escapeshellarg($group), escapeshellarg($file)), true);
 
185
        }
 
186
 
 
187
        public function chmod($file, $mode = false, $recursive = false) {
 
188
                if ( ! $this->exists($file) )
 
189
                        return false;
 
190
 
 
191
                if ( ! $mode ) {
 
192
                        if ( $this->is_file($file) )
 
193
                                $mode = FS_CHMOD_FILE;
 
194
                        elseif ( $this->is_dir($file) )
 
195
                                $mode = FS_CHMOD_DIR;
 
196
                        else
 
197
                                return false;
 
198
                }
 
199
 
 
200
                if ( ! $recursive || ! $this->is_dir($file) )
 
201
                        return $this->run_command(sprintf('chmod %o %s', $mode, escapeshellarg($file)), true);
 
202
                return $this->run_command(sprintf('chmod -R %o %s', $mode, escapeshellarg($file)), true);
 
203
        }
 
204
 
 
205
        /**
 
206
         * Change the ownership of a file / folder.
 
207
         *
 
208
         * @since Unknown
 
209
         *
 
210
         * @param string $file    Path to the file.
 
211
         * @param mixed  $owner   A user name or number.
 
212
         * @param bool $recursive Optional. If set True changes file owner recursivly. Defaults to False.
 
213
         * @return bool Returns true on success or false on failure.
 
214
         */
 
215
        public function chown( $file, $owner, $recursive = false ) {
 
216
                if ( ! $this->exists($file) )
 
217
                        return false;
 
218
                if ( ! $recursive || ! $this->is_dir($file) )
 
219
                        return $this->run_command(sprintf('chown %s %s', escapeshellarg($owner), escapeshellarg($file)), true);
 
220
                return $this->run_command(sprintf('chown -R %s %s', escapeshellarg($owner), escapeshellarg($file)), true);
 
221
        }
 
222
 
 
223
        public function owner($file) {
 
224
                $owneruid = @fileowner('ssh2.sftp://' . $this->sftp_link . '/' . ltrim($file, '/'));
 
225
                if ( ! $owneruid )
 
226
                        return false;
 
227
                if ( ! function_exists('posix_getpwuid') )
 
228
                        return $owneruid;
 
229
                $ownerarray = posix_getpwuid($owneruid);
 
230
                return $ownerarray['name'];
 
231
        }
 
232
 
 
233
        public function getchmod($file) {
 
234
                return substr( decoct( @fileperms( 'ssh2.sftp://' . $this->sftp_link . '/' . ltrim( $file, '/' ) ) ), -3 );
 
235
        }
 
236
 
 
237
        public function group($file) {
 
238
                $gid = @filegroup('ssh2.sftp://' . $this->sftp_link . '/' . ltrim($file, '/'));
 
239
                if ( ! $gid )
 
240
                        return false;
 
241
                if ( ! function_exists('posix_getgrgid') )
 
242
                        return $gid;
 
243
                $grouparray = posix_getgrgid($gid);
 
244
                return $grouparray['name'];
 
245
        }
 
246
 
 
247
        public function copy($source, $destination, $overwrite = false, $mode = false) {
 
248
                if ( ! $overwrite && $this->exists($destination) )
 
249
                        return false;
 
250
                $content = $this->get_contents($source);
 
251
                if ( false === $content)
 
252
                        return false;
 
253
                return $this->put_contents($destination, $content, $mode);
 
254
        }
 
255
 
 
256
        public function move($source, $destination, $overwrite = false) {
 
257
                return @ssh2_sftp_rename($this->link, $source, $destination);
 
258
        }
 
259
 
 
260
        public function delete($file, $recursive = false, $type = false) {
 
261
                if ( 'f' == $type || $this->is_file($file) )
 
262
                        return ssh2_sftp_unlink($this->sftp_link, $file);
 
263
                if ( ! $recursive )
 
264
                         return ssh2_sftp_rmdir($this->sftp_link, $file);
 
265
                $filelist = $this->dirlist($file);
 
266
                if ( is_array($filelist) ) {
 
267
                        foreach ( $filelist as $filename => $fileinfo) {
 
268
                                $this->delete($file . '/' . $filename, $recursive, $fileinfo['type']);
 
269
                        }
 
270
                }
 
271
                return ssh2_sftp_rmdir($this->sftp_link, $file);
 
272
        }
 
273
 
 
274
        public function exists($file) {
 
275
                $file = ltrim($file, '/');
 
276
                return file_exists('ssh2.sftp://' . $this->sftp_link . '/' . $file);
 
277
        }
 
278
 
 
279
        public function is_file($file) {
 
280
                $file = ltrim($file, '/');
 
281
                return is_file('ssh2.sftp://' . $this->sftp_link . '/' . $file);
 
282
        }
 
283
 
 
284
        public function is_dir($path) {
 
285
                $path = ltrim($path, '/');
 
286
                return is_dir('ssh2.sftp://' . $this->sftp_link . '/' . $path);
 
287
        }
 
288
 
 
289
        public function is_readable($file) {
 
290
                $file = ltrim($file, '/');
 
291
                return is_readable('ssh2.sftp://' . $this->sftp_link . '/' . $file);
 
292
        }
 
293
 
 
294
        public function is_writable($file) {
 
295
                $file = ltrim($file, '/');
 
296
                return is_writable('ssh2.sftp://' . $this->sftp_link . '/' . $file);
 
297
        }
 
298
 
 
299
        public function atime($file) {
 
300
                $file = ltrim($file, '/');
 
301
                return fileatime('ssh2.sftp://' . $this->sftp_link . '/' . $file);
 
302
        }
 
303
 
 
304
        public function mtime($file) {
 
305
                $file = ltrim($file, '/');
 
306
                return filemtime('ssh2.sftp://' . $this->sftp_link . '/' . $file);
 
307
        }
 
308
 
 
309
        public function size($file) {
 
310
                $file = ltrim($file, '/');
 
311
                return filesize('ssh2.sftp://' . $this->sftp_link . '/' . $file);
 
312
        }
 
313
 
 
314
        public function touch($file, $time = 0, $atime = 0) {
 
315
                //Not implemented.
 
316
        }
 
317
 
 
318
        public function mkdir($path, $chmod = false, $chown = false, $chgrp = false) {
 
319
                $path = untrailingslashit($path);
 
320
                if ( empty($path) )
 
321
                        return false;
 
322
 
 
323
                if ( ! $chmod )
 
324
                        $chmod = FS_CHMOD_DIR;
 
325
                if ( ! ssh2_sftp_mkdir($this->sftp_link, $path, $chmod, true) )
 
326
                        return false;
 
327
                if ( $chown )
 
328
                        $this->chown($path, $chown);
 
329
                if ( $chgrp )
 
330
                        $this->chgrp($path, $chgrp);
 
331
                return true;
 
332
        }
 
333
 
 
334
        public function rmdir($path, $recursive = false) {
 
335
                return $this->delete($path, $recursive);
 
336
        }
 
337
 
 
338
        public function dirlist($path, $include_hidden = true, $recursive = false) {
 
339
                if ( $this->is_file($path) ) {
 
340
                        $limit_file = basename($path);
 
341
                        $path = dirname($path);
 
342
                } else {
 
343
                        $limit_file = false;
 
344
                }
 
345
 
 
346
                if ( ! $this->is_dir($path) )
 
347
                        return false;
 
348
 
 
349
                $ret = array();
 
350
                $dir = @dir('ssh2.sftp://' . $this->sftp_link .'/' . ltrim($path, '/') );
 
351
 
 
352
                if ( ! $dir )
 
353
                        return false;
 
354
 
 
355
                while (false !== ($entry = $dir->read()) ) {
 
356
                        $struc = array();
 
357
                        $struc['name'] = $entry;
 
358
 
 
359
                        if ( '.' == $struc['name'] || '..' == $struc['name'] )
 
360
                                continue; //Do not care about these folders.
 
361
 
 
362
                        if ( ! $include_hidden && '.' == $struc['name'][0] )
 
363
                                continue;
 
364
 
 
365
                        if ( $limit_file && $struc['name'] != $limit_file )
 
366
                                continue;
 
367
 
 
368
                        $struc['perms']         = $this->gethchmod($path.'/'.$entry);
 
369
                        $struc['permsn']        = $this->getnumchmodfromh($struc['perms']);
 
370
                        $struc['number']        = false;
 
371
                        $struc['owner']         = $this->owner($path.'/'.$entry);
 
372
                        $struc['group']         = $this->group($path.'/'.$entry);
 
373
                        $struc['size']          = $this->size($path.'/'.$entry);
 
374
                        $struc['lastmodunix']= $this->mtime($path.'/'.$entry);
 
375
                        $struc['lastmod']   = date('M j',$struc['lastmodunix']);
 
376
                        $struc['time']          = date('h:i:s',$struc['lastmodunix']);
 
377
                        $struc['type']          = $this->is_dir($path.'/'.$entry) ? 'd' : 'f';
 
378
 
 
379
                        if ( 'd' == $struc['type'] ) {
 
380
                                if ( $recursive )
 
381
                                        $struc['files'] = $this->dirlist($path . '/' . $struc['name'], $include_hidden, $recursive);
 
382
                                else
 
383
                                        $struc['files'] = array();
 
384
                        }
 
385
 
 
386
                        $ret[ $struc['name'] ] = $struc;
 
387
                }
 
388
                $dir->close();
 
389
                unset($dir);
 
390
                return $ret;
 
391
        }
 
392
}