wp/wp-admin/includes/class-wp-filesystem-ssh2.php
changeset 16 a86126ab1dd4
parent 9 177826044cd9
child 18 be944660c56a
equal deleted inserted replaced
15:3d4e9c994f10 16:a86126ab1dd4
     4  *
     4  *
     5  * To use this class you must follow these steps for PHP 5.2.6+
     5  * To use this class you must follow these steps for PHP 5.2.6+
     6  *
     6  *
     7  * @contrib http://kevin.vanzonneveld.net/techblog/article/make_ssh_connections_with_php/ - Installation Notes
     7  * @contrib http://kevin.vanzonneveld.net/techblog/article/make_ssh_connections_with_php/ - Installation Notes
     8  *
     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)
     9  * Compile 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  *
    10  *
    11  * cd /usr/src
    11  * cd /usr/src
    12  * wget http://surfnet.dl.sourceforge.net/sourceforge/libssh2/libssh2-0.14.tar.gz
    12  * wget https://www.libssh2.org/download/libssh2-0.14.tar.gz
    13  * tar -zxvf libssh2-0.14.tar.gz
    13  * tar -zxvf libssh2-0.14.tar.gz
    14  * cd libssh2-0.14/
    14  * cd libssh2-0.14/
    15  * ./configure
    15  * ./configure
    16  * make all install
    16  * make all install
    17  *
    17  *
    24  * Add in your PHP.ini file: extension=ssh2.so
    24  * Add in your PHP.ini file: extension=ssh2.so
    25  *
    25  *
    26  * Restart Apache!
    26  * Restart Apache!
    27  * Check phpinfo() streams to confirm that: ssh2.shell, ssh2.exec, ssh2.tunnel, ssh2.scp, ssh2.sftp  exist.
    27  * Check phpinfo() streams to confirm that: ssh2.shell, ssh2.exec, ssh2.tunnel, ssh2.scp, ssh2.sftp  exist.
    28  *
    28  *
    29  * Note: as of WordPress 2.8, This utilises the PHP5+ function 'stream_get_contents'
    29  * Note: As of WordPress 2.8, this utilises the PHP5+ function `stream_get_contents()`.
    30  *
    30  *
    31  * @since 2.7.0
    31  * @since 2.7.0
    32  *
    32  *
    33  * @package WordPress
    33  * @package WordPress
    34  * @subpackage Filesystem
    34  * @subpackage Filesystem
    62 	 */
    62 	 */
    63 	public function __construct( $opt = '' ) {
    63 	public function __construct( $opt = '' ) {
    64 		$this->method = 'ssh2';
    64 		$this->method = 'ssh2';
    65 		$this->errors = new WP_Error();
    65 		$this->errors = new WP_Error();
    66 
    66 
    67 		//Check if possible to use ssh2 functions.
    67 		// Check if possible to use ssh2 functions.
    68 		if ( ! extension_loaded( 'ssh2' ) ) {
    68 		if ( ! extension_loaded( 'ssh2' ) ) {
    69 			$this->errors->add( 'no_ssh2_ext', __( 'The ssh2 PHP extension is not available' ) );
    69 			$this->errors->add( 'no_ssh2_ext', __( 'The ssh2 PHP extension is not available' ) );
    70 			return;
       
    71 		}
       
    72 		if ( ! function_exists( 'stream_get_contents' ) ) {
       
    73 			$this->errors->add(
       
    74 				'ssh2_php_requirement',
       
    75 				sprintf(
       
    76 					/* translators: %s: stream_get_contents() */
       
    77 					__( 'The ssh2 PHP extension is available, however, we require the PHP5 function %s' ),
       
    78 					'<code>stream_get_contents()</code>'
       
    79 				)
       
    80 			);
       
    81 			return;
    70 			return;
    82 		}
    71 		}
    83 
    72 
    84 		// Set defaults:
    73 		// Set defaults:
    85 		if ( empty( $opt['port'] ) ) {
    74 		if ( empty( $opt['port'] ) ) {
   135 		}
   124 		}
   136 
   125 
   137 		if ( ! $this->link ) {
   126 		if ( ! $this->link ) {
   138 			$this->errors->add(
   127 			$this->errors->add(
   139 				'connect',
   128 				'connect',
   140 				/* translators: %s: hostname:port */
       
   141 				sprintf(
   129 				sprintf(
       
   130 					/* translators: %s: hostname:port */
   142 					__( 'Failed to connect to SSH2 Server %s' ),
   131 					__( 'Failed to connect to SSH2 Server %s' ),
   143 					$this->options['hostname'] . ':' . $this->options['port']
   132 					$this->options['hostname'] . ':' . $this->options['port']
   144 				)
   133 				)
   145 			);
   134 			);
       
   135 
   146 			return false;
   136 			return false;
   147 		}
   137 		}
   148 
   138 
   149 		if ( ! $this->keys ) {
   139 		if ( ! $this->keys ) {
   150 			if ( ! @ssh2_auth_password( $this->link, $this->options['username'], $this->options['password'] ) ) {
   140 			if ( ! @ssh2_auth_password( $this->link, $this->options['username'], $this->options['password'] ) ) {
   151 				$this->errors->add(
   141 				$this->errors->add(
   152 					'auth',
   142 					'auth',
   153 					/* translators: %s: username */
       
   154 					sprintf(
   143 					sprintf(
       
   144 						/* translators: %s: Username. */
   155 						__( 'Username/Password incorrect for %s' ),
   145 						__( 'Username/Password incorrect for %s' ),
   156 						$this->options['username']
   146 						$this->options['username']
   157 					)
   147 					)
   158 				);
   148 				);
       
   149 
   159 				return false;
   150 				return false;
   160 			}
   151 			}
   161 		} else {
   152 		} else {
   162 			if ( ! @ssh2_auth_pubkey_file( $this->link, $this->options['username'], $this->options['public_key'], $this->options['private_key'], $this->options['password'] ) ) {
   153 			if ( ! @ssh2_auth_pubkey_file( $this->link, $this->options['username'], $this->options['public_key'], $this->options['private_key'], $this->options['password'] ) ) {
   163 				$this->errors->add(
   154 				$this->errors->add(
   164 					'auth',
   155 					'auth',
   165 					/* translators: %s: username */
       
   166 					sprintf(
   156 					sprintf(
       
   157 						/* translators: %s: Username. */
   167 						__( 'Public and Private keys incorrect for %s' ),
   158 						__( 'Public and Private keys incorrect for %s' ),
   168 						$this->options['username']
   159 						$this->options['username']
   169 					)
   160 					)
   170 				);
   161 				);
       
   162 
   171 				return false;
   163 				return false;
   172 			}
   164 			}
   173 		}
   165 		}
   174 
   166 
   175 		$this->sftp_link = ssh2_sftp( $this->link );
   167 		$this->sftp_link = ssh2_sftp( $this->link );
       
   168 
   176 		if ( ! $this->sftp_link ) {
   169 		if ( ! $this->sftp_link ) {
   177 			$this->errors->add(
   170 			$this->errors->add(
   178 				'connect',
   171 				'connect',
   179 				/* translators: %s: hostname:port */
       
   180 				sprintf(
   172 				sprintf(
       
   173 					/* translators: %s: hostname:port */
   181 					__( 'Failed to initialize a SFTP subsystem session with the SSH2 Server %s' ),
   174 					__( 'Failed to initialize a SFTP subsystem session with the SSH2 Server %s' ),
   182 					$this->options['hostname'] . ':' . $this->options['port']
   175 					$this->options['hostname'] . ':' . $this->options['port']
   183 				)
   176 				)
   184 			);
   177 			);
       
   178 
   185 			return false;
   179 			return false;
   186 		}
   180 		}
   187 
   181 
   188 		return true;
   182 		return true;
   189 	}
   183 	}
   203 	 */
   197 	 */
   204 	public function sftp_path( $path ) {
   198 	public function sftp_path( $path ) {
   205 		if ( '/' === $path ) {
   199 		if ( '/' === $path ) {
   206 			$path = '/./';
   200 			$path = '/./';
   207 		}
   201 		}
       
   202 
   208 		return 'ssh2.sftp://' . $this->sftp_link . '/' . ltrim( $path, '/' );
   203 		return 'ssh2.sftp://' . $this->sftp_link . '/' . ltrim( $path, '/' );
   209 	}
   204 	}
   210 
   205 
   211 	/**
   206 	/**
   212 	 * @since 2.7.0
   207 	 * @since 2.7.0
   213 	 *
   208 	 *
   214 	 * @param string $command
   209 	 * @param string $command
   215 	 * @param bool $returnbool
   210 	 * @param bool   $returnbool
   216 	 * @return bool|string True on success, false on failure. String if the command was executed, `$returnbool`
   211 	 * @return bool|string True on success, false on failure. String if the command was executed, `$returnbool`
   217 	 *                     is false (default), and data from the resulting stream was retrieved.
   212 	 *                     is false (default), and data from the resulting stream was retrieved.
   218 	 */
   213 	 */
   219 	public function run_command( $command, $returnbool = false ) {
   214 	public function run_command( $command, $returnbool = false ) {
   220 		if ( ! $this->link ) {
   215 		if ( ! $this->link ) {
   221 			return false;
   216 			return false;
   222 		}
   217 		}
   223 
   218 
   224 		if ( ! ( $stream = ssh2_exec( $this->link, $command ) ) ) {
   219 		$stream = ssh2_exec( $this->link, $command );
       
   220 
       
   221 		if ( ! $stream ) {
   225 			$this->errors->add(
   222 			$this->errors->add(
   226 				'command',
   223 				'command',
   227 				/* translators: %s: command */
       
   228 				sprintf(
   224 				sprintf(
       
   225 					/* translators: %s: Command. */
   229 					__( 'Unable to perform command: %s' ),
   226 					__( 'Unable to perform command: %s' ),
   230 					$command
   227 					$command
   231 				)
   228 				)
   232 			);
   229 			);
   233 		} else {
   230 		} else {
   235 			stream_set_timeout( $stream, FS_TIMEOUT );
   232 			stream_set_timeout( $stream, FS_TIMEOUT );
   236 			$data = stream_get_contents( $stream );
   233 			$data = stream_get_contents( $stream );
   237 			fclose( $stream );
   234 			fclose( $stream );
   238 
   235 
   239 			if ( $returnbool ) {
   236 			if ( $returnbool ) {
   240 				return ( $data === false ) ? false : '' != trim( $data );
   237 				return ( false === $data ) ? false : '' !== trim( $data );
   241 			} else {
   238 			} else {
   242 				return $data;
   239 				return $data;
   243 			}
   240 			}
   244 		}
   241 		}
       
   242 
   245 		return false;
   243 		return false;
   246 	}
   244 	}
   247 
   245 
   248 	/**
   246 	/**
   249 	 * Reads entire file into a string.
   247 	 * Reads entire file into a string.
   282 	 * @return bool True on success, false on failure.
   280 	 * @return bool True on success, false on failure.
   283 	 */
   281 	 */
   284 	public function put_contents( $file, $contents, $mode = false ) {
   282 	public function put_contents( $file, $contents, $mode = false ) {
   285 		$ret = file_put_contents( $this->sftp_path( $file ), $contents );
   283 		$ret = file_put_contents( $this->sftp_path( $file ), $contents );
   286 
   284 
   287 		if ( $ret !== strlen( $contents ) ) {
   285 		if ( strlen( $contents ) !== $ret ) {
   288 			return false;
   286 			return false;
   289 		}
   287 		}
   290 
   288 
   291 		$this->chmod( $file, $mode );
   289 		$this->chmod( $file, $mode );
   292 
   290 
   300 	 *
   298 	 *
   301 	 * @return string|false The current working directory on success, false on failure.
   299 	 * @return string|false The current working directory on success, false on failure.
   302 	 */
   300 	 */
   303 	public function cwd() {
   301 	public function cwd() {
   304 		$cwd = ssh2_sftp_realpath( $this->sftp_link, '.' );
   302 		$cwd = ssh2_sftp_realpath( $this->sftp_link, '.' );
       
   303 
   305 		if ( $cwd ) {
   304 		if ( $cwd ) {
   306 			$cwd = trailingslashit( trim( $cwd ) );
   305 			$cwd = trailingslashit( trim( $cwd ) );
   307 		}
   306 		}
       
   307 
   308 		return $cwd;
   308 		return $cwd;
   309 	}
   309 	}
   310 
   310 
   311 	/**
   311 	/**
   312 	 * Changes current directory.
   312 	 * Changes current directory.
   333 	 */
   333 	 */
   334 	public function chgrp( $file, $group, $recursive = false ) {
   334 	public function chgrp( $file, $group, $recursive = false ) {
   335 		if ( ! $this->exists( $file ) ) {
   335 		if ( ! $this->exists( $file ) ) {
   336 			return false;
   336 			return false;
   337 		}
   337 		}
       
   338 
   338 		if ( ! $recursive || ! $this->is_dir( $file ) ) {
   339 		if ( ! $recursive || ! $this->is_dir( $file ) ) {
   339 			return $this->run_command( sprintf( 'chgrp %s %s', escapeshellarg( $group ), escapeshellarg( $file ) ), true );
   340 			return $this->run_command( sprintf( 'chgrp %s %s', escapeshellarg( $group ), escapeshellarg( $file ) ), true );
   340 		}
   341 		}
       
   342 
   341 		return $this->run_command( sprintf( 'chgrp -R %s %s', escapeshellarg( $group ), escapeshellarg( $file ) ), true );
   343 		return $this->run_command( sprintf( 'chgrp -R %s %s', escapeshellarg( $group ), escapeshellarg( $file ) ), true );
   342 	}
   344 	}
   343 
   345 
   344 	/**
   346 	/**
   345 	 * Changes filesystem permissions.
   347 	 * Changes filesystem permissions.
   347 	 * @since 2.7.0
   349 	 * @since 2.7.0
   348 	 *
   350 	 *
   349 	 * @param string    $file      Path to the file.
   351 	 * @param string    $file      Path to the file.
   350 	 * @param int|false $mode      Optional. The permissions as octal number, usually 0644 for files,
   352 	 * @param int|false $mode      Optional. The permissions as octal number, usually 0644 for files,
   351 	 *                             0755 for directories. Default false.
   353 	 *                             0755 for directories. Default false.
   352 	 * @param bool      $recursive Optional. If set to true, changes file group recursively.
   354 	 * @param bool      $recursive Optional. If set to true, changes file permissions recursively.
   353 	 *                             Default false.
   355 	 *                             Default false.
   354 	 * @return bool True on success, false on failure.
   356 	 * @return bool True on success, false on failure.
   355 	 */
   357 	 */
   356 	public function chmod( $file, $mode = false, $recursive = false ) {
   358 	public function chmod( $file, $mode = false, $recursive = false ) {
   357 		if ( ! $this->exists( $file ) ) {
   359 		if ( ! $this->exists( $file ) ) {
   369 		}
   371 		}
   370 
   372 
   371 		if ( ! $recursive || ! $this->is_dir( $file ) ) {
   373 		if ( ! $recursive || ! $this->is_dir( $file ) ) {
   372 			return $this->run_command( sprintf( 'chmod %o %s', $mode, escapeshellarg( $file ) ), true );
   374 			return $this->run_command( sprintf( 'chmod %o %s', $mode, escapeshellarg( $file ) ), true );
   373 		}
   375 		}
       
   376 
   374 		return $this->run_command( sprintf( 'chmod -R %o %s', $mode, escapeshellarg( $file ) ), true );
   377 		return $this->run_command( sprintf( 'chmod -R %o %s', $mode, escapeshellarg( $file ) ), true );
   375 	}
   378 	}
   376 
   379 
   377 	/**
   380 	/**
   378 	 * Changes the owner of a file or directory.
   381 	 * Changes the owner of a file or directory.
   387 	 */
   390 	 */
   388 	public function chown( $file, $owner, $recursive = false ) {
   391 	public function chown( $file, $owner, $recursive = false ) {
   389 		if ( ! $this->exists( $file ) ) {
   392 		if ( ! $this->exists( $file ) ) {
   390 			return false;
   393 			return false;
   391 		}
   394 		}
       
   395 
   392 		if ( ! $recursive || ! $this->is_dir( $file ) ) {
   396 		if ( ! $recursive || ! $this->is_dir( $file ) ) {
   393 			return $this->run_command( sprintf( 'chown %s %s', escapeshellarg( $owner ), escapeshellarg( $file ) ), true );
   397 			return $this->run_command( sprintf( 'chown %s %s', escapeshellarg( $owner ), escapeshellarg( $file ) ), true );
   394 		}
   398 		}
       
   399 
   395 		return $this->run_command( sprintf( 'chown -R %s %s', escapeshellarg( $owner ), escapeshellarg( $file ) ), true );
   400 		return $this->run_command( sprintf( 'chown -R %s %s', escapeshellarg( $owner ), escapeshellarg( $file ) ), true );
   396 	}
   401 	}
   397 
   402 
   398 	/**
   403 	/**
   399 	 * Gets the file owner.
   404 	 * Gets the file owner.
   403 	 * @param string $file Path to the file.
   408 	 * @param string $file Path to the file.
   404 	 * @return string|false Username of the owner on success, false on failure.
   409 	 * @return string|false Username of the owner on success, false on failure.
   405 	 */
   410 	 */
   406 	public function owner( $file ) {
   411 	public function owner( $file ) {
   407 		$owneruid = @fileowner( $this->sftp_path( $file ) );
   412 		$owneruid = @fileowner( $this->sftp_path( $file ) );
       
   413 
   408 		if ( ! $owneruid ) {
   414 		if ( ! $owneruid ) {
   409 			return false;
   415 			return false;
   410 		}
   416 		}
       
   417 
   411 		if ( ! function_exists( 'posix_getpwuid' ) ) {
   418 		if ( ! function_exists( 'posix_getpwuid' ) ) {
   412 			return $owneruid;
   419 			return $owneruid;
   413 		}
   420 		}
       
   421 
   414 		$ownerarray = posix_getpwuid( $owneruid );
   422 		$ownerarray = posix_getpwuid( $owneruid );
       
   423 
       
   424 		if ( ! $ownerarray ) {
       
   425 			return false;
       
   426 		}
       
   427 
   415 		return $ownerarray['name'];
   428 		return $ownerarray['name'];
   416 	}
   429 	}
   417 
   430 
   418 	/**
   431 	/**
   419 	 * Gets the permissions of the specified file or filepath in their octal format.
   432 	 * Gets the permissions of the specified file or filepath in their octal format.
   435 	 * @param string $file Path to the file.
   448 	 * @param string $file Path to the file.
   436 	 * @return string|false The group on success, false on failure.
   449 	 * @return string|false The group on success, false on failure.
   437 	 */
   450 	 */
   438 	public function group( $file ) {
   451 	public function group( $file ) {
   439 		$gid = @filegroup( $this->sftp_path( $file ) );
   452 		$gid = @filegroup( $this->sftp_path( $file ) );
       
   453 
   440 		if ( ! $gid ) {
   454 		if ( ! $gid ) {
   441 			return false;
   455 			return false;
   442 		}
   456 		}
       
   457 
   443 		if ( ! function_exists( 'posix_getgrgid' ) ) {
   458 		if ( ! function_exists( 'posix_getgrgid' ) ) {
   444 			return $gid;
   459 			return $gid;
   445 		}
   460 		}
       
   461 
   446 		$grouparray = posix_getgrgid( $gid );
   462 		$grouparray = posix_getgrgid( $gid );
       
   463 
       
   464 		if ( ! $grouparray ) {
       
   465 			return false;
       
   466 		}
       
   467 
   447 		return $grouparray['name'];
   468 		return $grouparray['name'];
   448 	}
   469 	}
   449 
   470 
   450 	/**
   471 	/**
   451 	 * Copies a file.
   472 	 * Copies a file.
   462 	 */
   483 	 */
   463 	public function copy( $source, $destination, $overwrite = false, $mode = false ) {
   484 	public function copy( $source, $destination, $overwrite = false, $mode = false ) {
   464 		if ( ! $overwrite && $this->exists( $destination ) ) {
   485 		if ( ! $overwrite && $this->exists( $destination ) ) {
   465 			return false;
   486 			return false;
   466 		}
   487 		}
       
   488 
   467 		$content = $this->get_contents( $source );
   489 		$content = $this->get_contents( $source );
       
   490 
   468 		if ( false === $content ) {
   491 		if ( false === $content ) {
   469 			return false;
   492 			return false;
   470 		}
   493 		}
       
   494 
   471 		return $this->put_contents( $destination, $content, $mode );
   495 		return $this->put_contents( $destination, $content, $mode );
   472 	}
   496 	}
   473 
   497 
   474 	/**
   498 	/**
   475 	 * Moves a file.
   499 	 * Moves a file.
   481 	 * @param bool   $overwrite   Optional. Whether to overwrite the destination file if it exists.
   505 	 * @param bool   $overwrite   Optional. Whether to overwrite the destination file if it exists.
   482 	 *                            Default false.
   506 	 *                            Default false.
   483 	 * @return bool True on success, false on failure.
   507 	 * @return bool True on success, false on failure.
   484 	 */
   508 	 */
   485 	public function move( $source, $destination, $overwrite = false ) {
   509 	public function move( $source, $destination, $overwrite = false ) {
   486 		return @ssh2_sftp_rename( $this->sftp_link, $source, $destination );
   510 		if ( $this->exists( $destination ) ) {
       
   511 			if ( $overwrite ) {
       
   512 				// We need to remove the destination file before we can rename the source.
       
   513 				$this->delete( $destination, false, 'f' );
       
   514 			} else {
       
   515 				// If we're not overwriting, the rename will fail, so return early.
       
   516 				return false;
       
   517 			}
       
   518 		}
       
   519 
       
   520 		return ssh2_sftp_rename( $this->sftp_link, $source, $destination );
   487 	}
   521 	}
   488 
   522 
   489 	/**
   523 	/**
   490 	 * Deletes a file or directory.
   524 	 * Deletes a file or directory.
   491 	 *
   525 	 *
   492 	 * @since 2.7.0
   526 	 * @since 2.7.0
   493 	 *
   527 	 *
   494 	 * @param string       $file      Path to the file or directory.
   528 	 * @param string       $file      Path to the file or directory.
   495 	 * @param bool         $recursive Optional. If set to true, changes file group recursively.
   529 	 * @param bool         $recursive Optional. If set to true, deletes files and folders recursively.
   496 	 *                                Default false.
   530 	 *                                Default false.
   497 	 * @param string|false $type      Type of resource. 'f' for file, 'd' for directory.
   531 	 * @param string|false $type      Type of resource. 'f' for file, 'd' for directory.
   498 	 *                                Default false.
   532 	 *                                Default false.
   499 	 * @return bool True on success, false on failure.
   533 	 * @return bool True on success, false on failure.
   500 	 */
   534 	 */
   501 	public function delete( $file, $recursive = false, $type = false ) {
   535 	public function delete( $file, $recursive = false, $type = false ) {
   502 		if ( 'f' == $type || $this->is_file( $file ) ) {
   536 		if ( 'f' === $type || $this->is_file( $file ) ) {
   503 			return ssh2_sftp_unlink( $this->sftp_link, $file );
   537 			return ssh2_sftp_unlink( $this->sftp_link, $file );
   504 		}
   538 		}
       
   539 
   505 		if ( ! $recursive ) {
   540 		if ( ! $recursive ) {
   506 			return ssh2_sftp_rmdir( $this->sftp_link, $file );
   541 			return ssh2_sftp_rmdir( $this->sftp_link, $file );
   507 		}
   542 		}
       
   543 
   508 		$filelist = $this->dirlist( $file );
   544 		$filelist = $this->dirlist( $file );
       
   545 
   509 		if ( is_array( $filelist ) ) {
   546 		if ( is_array( $filelist ) ) {
   510 			foreach ( $filelist as $filename => $fileinfo ) {
   547 			foreach ( $filelist as $filename => $fileinfo ) {
   511 				$this->delete( $file . '/' . $filename, $recursive, $fileinfo['type'] );
   548 				$this->delete( $file . '/' . $filename, $recursive, $fileinfo['type'] );
   512 			}
   549 			}
   513 		}
   550 		}
       
   551 
   514 		return ssh2_sftp_rmdir( $this->sftp_link, $file );
   552 		return ssh2_sftp_rmdir( $this->sftp_link, $file );
   515 	}
   553 	}
   516 
   554 
   517 	/**
   555 	/**
   518 	 * Checks if a file or directory exists.
   556 	 * Checks if a file or directory exists.
   569 	 *
   607 	 *
   570 	 * @param string $file Path to file or directory.
   608 	 * @param string $file Path to file or directory.
   571 	 * @return bool Whether $file is writable.
   609 	 * @return bool Whether $file is writable.
   572 	 */
   610 	 */
   573 	public function is_writable( $file ) {
   611 	public function is_writable( $file ) {
   574 		// PHP will base it's writable checks on system_user === file_owner, not ssh_user === file_owner
   612 		// PHP will base its writable checks on system_user === file_owner, not ssh_user === file_owner.
   575 		return true;
   613 		return true;
   576 	}
   614 	}
   577 
   615 
   578 	/**
   616 	/**
   579 	 * Gets the file's last access time.
   617 	 * Gets the file's last access time.
   642 	 *                          Default false.
   680 	 *                          Default false.
   643 	 * @return bool True on success, false on failure.
   681 	 * @return bool True on success, false on failure.
   644 	 */
   682 	 */
   645 	public function mkdir( $path, $chmod = false, $chown = false, $chgrp = false ) {
   683 	public function mkdir( $path, $chmod = false, $chown = false, $chgrp = false ) {
   646 		$path = untrailingslashit( $path );
   684 		$path = untrailingslashit( $path );
       
   685 
   647 		if ( empty( $path ) ) {
   686 		if ( empty( $path ) ) {
   648 			return false;
   687 			return false;
   649 		}
   688 		}
   650 
   689 
   651 		if ( ! $chmod ) {
   690 		if ( ! $chmod ) {
   652 			$chmod = FS_CHMOD_DIR;
   691 			$chmod = FS_CHMOD_DIR;
   653 		}
   692 		}
       
   693 
   654 		if ( ! ssh2_sftp_mkdir( $this->sftp_link, $path, $chmod, true ) ) {
   694 		if ( ! ssh2_sftp_mkdir( $this->sftp_link, $path, $chmod, true ) ) {
   655 			return false;
   695 			return false;
   656 		}
   696 		}
       
   697 
       
   698 		// Set directory permissions.
       
   699 		ssh2_sftp_chmod( $this->sftp_link, $path, $chmod );
       
   700 
   657 		if ( $chown ) {
   701 		if ( $chown ) {
   658 			$this->chown( $path, $chown );
   702 			$this->chown( $path, $chown );
   659 		}
   703 		}
       
   704 
   660 		if ( $chgrp ) {
   705 		if ( $chgrp ) {
   661 			$this->chgrp( $path, $chgrp );
   706 			$this->chgrp( $path, $chgrp );
   662 		}
   707 		}
       
   708 
   663 		return true;
   709 		return true;
   664 	}
   710 	}
   665 
   711 
   666 	/**
   712 	/**
   667 	 * Deletes a directory.
   713 	 * Deletes a directory.
   708 			$path       = dirname( $path );
   754 			$path       = dirname( $path );
   709 		} else {
   755 		} else {
   710 			$limit_file = false;
   756 			$limit_file = false;
   711 		}
   757 		}
   712 
   758 
   713 		if ( ! $this->is_dir( $path ) ) {
   759 		if ( ! $this->is_dir( $path ) || ! $this->is_readable( $path ) ) {
   714 			return false;
   760 			return false;
   715 		}
   761 		}
   716 
   762 
   717 		$ret = array();
   763 		$ret = array();
   718 		$dir = @dir( $this->sftp_path( $path ) );
   764 		$dir = dir( $this->sftp_path( $path ) );
   719 
   765 
   720 		if ( ! $dir ) {
   766 		if ( ! $dir ) {
   721 			return false;
   767 			return false;
   722 		}
   768 		}
   723 
   769 
   724 		while ( false !== ( $entry = $dir->read() ) ) {
   770 		while ( false !== ( $entry = $dir->read() ) ) {
   725 			$struc         = array();
   771 			$struc         = array();
   726 			$struc['name'] = $entry;
   772 			$struc['name'] = $entry;
   727 
   773 
   728 			if ( '.' == $struc['name'] || '..' == $struc['name'] ) {
   774 			if ( '.' === $struc['name'] || '..' === $struc['name'] ) {
   729 				continue; //Do not care about these folders.
   775 				continue; // Do not care about these folders.
   730 			}
   776 			}
   731 
   777 
   732 			if ( ! $include_hidden && '.' == $struc['name'][0] ) {
   778 			if ( ! $include_hidden && '.' === $struc['name'][0] ) {
   733 				continue;
   779 				continue;
   734 			}
   780 			}
   735 
   781 
   736 			if ( $limit_file && $struc['name'] != $limit_file ) {
   782 			if ( $limit_file && $struc['name'] != $limit_file ) {
   737 				continue;
   783 				continue;
   742 			$struc['number']      = false;
   788 			$struc['number']      = false;
   743 			$struc['owner']       = $this->owner( $path . '/' . $entry );
   789 			$struc['owner']       = $this->owner( $path . '/' . $entry );
   744 			$struc['group']       = $this->group( $path . '/' . $entry );
   790 			$struc['group']       = $this->group( $path . '/' . $entry );
   745 			$struc['size']        = $this->size( $path . '/' . $entry );
   791 			$struc['size']        = $this->size( $path . '/' . $entry );
   746 			$struc['lastmodunix'] = $this->mtime( $path . '/' . $entry );
   792 			$struc['lastmodunix'] = $this->mtime( $path . '/' . $entry );
   747 			$struc['lastmod']     = date( 'M j', $struc['lastmodunix'] );
   793 			$struc['lastmod']     = gmdate( 'M j', $struc['lastmodunix'] );
   748 			$struc['time']        = date( 'h:i:s', $struc['lastmodunix'] );
   794 			$struc['time']        = gmdate( 'h:i:s', $struc['lastmodunix'] );
   749 			$struc['type']        = $this->is_dir( $path . '/' . $entry ) ? 'd' : 'f';
   795 			$struc['type']        = $this->is_dir( $path . '/' . $entry ) ? 'd' : 'f';
   750 
   796 
   751 			if ( 'd' == $struc['type'] ) {
   797 			if ( 'd' === $struc['type'] ) {
   752 				if ( $recursive ) {
   798 				if ( $recursive ) {
   753 					$struc['files'] = $this->dirlist( $path . '/' . $struc['name'], $include_hidden, $recursive );
   799 					$struc['files'] = $this->dirlist( $path . '/' . $struc['name'], $include_hidden, $recursive );
   754 				} else {
   800 				} else {
   755 					$struc['files'] = array();
   801 					$struc['files'] = array();
   756 				}
   802 				}
   757 			}
   803 			}
   758 
   804 
   759 			$ret[ $struc['name'] ] = $struc;
   805 			$ret[ $struc['name'] ] = $struc;
   760 		}
   806 		}
       
   807 
   761 		$dir->close();
   808 		$dir->close();
   762 		unset( $dir );
   809 		unset( $dir );
       
   810 
   763 		return $ret;
   811 		return $ret;
   764 	}
   812 	}
   765 }
   813 }