diff --git a/includes/filetransfer/filetransfer.inc b/includes/filetransfer/filetransfer.inc index bd2057c..230c0c5 100644 --- a/includes/filetransfer/filetransfer.inc +++ b/includes/filetransfer/filetransfer.inc @@ -1,7 +1,12 @@ jail = $jail; } /** + * Defines a factory method for this class. + * * Classes that extend this class must override the factory() static method. + * They should return a new instance of the appropriate FileTransfer subclass. * * @param string $jail * The full path where all file operations performed by this object will @@ -34,19 +73,25 @@ abstract class FileTransfer { * An array of connection settings for the FileTransfer subclass. If the * getSettingsForm() method uses any nested settings, the same structure * will be assumed here. - * @return object - * New instance of the appropriate FileTransfer subclass. + * + * @throws FileTransferException */ static function factory($jail, $settings) { throw new FileTransferException('FileTransfer::factory() static method not overridden by FileTransfer subclass.'); } /** - * Implementation of the magic __get() method. + * Implements the magic __get() method. + * + * If the connection isn't set to anything, this will call the connect() + * method and return the result; afterwards, the connection will be returned + * directly without using this method. * - * If the connection isn't set to anything, this will call the connect() method - * and set it to and return the result; afterwards, the connection will be - * returned directly without using this method. + * @param $name + * The name of the variable to return. + * + * @return + * The variable specified in $name. */ function __get($name) { if ($name == 'connection') { @@ -81,11 +126,18 @@ abstract class FileTransfer { } /** - * @see http://php.net/chmod + * Changes the permissions of the file / directory specified. * * @param string $path + * The file / directory to change the permissions of. * @param long $mode + * @see http://php.net/chmod * @param bool $recursive + * Pass TRUE to recursively chmod the entire directory specified in $path. + * + * @throws FileTransferException + * + * @see http://php.net/chmod */ public final function chmod($path, $mode, $recursive = FALSE) { if (!in_array('FileTransferChmodInterface', class_implements(get_class($this)))) { @@ -153,6 +205,8 @@ abstract class FileTransfer { * * @param $path * A path to check against the jail. + * + * @throws FileTransferException */ protected final function checkPath($path) { $full_jail = $this->chroot . $this->jail; @@ -165,14 +219,18 @@ abstract class FileTransfer { /** * Returns a modified path suitable for passing to the server. - * If a path is a windows path, makes it POSIX compliant by removing the drive letter. - * If $this->chroot has a value, it is stripped from the path to allow for - * chroot'd filetransfer systems. + * + * If a path is a windows path, makes it POSIX compliant by removing the drive + * letter. If $this->chroot has a value, it is stripped from the path to allow + * for chroot'd filetransfer systems. * * @param $path + * The path to modify. * @param $strip_chroot + * Whether to remove the path in $this->chroot. * * @return string + * The modified path. */ protected final function fixRemotePath($path, $strip_chroot = TRUE) { $path = $this->sanitizePath($path); @@ -189,7 +247,10 @@ abstract class FileTransfer { * Changes backslashes to slashes, also removes a trailing slash. * * @param string $path + * The path to modify. + * * @return string + * The modified path. */ function sanitizePath($path) { $path = str_replace('\\', '/', $path); // Windows path sanitization. @@ -202,7 +263,7 @@ abstract class FileTransfer { /** * Copies a directory. * - * We need a separate method to make the $destination is in the jail. + * We need a separate method to make sure that $destination is in the jail. * * @param $source * The source path. @@ -260,12 +321,10 @@ abstract class FileTransfer { abstract protected function removeFileJailed($destination); /** - * Checks if a particular path is a directory + * Checks if a particular path is a directory. * * @param $path - * The path to check - * - * @return boolean + * The path to check. */ abstract public function isDirectory($path); @@ -273,9 +332,7 @@ abstract class FileTransfer { * Checks if a particular path is a file (not a directory). * * @param $path - * The path to check - * - * @return boolean + * The path to check. */ abstract public function isFile($path); @@ -286,7 +343,7 @@ abstract class FileTransfer { * it will return the chroot, otherwise FALSE. * * @return - * The chroot path for this connection or FALSE. + * The chroot path for this connection, or FALSE. */ function findChroot() { // If the file exists as is, there is no chroot. @@ -312,7 +369,7 @@ abstract class FileTransfer { } /** - * Sets the chroot and changes the jail to match the correct path scheme + * Sets the chroot and changes the jail to match the correct path scheme. * */ function setChroot() { @@ -325,6 +382,9 @@ abstract class FileTransfer { * * Implementing classes can either extend this form with fields collecting the * specific information they need, or override it entirely. + * + * @return + * Array containing a form definition. */ public function getSettingsForm() { $form['username'] = array( @@ -358,11 +418,27 @@ abstract class FileTransfer { } /** - * FileTransferException class. + * Defines an exception class for file transfers. */ class FileTransferException extends Exception { + + /** + * Arguments to be used in this exception. + * + * @var array + */ public $arguments; + /** + * Constructs a FileTransferException object. + * + * @param $message + * Exception message. + * @param $code + * Exception code. + * @param $arguments + * Arguments to be used in this exception. + */ function __construct($message, $code = 0, $arguments = array()) { parent::__construct($message, $code); $this->arguments = $arguments; @@ -371,7 +447,7 @@ class FileTransferException extends Exception { /** - * A FileTransfer Class implementing this interface can be used to chmod files. + * Defines an interface to chmod files. */ interface FileTransferChmodInterface { @@ -382,7 +458,7 @@ interface FileTransferChmodInterface { * Path to change permissions of. * @param long $mode * @see http://php.net/chmod - * @param boolean $recursive + * @param bool $recursive * Pass TRUE to recursively chmod the entire directory specified in $path. */ function chmodJailed($path, $mode, $recursive); @@ -399,7 +475,7 @@ interface FileTransferChmodInterface { */ class SkipDotsRecursiveDirectoryIterator extends RecursiveDirectoryIterator { /** - * Constructs a SkipDotsRecursiveDirectoryIterator + * Constructs a SkipDotsRecursiveDirectoryIterator object. * * @param $path * The path of the directory to be iterated over. @@ -408,6 +484,11 @@ class SkipDotsRecursiveDirectoryIterator extends RecursiveDirectoryIterator { parent::__construct($path); } + /** + * Overrides RecursiveDirectoryIterator::next(). + * + * Keeps calling parent::next() until a directory is found that isn't . or .. + */ function next() { parent::next(); while ($this->isDot()) { diff --git a/includes/filetransfer/ftp.inc b/includes/filetransfer/ftp.inc index 838dc7c..2591c72 100644 --- a/includes/filetransfer/ftp.inc +++ b/includes/filetransfer/ftp.inc @@ -1,10 +1,18 @@ username = $username; $this->password = $password; @@ -14,13 +22,13 @@ abstract class FileTransferFTP extends FileTransfer { } /** - * Return an object which can implement the FTP protocol. + * Overrides FileTransfer::factory(). * - * @param string $jail - * @param array $settings * @return FileTransferFTP * The appropriate FileTransferFTP subclass based on the available * options. If the FTP PHP extension is available, use it. + * + * @throws FileTransferException */ static function factory($jail, $settings) { $username = empty($settings['username']) ? '' : $settings['username']; @@ -39,7 +47,7 @@ abstract class FileTransferFTP extends FileTransfer { } /** - * Returns the form to configure the FileTransfer class for FTP. + * Overrides FileTransfer::getSettingsForm(). */ public function getSettingsForm() { $form = parent::getSettingsForm(); @@ -48,8 +56,16 @@ abstract class FileTransferFTP extends FileTransfer { } } +/** + * Defines a file transfer class using the PHP FTP extension. + */ class FileTransferFTPExtension extends FileTransferFTP implements FileTransferChmodInterface { + /** + * Overrides FileTransferFTP::connect(). + * + * @throws FileTransferException + */ public function connect() { $this->connection = ftp_connect($this->hostname, $this->port); @@ -61,18 +77,33 @@ class FileTransferFTPExtension extends FileTransferFTP implements FileTransferCh } } + /** + * Overrides FileTransferFTP::copyFileJailed(). + * + * @throws FileTransferException + */ protected function copyFileJailed($source, $destination) { if (!@ftp_put($this->connection, $destination, $source, FTP_BINARY)) { throw new FileTransferException("Cannot move @source to @destination", NULL, array("@source" => $source, "@destination" => $destination)); } } + /** + * Overrides FileTransferFTP::createDirectoryJailed(). + * + * @throws FileTransferException + */ protected function createDirectoryJailed($directory) { if (!ftp_mkdir($this->connection, $directory)) { throw new FileTransferException("Cannot create directory @directory", NULL, array("@directory" => $directory)); } } + /** + * Overrides FileTransferFTP::removeDirectoryJailed(). + * + * @throws FileTransferException + */ protected function removeDirectoryJailed($directory) { $pwd = ftp_pwd($this->connection); if (!ftp_chdir($this->connection, $directory)) { @@ -100,12 +131,23 @@ class FileTransferFTPExtension extends FileTransferFTP implements FileTransferCh } } + /** + * Overrides FileTransferFTP::removeFileJailed(). + * + * @throws FileTransferException + */ protected function removeFileJailed($destination) { if (!ftp_delete($this->connection, $destination)) { throw new FileTransferException("Unable to remove to file @file", NULL, array('@file' => $destination)); } } + /** + * Overrides FileTransferFTP::isDirectory(). + * + * @return + * TRUE if $path is a directory, FALSE if not. + */ public function isDirectory($path) { $result = FALSE; $curr = ftp_pwd($this->connection); @@ -116,10 +158,21 @@ class FileTransferFTPExtension extends FileTransferFTP implements FileTransferCh return $result; } + /** + * Overrides FileTransferFTP::isFile(). + * + * @return + * TRUE if $path is a file, FALSE if not. + */ public function isFile($path) { return ftp_size($this->connection, $path) != -1; } + /** + * Implements FileTransferChmodInterface::chmodJailed(). + * + * @throws FileTransferException + */ function chmodJailed($path, $mode, $recursive) { if (!ftp_chmod($this->connection, $mode, $path)) { throw new FileTransferException("Unable to set permissions on %file", NULL, array ('%file' => $path)); @@ -137,6 +190,9 @@ class FileTransferFTPExtension extends FileTransferFTP implements FileTransferCh } } +/** + * Changes the permissions of the file / directory using an FTP SITE command. + */ if (!function_exists('ftp_chmod')) { function ftp_chmod($ftp_stream, $mode, $filename) { return ftp_site($ftp_stream, sprintf('CHMOD %o %s', $mode, $filename)); diff --git a/includes/filetransfer/local.inc b/includes/filetransfer/local.inc index b125989..2c80a58 100644 --- a/includes/filetransfer/local.inc +++ b/includes/filetransfer/local.inc @@ -1,30 +1,59 @@ $source, '%destination' => $destination)); } } + /** + * Overrides FileTransfer::createDirectoryJailed(). + * + * @throws FileTransferException + */ protected function createDirectoryJailed($directory) { if (!is_dir($directory) && @!mkdir($directory, 0777, TRUE)) { throw new FileTransferException('Cannot create directory %directory.', NULL, array('%directory' => $directory)); } } + /** + * Overrides FileTransfer::removeDirectoryJailed(). + * + * @throws FileTransferException + */ protected function removeDirectoryJailed($directory) { if (!is_dir($directory)) { // Programmer error assertion, not something we expect users to see. @@ -47,20 +76,42 @@ class FileTransferLocal extends FileTransfer implements FileTransferChmodInterfa } } + /** + * Overrides FileTransfer::removeFileJailed(). + * + * @throws FileTransferException + */ protected function removeFileJailed($file) { if (@!drupal_unlink($file)) { throw new FileTransferException('Cannot remove file %file.', NULL, array('%file' => $file)); } } + /** + * Overrides FileTransfer::isDirectory(). + * + * @return + * TRUE if $path is a directory, FALSE if not. + */ public function isDirectory($path) { return is_dir($path); } + /** + * Overrides FileTransfer::isFile(). + * + * @return + * TRUE if $path is a file, FALSE if not. + */ public function isFile($path) { return is_file($path); } + /** + * Implements FileTransferChmodInterface::chmodJailed(). + * + * @throws FileTransferException + */ public function chmodJailed($path, $mode, $recursive) { if ($recursive && is_dir($path)) { foreach (new RecursiveIteratorIterator(new SkipDotsRecursiveDirectoryIterator($path), RecursiveIteratorIterator::SELF_FIRST) as $filename => $file) { diff --git a/includes/filetransfer/ssh.inc b/includes/filetransfer/ssh.inc index 43ec324..8d44bb0 100644 --- a/includes/filetransfer/ssh.inc +++ b/includes/filetransfer/ssh.inc @@ -1,10 +1,18 @@ username = $username; $this->password = $password; @@ -13,6 +21,11 @@ class FileTransferSSH extends FileTransfer implements FileTransferChmodInterface parent::__construct($jail); } + /** + * Overrides FileTransfer::connect(). + * + * @throws FileTransferException + */ function connect() { $this->connection = @ssh2_connect($this->hostname, $this->port); if (!$this->connection) { @@ -23,6 +36,12 @@ class FileTransferSSH extends FileTransfer implements FileTransferChmodInterface } } + /** + * Overrides FileTransfer::factory(). + * + * @return FileTransferSSH + * Returns a FileTransferSSH object + */ static function factory($jail, $settings) { $username = empty($settings['username']) ? '' : $settings['username']; $password = empty($settings['password']) ? '' : $settings['password']; @@ -31,30 +50,55 @@ class FileTransferSSH extends FileTransfer implements FileTransferChmodInterface return new FileTransferSSH($jail, $username, $password, $hostname, $port); } + /** + * Overrides FileTransfer::copyFileJailed(). + * + * @throws FileTransferException + */ protected function copyFileJailed($source, $destination) { if (!@ssh2_scp_send($this->connection, $source, $destination)) { throw new FileTransferException('Cannot copy @source_file to @destination_file.', NULL, array('@source' => $source, '@destination' => $destination)); } } + /** + * Overrides FileTransfer::copyDirectoryJailed(). + * + * @throws FileTransferException + */ protected function copyDirectoryJailed($source, $destination) { if (@!ssh2_exec($this->connection, 'cp -Rp ' . escapeshellarg($source) . ' ' . escapeshellarg($destination))) { throw new FileTransferException('Cannot copy directory @directory.', NULL, array('@directory' => $source)); } } + /** + * Overrides FileTransfer::createDirectoryJailed(). + * + * @throws FileTransferException + */ protected function createDirectoryJailed($directory) { if (@!ssh2_exec($this->connection, 'mkdir ' . escapeshellarg($directory))) { throw new FileTransferException('Cannot create directory @directory.', NULL, array('@directory' => $directory)); } } + /** + * Overrides FileTransfer::removeDirectoryJailed(). + * + * @throws FileTransferException + */ protected function removeDirectoryJailed($directory) { if (@!ssh2_exec($this->connection, 'rm -Rf ' . escapeshellarg($directory))) { throw new FileTransferException('Cannot remove @directory.', NULL, array('@directory' => $directory)); } } + /** + * Overrides FileTransfer::removeFileJailed(). + * + * @throws FileTransferException + */ protected function removeFileJailed($destination) { if (!@ssh2_exec($this->connection, 'rm ' . escapeshellarg($destination))) { throw new FileTransferException('Cannot remove @directory.', NULL, array('@directory' => $destination)); @@ -62,7 +106,14 @@ class FileTransferSSH extends FileTransfer implements FileTransferChmodInterface } /** - * WARNING: This is untested. It is not currently used, but should do the trick. + * Overrides FileTransfer::isDirectory(). + * + * WARNING: This is untested. It's not currently used, but should work. + * + * @return + * TRUE if $path is a directory, FALSE if not. + * + * @throws FileTransferException */ public function isDirectory($path) { $directory = escapeshellarg($path); @@ -77,6 +128,14 @@ class FileTransferSSH extends FileTransfer implements FileTransferChmodInterface } } + /** + * Overrides FileTransfer::isFile(). + * + * @return + * TRUE if $path is a directory, FALSE if not. + * + * @throws FileTransferException + */ public function isFile($path) { $file = escapeshellarg($path); $cmd = "[ -f {$file} ] && echo 'yes'"; @@ -90,6 +149,11 @@ class FileTransferSSH extends FileTransfer implements FileTransferChmodInterface } } + /** + * Implements FileTransferChmodInterface::chmodJailed(). + * + * @throws FileTransferException + */ function chmodJailed($path, $mode, $recursive) { $cmd = sprintf("chmod %s%o %s", $recursive ? '-R ' : '', $mode, escapeshellarg($path)); if (@!ssh2_exec($this->connection, $cmd)) { @@ -98,7 +162,7 @@ class FileTransferSSH extends FileTransfer implements FileTransferChmodInterface } /** - * Returns the form to configure the FileTransfer class for SSH. + * Overrides FileTransfer::getSettingsForm(). */ public function getSettingsForm() { $form = parent::getSettingsForm();