Projects : mp-wp : mp-wp_svg-screenshots-and-errorreporting-r2
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 | * To use this class you must follow these steps for PHP 5.2.6+ |
13 | * |
14 | * @contrib http://kevin.vanzonneveld.net/techblog/article/make_ssh_connections_with_php/ - Installation Notes |
15 | * |
16 | * Complie libssh2 (Note: Only 0.14 is officaly working with PHP 5.2.6+ right now.) |
17 | * |
18 | * cd /usr/src |
19 | * wget http://surfnet.dl.sourceforge.net/sourceforge/libssh2/libssh2-0.14.tar.gz |
20 | * tar -zxvf libssh2-0.14.tar.gz |
21 | * cd libssh2-0.14/ |
22 | * ./configure |
23 | * make all install |
24 | * |
25 | * Note: No not leave the directory yet! |
26 | * |
27 | * Enter: pecl install -f ssh2 |
28 | * |
29 | * Copy the ssh.so file it creates to your PHP Module Directory. |
30 | * Open up your PHP.INI file and look for where extensions are placed. |
31 | * Add in your PHP.ini file: extension=ssh2.so |
32 | * |
33 | * Restart Apache! |
34 | * Check phpinfo() streams to confirm that: ssh2.shell, ssh2.exec, ssh2.tunnel, ssh2.scp, ssh2.sftp exist. |
35 | * |
36 | * |
37 | * @since 2.7 |
38 | * @package WordPress |
39 | * @subpackage Filesystem |
40 | * @uses WP_Filesystem_Base Extends class |
41 | */ |
42 | class WP_Filesystem_SSH2 extends WP_Filesystem_Base { |
43 | |
44 | var $debugtest = false; // set this to true only if your a debuging your connection |
45 | |
46 | var $link = null; |
47 | var $sftp_link = null; |
48 | var $keys = false; |
49 | /* |
50 | * This is the timeout value for ssh results to comeback. |
51 | * Slower servers might need this incressed, but this number otherwise should not change. |
52 | * |
53 | * @parm $timeout int |
54 | * |
55 | */ |
56 | var $timeout = 15; |
57 | var $errors = array(); |
58 | var $options = array(); |
59 | |
60 | var $permission = 0644; |
61 | |
62 | function WP_Filesystem_SSH2($opt='') { |
63 | $this->method = 'ssh2'; |
64 | $this->errors = new WP_Error(); |
65 | |
66 | //Check if possible to use ssh2 functions. |
67 | if ( ! extension_loaded('ssh2') ) { |
68 | $this->errors->add('no_ssh2_ext', __('The ssh2 PHP extension is not available')); |
69 | return false; |
70 | } |
71 | |
72 | // Set defaults: |
73 | if ( empty($opt['port']) ) |
74 | $this->options['port'] = 22; |
75 | else |
76 | $this->options['port'] = $opt['port']; |
77 | |
78 | if ( empty($opt['hostname']) ) |
79 | $this->errors->add('empty_hostname', __('SSH2 hostname is required')); |
80 | else |
81 | $this->options['hostname'] = $opt['hostname']; |
82 | |
83 | if ( isset($opt['base']) && ! empty($opt['base']) ) |
84 | $this->wp_base = $opt['base']; |
85 | |
86 | // Check if the options provided are OK. |
87 | if ( empty ($opt['username']) ) |
88 | $this->errors->add('empty_username', __('SSH2 username is required')); |
89 | else |
90 | $this->options['username'] = $opt['username']; |
91 | |
92 | if ( ( !empty ($opt['public_key']) ) && ( !empty ($opt['private_key']) ) ) { |
93 | $this->options['public_key'] = $opt['public_key']; |
94 | $this->options['private_key'] = $opt['private_key']; |
95 | |
96 | $this->options['hostkey'] = array("hostkey" => "ssh-rsa"); |
97 | |
98 | $this->keys = true; |
99 | } |
100 | |
101 | |
102 | if ( empty ($opt['password']) ) { |
103 | if ( !$this->keys ) // password can be blank if we are using keys |
104 | $this->errors->add('empty_password', __('SSH2 password is required')); |
105 | } else { |
106 | $this->options['password'] = $opt['password']; |
107 | } |
108 | |
109 | } |
110 | |
111 | function connect() { |
112 | $this->debug("connect();"); |
113 | |
114 | if ( ! $this->keys ) { |
115 | $this->link = @ssh2_connect($this->options['hostname'], $this->options['port']); |
116 | } else { |
117 | $this->link = @ssh2_connect($this->options['hostname'], $this->options['port'], $this->options['hostkey']); |
118 | } |
119 | |
120 | if ( ! $this->link ) { |
121 | $this->errors->add('connect', sprintf(__('Failed to connect to SSH2 Server %1$s:%2$s'), $this->options['hostname'], $this->options['port'])); |
122 | return false; |
123 | } |
124 | |
125 | if ( !$this->keys ) { |
126 | if ( ! @ssh2_auth_password($this->link, $this->options['username'], $this->options['password']) ) { |
127 | $this->errors->add('auth', sprintf(__('Username/Password incorrect for %s'), $this->options['username'])); |
128 | return false; |
129 | } |
130 | } else { |
131 | if ( ! @ssh2_auth_pubkey_file($this->link, $this->options['username'], $this->options['public_key'], $this->options['private_key'], $this->options['password'] ) ) { |
132 | $this->errors->add('auth', sprintf(__('Public and Private keys incorrent for %s'), $this->options['username'])); |
133 | return false; |
134 | } |
135 | } |
136 | |
137 | $this->sftp_link = ssh2_sftp($this->link); |
138 | |
139 | return true; |
140 | } |
141 | |
142 | function run_command($link, $command, $returnbool = false) { |
143 | $this->debug("run_command();"); |
144 | if(!($stream = @ssh2_exec( $link, $command . "; echo \"__COMMAND_FINISHED__\";"))) { |
145 | $this->errors->add('command', sprintf(__('Unable to perform command: %s'), $command)); |
146 | } else { |
147 | stream_set_blocking( $stream, true ); |
148 | $time_start = time(); |
149 | $data = null; |
150 | while( true ) { |
151 | if (strpos($data,"__COMMAND_FINISHED__") !== false){ |
152 | break; // the command has finshed! |
153 | } |
154 | if( (time()-$time_start) > $this->timeout ){ |
155 | $this->errors->add('command', sprintf(__('Connection to the server has timeout after %s seconds.'), $this->timeout)); |
156 | unset($this->link); |
157 | unset($this->sftp_link); // close connections |
158 | return false; |
159 | } |
160 | while( $buf = fread( $stream, strlen($stream) ) ) |
161 | $data .= $buf; |
162 | } |
163 | fclose($stream); |
164 | $data = trim(str_replace("__COMMAND_FINISHED__", "", $data)); |
165 | if (($returnbool) && ( (int) $data )) { |
166 | return true; |
167 | } elseif (($returnbool) && (! (int) $data )) { |
168 | return false; |
169 | } else { |
170 | return $data; |
171 | } |
172 | } |
173 | return false; |
174 | } |
175 | |
176 | function debug($text) |
177 | { |
178 | if ($this->debugtest) |
179 | { |
180 | echo "<br/>" . $text . "<br/>"; |
181 | } |
182 | } |
183 | |
184 | function setDefaultPermissions($perm) { |
185 | $this->debug("setDefaultPermissions();"); |
186 | if ( $perm ) |
187 | $this->permission = $perm; |
188 | } |
189 | |
190 | function get_contents($file, $type = '', $resumepos = 0 ) { |
191 | $this->debug("get_contents();"); |
192 | $tempfile = wp_tempnam( $file ); |
193 | if ( ! $tempfile ) |
194 | return false; |
195 | if( ! ssh2_scp_recv($this->link, $file, $tempfile) ) |
196 | return false; |
197 | $contents = file_get_contents($tempfile); |
198 | unlink($tempfile); |
199 | return $contents; |
200 | } |
201 | |
202 | function get_contents_array($file) { |
203 | $this->debug("get_contents_array();"); |
204 | return explode("\n", $this->get_contents($file)); |
205 | } |
206 | |
207 | function put_contents($file, $contents, $type = '' ) { |
208 | $this->debug("put_contents($file);"); |
209 | $tempfile = wp_tempnam( $file ); |
210 | $temp = fopen($tempfile, 'w'); |
211 | if ( ! $temp ) |
212 | return false; |
213 | fwrite($temp, $contents); |
214 | fclose($temp); |
215 | $ret = ssh2_scp_send($this->link, $tempfile, $file, $this->permission); |
216 | unlink($tempfile); |
217 | return $ret; |
218 | } |
219 | |
220 | function cwd() { |
221 | $this->debug("cwd();"); |
222 | $cwd = $this->run_command($this->link, 'pwd'); |
223 | if( $cwd ) |
224 | $cwd = trailingslashit($cwd); |
225 | return $cwd; |
226 | } |
227 | |
228 | function chdir($dir) { |
229 | $this->debug("chdir();"); |
230 | return $this->run_command($this->link, 'cd ' . $dir, true); |
231 | } |
232 | |
233 | function chgrp($file, $group, $recursive = false ) { |
234 | $this->debug("chgrp();"); |
235 | if ( ! $this->exists($file) ) |
236 | return false; |
237 | if ( ! $recursive || ! $this->is_dir($file) ) |
238 | return $this->run_command($this->link, sprintf('chgrp %o %s', $mode, $file), true); |
239 | return $this->run_command($this->link, sprintf('chgrp -R %o %s', $mode, $file), true); |
240 | } |
241 | |
242 | function chmod($file, $mode = false, $recursive = false) { |
243 | $this->debug("chmod();"); |
244 | if( ! $mode ) |
245 | $mode = $this->permission; |
246 | if( ! $mode ) |
247 | return false; |
248 | if ( ! $this->exists($file) ) |
249 | return false; |
250 | if ( ! $recursive || ! $this->is_dir($file) ) |
251 | return $this->run_command($this->link, sprintf('chmod %o %s', $mode, $file), true); |
252 | return $this->run_command($this->link, sprintf('chmod -R %o %s', $mode, $file), true); |
253 | } |
254 | |
255 | function chown($file, $owner, $recursive = false ) { |
256 | $this->debug("chown();"); |
257 | if ( ! $this->exists($file) ) |
258 | return false; |
259 | if ( ! $recursive || ! $this->is_dir($file) ) |
260 | return $this->run_command($this->link, sprintf('chown %o %s', $mode, $file), true); |
261 | return $this->run_command($this->link, sprintf('chown -R %o %s', $mode, $file), true); |
262 | } |
263 | |
264 | function owner($file) { |
265 | $this->debug("owner();"); |
266 | $dir = $this->dirlist($file); |
267 | return $dir[$file]['owner']; |
268 | } |
269 | |
270 | function getchmod($file) { |
271 | $this->debug("getchmod();"); |
272 | $dir = $this->dirlist($file); |
273 | return $dir[$file]['permsn']; |
274 | } |
275 | |
276 | function group($file) { |
277 | $this->debug("group();"); |
278 | $dir = $this->dirlist($file); |
279 | return $dir[$file]['group']; |
280 | } |
281 | |
282 | function copy($source, $destination, $overwrite = false ) { |
283 | $this->debug("copy();"); |
284 | if( ! $overwrite && $this->exists($destination) ) |
285 | return false; |
286 | $content = $this->get_contents($source); |
287 | if( false === $content) |
288 | return false; |
289 | return $this->put_contents($destination, $content); |
290 | } |
291 | |
292 | function move($source, $destination, $overwrite = false) { |
293 | $this->debug("move();"); |
294 | return @ssh2_sftp_rename($this->link, $source, $destination); |
295 | } |
296 | |
297 | function delete($file, $recursive = false) { |
298 | $this->debug("delete();"); |
299 | if ( $this->is_file($file) ) |
300 | return ssh2_sftp_unlink($this->sftp_link, $file); |
301 | if ( ! $recursive ) |
302 | return ssh2_sftp_rmdir($this->sftp_link, $file); |
303 | $filelist = $this->dirlist($file); |
304 | if ( is_array($filelist) ) { |
305 | foreach ( $filelist as $filename => $fileinfo) { |
306 | $this->delete($file . '/' . $filename, $recursive); |
307 | } |
308 | } |
309 | return ssh2_sftp_rmdir($this->sftp_link, $file); |
310 | } |
311 | |
312 | function exists($file) { |
313 | $this->debug("exists();"); |
314 | return $this->run_command($this->link, sprintf('ls -lad %s', $file), true); |
315 | } |
316 | |
317 | function is_file($file) { |
318 | $this->debug("is_file();"); |
319 | //DO NOT RELY ON dirlist()! |
320 | $list = $this->run_command($this->link, sprintf('ls -lad %s', $file)); |
321 | $list = $this->parselisting($list); |
322 | if ( ! $list ) |
323 | return false; |
324 | else |
325 | return ( !$list['isdir'] && !$list['islink'] ); //ie. not a file or link, yet exists, must be file. |
326 | } |
327 | |
328 | function is_dir($path) { |
329 | $this->debug("is_dir();"); |
330 | //DO NOT RELY ON dirlist()! |
331 | $list = $this->parselisting($this->run_command($this->link, sprintf('ls -lad %s', untrailingslashit($path)))); |
332 | if ( ! $list ) |
333 | return false; |
334 | else |
335 | return $list['isdir']; |
336 | } |
337 | |
338 | function is_readable($file) { |
339 | //Not implmented. |
340 | } |
341 | |
342 | function is_writable($file) { |
343 | //Not implmented. |
344 | } |
345 | |
346 | function atime($file) { |
347 | //Not implmented. |
348 | } |
349 | |
350 | function mtime($file) { |
351 | //Not implmented. |
352 | } |
353 | |
354 | function size($file) { |
355 | //Not implmented. |
356 | } |
357 | |
358 | function touch($file, $time = 0, $atime = 0) { |
359 | //Not implmented. |
360 | } |
361 | |
362 | function mkdir($path, $chmod = null, $chown = false, $chgrp = false) { |
363 | $this->debug("mkdir();"); |
364 | $path = untrailingslashit($path); |
365 | if( ! ssh2_sftp_mkdir($this->sftp_link, $path, $chmod, true) ) |
366 | return false; |
367 | if( $chown ) |
368 | $this->chown($path, $chown); |
369 | if( $chgrp ) |
370 | $this->chgrp($path, $chgrp); |
371 | return true; |
372 | } |
373 | |
374 | function rmdir($path, $recursive = false) { |
375 | $this->debug("rmdir();"); |
376 | return $this->delete($path, $recursive); |
377 | } |
378 | |
379 | function parselisting($line) { |
380 | $this->debug("parselisting();"); |
381 | $is_windows = ($this->OS_remote == FTP_OS_Windows); |
382 | 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)) { |
383 | $b = array(); |
384 | if ($lucifer[3]<70) { $lucifer[3] +=2000; } else { $lucifer[3]+=1900; } // 4digit year fix |
385 | $b['isdir'] = ($lucifer[7]=="<DIR>"); |
386 | if ( $b['isdir'] ) |
387 | $b['type'] = 'd'; |
388 | else |
389 | $b['type'] = 'f'; |
390 | $b['size'] = $lucifer[7]; |
391 | $b['month'] = $lucifer[1]; |
392 | $b['day'] = $lucifer[2]; |
393 | $b['year'] = $lucifer[3]; |
394 | $b['hour'] = $lucifer[4]; |
395 | $b['minute'] = $lucifer[5]; |
396 | $b['time'] = @mktime($lucifer[4]+(strcasecmp($lucifer[6],"PM")==0?12:0),$lucifer[5],0,$lucifer[1],$lucifer[2],$lucifer[3]); |
397 | $b['am/pm'] = $lucifer[6]; |
398 | $b['name'] = $lucifer[8]; |
399 | } else if (!$is_windows && $lucifer=preg_split("/[ ]/",$line,9,PREG_SPLIT_NO_EMPTY)) { |
400 | //echo $line."\n"; |
401 | $lcount=count($lucifer); |
402 | if ($lcount<8) return ''; |
403 | $b = array(); |
404 | $b['isdir'] = $lucifer[0]{0} === "d"; |
405 | $b['islink'] = $lucifer[0]{0} === "l"; |
406 | if ( $b['isdir'] ) |
407 | $b['type'] = 'd'; |
408 | elseif ( $b['islink'] ) |
409 | $b['type'] = 'l'; |
410 | else |
411 | $b['type'] = 'f'; |
412 | $b['perms'] = $lucifer[0]; |
413 | $b['number'] = $lucifer[1]; |
414 | $b['owner'] = $lucifer[2]; |
415 | $b['group'] = $lucifer[3]; |
416 | $b['size'] = $lucifer[4]; |
417 | if ($lcount==8) { |
418 | sscanf($lucifer[5],"%d-%d-%d",$b['year'],$b['month'],$b['day']); |
419 | sscanf($lucifer[6],"%d:%d",$b['hour'],$b['minute']); |
420 | $b['time'] = @mktime($b['hour'],$b['minute'],0,$b['month'],$b['day'],$b['year']); |
421 | $b['name'] = $lucifer[7]; |
422 | } else { |
423 | $b['month'] = $lucifer[5]; |
424 | $b['day'] = $lucifer[6]; |
425 | if (preg_match("/([0-9]{2}):([0-9]{2})/",$lucifer[7],$l2)) { |
426 | $b['year'] = date("Y"); |
427 | $b['hour'] = $l2[1]; |
428 | $b['minute'] = $l2[2]; |
429 | } else { |
430 | $b['year'] = $lucifer[7]; |
431 | $b['hour'] = 0; |
432 | $b['minute'] = 0; |
433 | } |
434 | $b['time'] = strtotime(sprintf("%d %s %d %02d:%02d",$b['day'],$b['month'],$b['year'],$b['hour'],$b['minute'])); |
435 | $b['name'] = $lucifer[8]; |
436 | } |
437 | } |
438 | |
439 | return $b; |
440 | } |
441 | |
442 | function dirlist($path = '.', $incdot = false, $recursive = false) { |
443 | $this->debug("dirlist();"); |
444 | if( $this->is_file($path) ) { |
445 | $limitFile = basename($path); |
446 | $path = trailingslashit(dirname($path)); |
447 | } else { |
448 | $limitFile = false; |
449 | } |
450 | |
451 | $list = $this->run_command($this->link, sprintf('ls -la %s', $path)); |
452 | |
453 | if ( $list === false ) |
454 | return false; |
455 | |
456 | $list = explode("\n", $list); |
457 | |
458 | $dirlist = array(); |
459 | foreach ( (array)$list as $k => $v ) { |
460 | $entry = $this->parselisting($v); |
461 | if ( empty($entry) ) |
462 | continue; |
463 | |
464 | if ( '.' == $entry['name'] || '..' == $entry['name'] ) |
465 | continue; |
466 | |
467 | $dirlist[ $entry['name'] ] = $entry; |
468 | } |
469 | |
470 | if ( ! $dirlist ) |
471 | return false; |
472 | |
473 | if ( empty($dirlist) ) |
474 | return array(); |
475 | |
476 | $ret = array(); |
477 | foreach ( $dirlist as $struc ) { |
478 | |
479 | if ( 'd' == $struc['type'] ) { |
480 | $struc['files'] = array(); |
481 | |
482 | if ( $incdot ){ |
483 | //We're including the doted starts |
484 | if( '.' != $struc['name'] && '..' != $struc['name'] ){ //Ok, It isnt a special folder |
485 | if ($recursive) |
486 | $struc['files'] = $this->dirlist($path . '/' . $struc['name'], $incdot, $recursive); |
487 | } |
488 | } else { //No dots |
489 | if ( $recursive ) |
490 | $struc['files'] = $this->dirlist($path . '/' . $struc['name'], $incdot, $recursive); |
491 | } |
492 | } |
493 | //File |
494 | $ret[$struc['name']] = $struc; |
495 | } |
496 | return $ret; |
497 | } |
498 | function __destruct() { |
499 | $this->debug("__destruct();"); |
500 | if ( $this->link ) |
501 | unset($this->link); |
502 | if ( $this->sftp_link ) |
503 | unset($this->sftp_link); |
504 | } |
505 | } |
506 | |
507 | ?> |