Make WordPress Core

Ticket #7690: class-wp-filesystem-ssh2.php

File class-wp-filesystem-ssh2.php, 12.3 KB (added by ShaneF, 17 years ago)

This is the SSH2 Transfer Class -- UNTESTED -- Needs testing on Unix/Linux boxes with libssh2.so enabled and working

Line 
1<?php
2/**
3 * WordPress SSH2 Filesystem.
4 *
5 * @package WordPress
6 * @subpackage Filesystem
7 */
8
9/**
10 * WordPress Filesystem Class for implementing SSH2.
11 *
12 * @since 2.7
13 * @package WordPress
14 * @subpackage Filesystem
15 * @uses WP_Filesystem_Base Extends class
16 */
17class WP_Filesystem_SSH2 extends WP_Filesystem_Base {
18       
19        var $debugtest = true;  //      this is my var that will output the text when debuggin this class
20       
21        var $link;
22        var $timeout = 5;
23        var $errors = array();
24        var $options = array();
25
26        var $permission = null;
27
28        var $filetypes = array(
29                                                        'php'=>FTP_ASCII,
30                                                        'css'=>FTP_ASCII,
31                                                        'txt'=>FTP_ASCII,
32                                                        'js'=>FTP_ASCII,
33                                                        'html'=>FTP_ASCII,
34                                                        'htm'=>FTP_ASCII,
35                                                        'xml'=>FTP_ASCII,
36
37                                                        'jpg'=>FTP_BINARY,
38                                                        'png'=>FTP_BINARY,
39                                                        'gif'=>FTP_BINARY,
40                                                        'bmp'=>FTP_BINARY
41                                                        );
42
43        function WP_Filesystem_SSH2($opt='') {
44                $this->method = 'ssh2';
45                $this->errors = new WP_Error();
46
47                //Check if possible to use ftp functions.
48                if ( ! extension_loaded('ssh2') ) {
49                        $this->errors->add('no_ssh2_ext', __('The ssh2 PHP extension is not available'));
50                        return false;
51                }
52
53                // Set defaults:
54                if ( empty($opt['port']) )
55                        $this->options['port'] = 22;
56                else
57                        $this->options['port'] = $opt['port'];
58
59                if ( empty($opt['hostname']) )
60                        $this->errors->add('empty_hostname', __('SSH2 hostname is required'));
61                else
62                        $this->options['hostname'] = $opt['hostname'];
63
64                if ( isset($opt['base']) && ! empty($opt['base']) )
65                        $this->wp_base = $opt['base'];
66
67                // Check if the options provided are OK.
68                if ( empty ($opt['username']) )
69                        $this->errors->add('empty_username', __('SSH2 username is required'));
70                else
71                        $this->options['username'] = $opt['username'];
72
73                if ( empty ($opt['password']) )
74                        $this->errors->add('empty_password', __('SSH password is required'));
75                else
76                        $this->options['password'] = $opt['password'];
77
78        }
79
80        function connect() {
81                $this->debug("connect();");
82                $this->link = @ssh2_connect($this->options['hostname'], $this->options['port']);
83
84                if ( ! $this->link ) {
85                        $this->errors->add('connect', sprintf(__('Failed to connect to SSH2 Server %1$s:%2$s'), $this->options['hostname'], $this->options['port']));
86                        return false;
87                }
88
89                if ( ! @ssh2_auth_password($this->link,$this->options['username'], $this->options['password']) ) {
90                        $this->errors->add('auth', sprintf(__('Username/Password incorrect for %s'), $this->options['username']));
91                        return false;
92                }
93
94                return true;
95        }
96       
97        function run_command($link, $command, $returnbool = false) {
98                $this->debug("run_command(".$command.");");
99                if(!($stream = @ssh2_exec( $link, $command ))) {
100            $this->errors->add('command', sprintf(__('Unable to preform command: %s'), $command));
101        } else {
102            stream_set_blocking( $stream, true );
103                        $time_start = time();
104            $data = "";
105                        while( true ) {
106                            if( (time()-$time_start) > $this->timeout ){
107                                $this->errors->add('command', sprintf(__('Connection to the server has timeout after %s seconds.'), $this->timeout));
108                                break;
109                            }
110                    while( $buf = fread( $stream, strlen($stream) ) ){
111                        $data .= $buf;
112                    }
113                        }
114            fclose($stream);
115            if (($returnbool) && ($data)) {
116                $this->debug("Data: " . print_r($data, true) . " Returning: True");
117                return true;
118            } elseif (($returnbool) && (!$data)) {
119                $this->debug("Data: " . print_r($data, true) . " Returning: False");
120                return false;
121            } else {
122                $this->debug("Data: " . print_r($data, true));
123                return $data;
124            }
125        }
126        }
127
128        function debug($text)
129        {
130                if ($this->debugtest)
131                {
132                        echo $text . "<br/>";
133                }
134        }
135
136        function setDefaultPermissions($perm) {
137                $this->permission = $perm;
138        }
139
140        function get_contents($file, $type = '', $resumepos = 0 ){
141                if( empty($type) ){
142                        $extension = substr(strrchr($file, "."), 1);
143                        $type = isset($this->filetypes[ $extension ]) ? $this->filetypes[ $extension ] : FTP_ASCII;
144                }
145                $temp = tmpfile();
146                if ( ! $temp )
147                        return false;
148                if( ! @ssh2_scp_recv($this->link, $temp, $file) )
149                        return false;
150                fseek($temp, 0); //Skip back to the start of the file being written to
151                $contents = '';
152                while (!feof($temp)) {
153                        $contents .= fread($temp, 8192);
154                }
155                fclose($temp);
156                return $contents;
157        }
158       
159        function get_contents_array($file) {
160                return explode("\n", $this->get_contents($file));
161        }
162       
163        function put_contents($file, $contents, $type = '' ) {
164                if( empty($type) ) {
165                        $extension = substr(strrchr($file, "."), 1);
166                        $type = isset($this->filetypes[ $extension ]) ? $this->filetypes[ $extension ] : FTP_ASCII;
167                }
168                $temp = tmpfile();
169                if ( ! $temp )
170                        return false;
171                fwrite($temp, $contents);
172                fseek($temp, 0); //Skip back to the start of the file being written to
173                $ret = @ssh2_scp_send($this->link, $file, $temp, $type);
174                fclose($temp);
175                return $ret;
176        }
177       
178        function cwd() {
179                $cwd = $this->run_command($this->link, "pwd");
180                if( $cwd )
181                        $cwd = trailingslashit($cwd);
182                return $cwd;
183        }
184       
185        function chdir($dir) {
186                if ($this->run_command($this->link, "cd " . $dir, true)) {
187                        return true;
188                }
189                return false;
190        }
191       
192        function chgrp($file, $group, $recursive = false ) {
193                return false;
194        }
195       
196        function chmod($file, $mode = false, $recursive = false) {
197                if( ! $mode )
198                        $mode = $this->permission;
199                if( ! $mode )
200                        return false;
201                if ( ! $this->exists($file) )
202                        return false;
203                if ( ! $recursive || ! $this->is_dir($file) ) {
204                        return $this->run_command($this->link, sprintf('CHMOD %o %s', $mode, $file), true);
205                }
206                //Is a directory, and we want recursive
207                $filelist = $this->dirlist($file);
208                foreach($filelist as $filename){
209                        $this->chmod($file . '/' . $filename, $mode, $recursive);
210                }
211                return true;
212        }
213       
214        function chown($file, $owner, $recursive = false ) {
215                return false;
216        }
217       
218        function owner($file) {
219                $dir = $this->dirlist($file);
220                return $dir[$file]['owner'];
221        }
222       
223        function getchmod($file) {
224                $dir = $this->dirlist($file);
225                return $dir[$file]['permsn'];
226        }
227       
228        function group($file) {
229                $dir = $this->dirlist($file);
230                return $dir[$file]['group'];
231        }
232       
233        function copy($source, $destination, $overwrite = false ) {
234                if( ! $overwrite && $this->exists($destination) )
235                        return false;
236                $content = $this->get_contents($source);
237                if( false === $content)
238                        return false;
239                return $this->put_contents($destination, $content);
240        }
241       
242        function move($source, $destination, $overwrite = false) {
243                return @ssh2_sftp_rename($this->link, $source, $destination);
244        }
245
246        function delete($file, $recursive=false) {
247                if ( $this->is_file($file) )
248                        return @ssh2_sftp_unlink($this->link, $file);
249                if ( !$recursive )
250                        return @ssh2_sftp_rmdir($this->link, $file);
251                $filelist = $this->dirlist($file);
252                foreach ((array) $filelist as $filename => $fileinfo) {
253                        $this->delete($file . '/' . $filename, $recursive);
254                }
255                return @ssh2_sftp_rmdir($this->link, $file);
256        }
257
258        function exists($file) {
259                $list = $this->run_command($this->link, sprintf('ls -la %s', $file));
260                if( ! $list )
261                        return false;
262                return count($list) == 1 ? true : false;
263        }
264       
265        function is_file($file) {
266                return $this->is_dir($file) ? false : true;
267        }
268       
269        function is_dir($path) {
270                $cwd = $this->cwd();
271                $result = $this->run_command($this->link, sprintf('cd %s', $path), true);
272                if( $result && $path == $this->cwd() || $this->cwd() != $cwd ) {
273                        // @todo: use ssh2_exec
274                        @ftp_chdir($this->link, $cwd);
275                        return true;
276                }
277                return false;
278        }
279       
280        function is_readable($file) {
281                //Get dir list, Check if the file is writable by the current user??
282                return true;
283        }
284       
285        function is_writable($file) {
286                //Get dir list, Check if the file is writable by the current user??
287                return true;
288        }
289       
290        function atime($file) {
291                return false;
292        }
293       
294        function mtime($file) {
295                return; //      i have to look up to see if there is a way in SSH2 to look the modifed date
296                //      return ftp_mdtm($this->link, $file);
297        }
298       
299        function size($file) {
300                return; //      i have to look up to see if there is a way in SSH2 to get the file size
301                //      return ftp_size($this->link, $file);
302        }
303       
304        function touch($file, $time = 0, $atime = 0) {
305                return false;
306        }
307       
308        function mkdir($path, $chmod = false, $chown = false, $chgrp = false) {
309                if( !@ssh2_sftp_mkdir($this->link, $path) )
310                        return false;
311                if( $chmod )
312                        $this->chmod($path, $chmod);
313                if( $chown )
314                        $this->chown($path, $chown);
315                if( $chgrp )
316                        $this->chgrp($path, $chgrp);
317                return true;
318        }
319       
320        function rmdir($path, $recursive = false) {
321                if( ! $recursive )
322                        return @ssh2_sftp_rmdir($this->link, $path);
323
324                //TODO: Recursive Directory delete, Have to delete files from the folder first.
325                //$dir = $this->dirlist($path);
326                //foreach($dir as $file)
327
328        }
329
330        function parselisting($line) {
331                $is_windows = ($this->OS_remote == FTP_OS_Windows);
332                if ($is_windows && preg_match("/([0-9]{2})-([0-9]{2})-([0-9]{2}) +([0-9]{2}):([0-9]{2})(AM|PM) +([0-9]+|<DIR>) +(.+)/", $line, $lucifer)) {
333                        $b = array();
334                        if ($lucifer[3]<70) { $lucifer[3] +=2000; } else { $lucifer[3]+=1900; } // 4digit year fix
335                        $b['isdir'] = ($lucifer[7]=="<DIR>");
336                        if ( $b['isdir'] )
337                                $b['type'] = 'd';
338                        else
339                                $b['type'] = 'f';
340                        $b['size'] = $lucifer[7];
341                        $b['month'] = $lucifer[1];
342                        $b['day'] = $lucifer[2];
343                        $b['year'] = $lucifer[3];
344                        $b['hour'] = $lucifer[4];
345                        $b['minute'] = $lucifer[5];
346                        $b['time'] = @mktime($lucifer[4]+(strcasecmp($lucifer[6],"PM")==0?12:0),$lucifer[5],0,$lucifer[1],$lucifer[2],$lucifer[3]);
347                        $b['am/pm'] = $lucifer[6];
348                        $b['name'] = $lucifer[8];
349                } else if (!$is_windows && $lucifer=preg_split("/[ ]/",$line,9,PREG_SPLIT_NO_EMPTY)) {
350                        //echo $line."\n";
351                        $lcount=count($lucifer);
352                        if ($lcount<8) return '';
353                        $b = array();
354                        $b['isdir'] = $lucifer[0]{0} === "d";
355                        $b['islink'] = $lucifer[0]{0} === "l";
356                        if ( $b['isdir'] )
357                                $b['type'] = 'd';
358                        elseif ( $b['islink'] )
359                                $b['type'] = 'l';
360                        else
361                                $b['type'] = 'f';
362                        $b['perms'] = $lucifer[0];
363                        $b['number'] = $lucifer[1];
364                        $b['owner'] = $lucifer[2];
365                        $b['group'] = $lucifer[3];
366                        $b['size'] = $lucifer[4];
367                        if ($lcount==8) {
368                                sscanf($lucifer[5],"%d-%d-%d",$b['year'],$b['month'],$b['day']);
369                                sscanf($lucifer[6],"%d:%d",$b['hour'],$b['minute']);
370                                $b['time'] = @mktime($b['hour'],$b['minute'],0,$b['month'],$b['day'],$b['year']);
371                                $b['name'] = $lucifer[7];
372                        } else {
373                                $b['month'] = $lucifer[5];
374                                $b['day'] = $lucifer[6];
375                                if (preg_match("/([0-9]{2}):([0-9]{2})/",$lucifer[7],$l2)) {
376                                        $b['year'] = date("Y");
377                                        $b['hour'] = $l2[1];
378                                        $b['minute'] = $l2[2];
379                                } else {
380                                        $b['year'] = $lucifer[7];
381                                        $b['hour'] = 0;
382                                        $b['minute'] = 0;
383                                }
384                                $b['time'] = strtotime(sprintf("%d %s %d %02d:%02d",$b['day'],$b['month'],$b['year'],$b['hour'],$b['minute']));
385                                $b['name'] = $lucifer[8];
386                        }
387                }
388
389                return $b;
390        }
391
392        function dirlist($path = '.', $incdot = false, $recursive = false) {
393                if( $this->is_file($path) ) {
394                        $limitFile = basename($path);
395                        $path = dirname($path) . '/';
396                } else {
397                        $limitFile = false;
398                }
399               
400                $list = $this->run_command($this->link, sprintf('ls -a %s', $path));
401
402                if ( $list === false )
403                        return false;
404
405                $dirlist = array();
406                foreach ( $list as $k => $v ) {
407                        $entry = $this->parselisting($v);
408                        if ( empty($entry) )
409                                continue;
410
411                        if ( '.' == $entry["name"] || '..' == $entry["name"] )
412                                continue;
413
414                        $dirlist[ $entry['name'] ] = $entry;
415                }
416
417                if ( ! $dirlist )
418                        return false;
419                if ( empty($dirlist) )
420                        return array();
421
422                $ret = array();
423                foreach ( $dirlist as $struc ) {
424
425                        if ( 'd' == $struc['type'] ) {
426                                $struc['files'] = array();
427
428                                if ( $incdot ){
429                                        //We're including the doted starts
430                                        if( '.' != $struc['name'] && '..' != $struc['name'] ){ //Ok, It isnt a special folder
431                                                if ($recursive)
432                                                        $struc['files'] = $this->dirlist($path . '/' . $struc['name'], $incdot, $recursive);
433                                        }
434                                } else { //No dots
435                                        if ($recursive)
436                                                $struc['files'] = $this->dirlist($path . '/' . $struc['name'], $incdot, $recursive);
437                                }
438                        }
439                        //File
440                        $ret[$struc['name']] = $struc;
441                }
442                return $ret;
443        }
444
445        function __destruct(){
446                if( $this->link )
447                        unset($this->link);
448        }
449}
450
451?>