Rev 320 | Blame | Compare with Previous | Last modification | View Log | RSS feed
<?php/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: *//*** Net_FTP main file.** This file must be included to use the Net_FTP package.** PHP versions 4 and 5** LICENSE: This source file is subject to version 3.0 of the PHP license* that is available through the world-wide-web at the following URI:* http://www.php.net/license/3_0.txt. If you did not receive a copy of* the PHP License and are unable to obtain it through the web, please* send a note to license@php.net so we can mail you a copy immediately.** @category Networking* @package FTP* @author Tobias Schlitt <toby@php.net>* @copyright 1997-2005 The PHP Group* @license http://www.php.net/license/3_0.txt PHP License 3.0* @version CVS: $Id: FTP.php,v 1.2 2006-10-05 08:55:35 florian Exp $* @link http://pear.php.net/package/Net_FTP* @since File available since Release 0.0.1*/require_once 'PEAR.php';/*** Option to let the ls() method return only files.** @since 1.3* @name NET_FTP_FILES_ONLY* @see Net_FTP::ls()*/define('NET_FTP_FILES_ONLY', 0, true);/*** Option to let the ls() method return only directories.** @since 1.3* @name NET_FTP_DIRS_ONLY* @see Net_FTP::ls()*/define('NET_FTP_DIRS_ONLY', 1, true);/*** Option to let the ls() method return directories and files (default).** @since 1.3* @name NET_FTP_DIRS_FILES* @see Net_FTP::ls()*/define('NET_FTP_DIRS_FILES', 2, true);/*** Option to let the ls() method return the raw directory listing from ftp_rawlist().** @since 1.3* @name NET_FTP_RAWLIST* @see Net_FTP::ls()*/define('NET_FTP_RAWLIST', 3, true);/*** Error code to indicate a failed connection* This error code indicates, that the connection you tryed to set up* could not be established. Check your connection settings (host & port)!** @since 1.3* @name NET_FTP_ERR_CONNECT_FAILED* @see Net_FTP::connect()*/define('NET_FTP_ERR_CONNECT_FAILED', -1);/*** Error code to indicate a failed login* This error code indicates, that the login to the FTP server failed. Check* your user data (username & password).** @since 1.3* @name NET_FTP_ERR_LOGIN_FAILED* @see Net_FTP::login()*/define('NET_FTP_ERR_LOGIN_FAILED', -2);/*** Error code to indicate a failed directory change* The cd() method failed. Ensure that the directory you wanted to access exists.** @since 1.3* @name NET_FTP_ERR_DIRCHANGE_FAILED* @see Net_FTP::cd()*/define('NET_FTP_ERR_DIRCHANGE_FAILED', 2); // Compatibillity reasons!/*** Error code to indicate that Net_FTP could not determine the current path* The cwd() method failed and could not determine the path you currently reside* in on the FTP server.** @since 1.3* @name NET_FTP_ERR_DETERMINEPATH_FAILED* @see Net_FTP::pwd()*/define('NET_FTP_ERR_DETERMINEPATH_FAILED', 4); // Compatibillity reasons!/*** Error code to indicate that the creation of a directory failed* The directory you tryed to create could not be created. Check the* access rights on the parent directory!** @since 1.3* @name NET_FTP_ERR_CREATEDIR_FAILED* @see Net_FTP::mkdir()*/define('NET_FTP_ERR_CREATEDIR_FAILED', -4);/*** Error code to indicate that the EXEC execution failed.* The execution of a command using EXEC failed. Ensure, that your* FTP server supports the EXEC command.** @since 1.3* @name NET_FTP_ERR_EXEC_FAILED* @see Net_FTP::execute()*/define('NET_FTP_ERR_EXEC_FAILED', -5);/*** Error code to indicate that the SITE command failed.* The execution of a command using SITE failed. Ensure, that your* FTP server supports the SITE command.** @since 1.3* @name NET_FTP_ERR_SITE_FAILED* @see Net_FTP::site()*/define('NET_FTP_ERR_SITE_FAILED', -6);/*** Error code to indicate that the CHMOD command failed.* The execution of CHMOD failed. Ensure, that your* FTP server supports the CHMOD command and that you have the appropriate* access rights to use CHMOD.** @since 1.3* @name NET_FTP_ERR_CHMOD_FAILED* @see Net_FTP::chmod()*/define('NET_FTP_ERR_CHMOD_FAILED', -7);/*** Error code to indicate that a file rename failed* The renaming of a file on the server failed. Ensure that you have the* appropriate access rights to rename the file.** @since 1.3* @name NET_FTP_ERR_RENAME_FAILED* @see Net_FTP::rename()*/define('NET_FTP_ERR_RENAME_FAILED', -8);/*** Error code to indicate that the MDTM command failed* The MDTM command is not supported for directories. Ensure that you gave* a file path to the mdtm() method, not a directory path.** @since 1.3* @name NET_FTP_ERR_MDTMDIR_UNSUPPORTED* @see Net_FTP::mdtm()*/define('NET_FTP_ERR_MDTMDIR_UNSUPPORTED', -9);/*** Error code to indicate that the MDTM command failed* The MDTM command failed. Ensure that your server supports the MDTM command.** @since 1.3* @name NET_FTP_ERR_MDTM_FAILED* @see Net_FTP::mdtm()*/define('NET_FTP_ERR_MDTM_FAILED', -10);/*** Error code to indicate that a date returned by the server was misformated* A date string returned by your server seems to be missformated and could not be* parsed. Check that the server is configured correctly. If you're sure, please* send an email to the auhtor with a dumped output of $ftp->ls('./', NET_FTP_RAWLIST);* to get the date format supported.** @since 1.3* @name NET_FTP_ERR_DATEFORMAT_FAILED* @see Net_FTP::mdtm(), Net_FTP::ls()*/define('NET_FTP_ERR_DATEFORMAT_FAILED', -11);/*** Error code to indicate that the SIZE command failed* The determination of the filesize of a file failed. Ensure that your server supports the* SIZE command.** @since 1.3* @name NET_FTP_ERR_SIZE_FAILED* @see Net_FTP::size()*/define('NET_FTP_ERR_SIZE_FAILED', -12);/*** Error code to indicate that a local file could not be overwritten* You specified not to overwrite files. Therefore the local file has not been* overwriten. If you want to get the file overwriten, please set the option to* do so.** @since 1.3* @name NET_FTP_ERR_OVERWRITELOCALFILE_FORBIDDEN* @see Net_FTP::get(), Net_FTP::getRecursive()*/define('NET_FTP_ERR_OVERWRITELOCALFILE_FORBIDDEN', -13);/*** Error code to indicate that a local file could not be overwritten* Also you specified to overwrite the local file you want to download to,* it has not been possible to do so. Check that you have the appropriate access* rights on the local file to overwrite it.** @since 1.3* @name NET_FTP_ERR_OVERWRITELOCALFILE_FAILED* @see Net_FTP::get(), Net_FTP::getRecursive()*/define('NET_FTP_ERR_OVERWRITELOCALFILE_FAILED', -14);/*** Error code to indicate that the file you wanted to upload does not exist* The file you tried to upload does not exist. Ensure that it exists.** @since 1.3* @name NET_FTP_ERR_LOCALFILENOTEXIST* @see Net_FTP::put(), Net_FTP::putRecursive()*/define('NET_FTP_ERR_LOCALFILENOTEXIST', -15);/*** Error code to indicate that a remote file could not be overwritten* You specified not to overwrite files. Therefore the remote file has not been* overwriten. If you want to get the file overwriten, please set the option to* do so.** @since 1.3* @name NET_FTP_ERR_OVERWRITEREMOTEFILE_FORBIDDEN* @see Net_FTP::put(), Net_FTP::putRecursive()*/define('NET_FTP_ERR_OVERWRITEREMOTEFILE_FORBIDDEN', -16);/*** Error code to indicate that the upload of a file failed* The upload you tried failed. Ensure that you have appropriate access rights* to upload the desired file.** @since 1.3* @name NET_FTP_ERR_UPLOADFILE_FAILED* @see Net_FTP::put(), Net_FTP::putRecursive()*/define('NET_FTP_ERR_UPLOADFILE_FAILED', -17);/*** Error code to indicate that you specified an incorrect directory path* The remote path you specified seems not to be a directory. Ensure that* the path you specify is a directory and that the path string ends with* a /.** @since 1.3* @name NET_FTP_ERR_REMOTEPATHNODIR* @see Net_FTP::putRecursive(), Net_FTP::getRecursive()*/define('NET_FTP_ERR_REMOTEPATHNODIR', -18);/*** Error code to indicate that you specified an incorrect directory path* The local path you specified seems not to be a directory. Ensure that* the path you specify is a directory and that the path string ends with* a /.** @since 1.3* @name NET_FTP_ERR_LOCALPATHNODIR* @see Net_FTP::putRecursive(), Net_FTP::getRecursive()*/define('NET_FTP_ERR_LOCALPATHNODIR', -19);/*** Error code to indicate that a local directory failed to be created* You tried to create a local directory through getRecursive() method,* which has failed. Ensure that you have the appropriate access rights* to create it.** @since 1.3* @name NET_FTP_ERR_CREATELOCALDIR_FAILED* @see Net_FTP::getRecursive()*/define('NET_FTP_ERR_CREATELOCALDIR_FAILED', -20);/*** Error code to indicate that the provided hostname was incorrect* The hostname you provided was invalid. Ensure to provide either a* full qualified domain name or an IP address.** @since 1.3* @name NET_FTP_ERR_HOSTNAMENOSTRING* @see Net_FTP::setHostname()*/define('NET_FTP_ERR_HOSTNAMENOSTRING', -21);/*** Error code to indicate that the provided port was incorrect* The port number you provided was invalid. Ensure to provide either a* a numeric port number greater zero.** @since 1.3* @name NET_FTP_ERR_PORTLESSZERO* @see Net_FTP::setPort()*/define('NET_FTP_ERR_PORTLESSZERO', -22);/*** Error code to indicate that you provided an invalid mode constant* The mode constant you provided was invalid. You may only provide* FTP_ASCII or FTP_BINARY.** @since 1.3* @name NET_FTP_ERR_NOMODECONST* @see Net_FTP::setMode()*/define('NET_FTP_ERR_NOMODECONST', -23);/*** Error code to indicate that you provided an invalid timeout* The timeout you provided was invalid. You have to provide a timeout greater* or equal to zero.** @since 1.3* @name NET_FTP_ERR_TIMEOUTLESSZERO* @see Net_FTP::Net_FTP(), Net_FTP::setTimeout()*/define('NET_FTP_ERR_TIMEOUTLESSZERO', -24);/*** Error code to indicate that you provided an invalid timeout* An error occured while setting the timeout. Ensure that you provide a* valid integer for the timeount and that your PHP installation works* correctly.** @since 1.3* @name NET_FTP_ERR_SETTIMEOUT_FAILED* @see Net_FTP::Net_FTP(), Net_FTP::setTimeout()*/define('NET_FTP_ERR_SETTIMEOUT_FAILED', -25);/*** Error code to indicate that the provided extension file doesn't exist* The provided extension file does not exist. Ensure to provided an* existant extension file.** @since 1.3* @name NET_FTP_ERR_EXTFILENOTEXIST* @see Net_FTP::getExtensionFile()*/define('NET_FTP_ERR_EXTFILENOTEXIST', -26);/*** Error code to indicate that the provided extension file is not readable* The provided extension file is not readable. Ensure to have sufficient* access rights for it.** @since 1.3* @name NET_FTP_ERR_EXTFILEREAD_FAILED* @see Net_FTP::getExtensionFile()*/define('NET_FTP_ERR_EXTFILEREAD_FAILED', -27);/*** Error code to indicate that the deletion of a file failed* The specified file could not be deleted. Ensure to have sufficient* access rights to delete the file.** @since 1.3* @name NET_FTP_ERR_EXTFILEREAD_FAILED* @see Net_FTP::rm()*/define('NET_FTP_ERR_DELETEFILE_FAILED', -28);/*** Error code to indicate that the deletion of a directory faild* The specified file could not be deleted. Ensure to have sufficient* access rights to delete the file.** @since 1.3* @name NET_FTP_ERR_EXTFILEREAD_FAILED* @see Net_FTP::rm()*/define('NET_FTP_ERR_DELETEDIR_FAILED', -29);/*** Error code to indicate that the directory listing failed* PHP could not list the directory contents on the server. Ensure* that your server is configured appropriate.** @since 1.3* @name NET_FTP_ERR_RAWDIRLIST_FAILED* @see Net_FTP::ls()*/define('NET_FTP_ERR_RAWDIRLIST_FAILED', -30);/*** Error code to indicate that the directory listing failed* The directory listing format your server uses seems not to* be supported by Net_FTP. Please send the output of the* call ls('./', NET_FTP_RAWLIST); to the author of this* class to get it supported.** @since 1.3* @name NET_FTP_ERR_DIRLIST_UNSUPPORTED* @see Net_FTP::ls()*/define('NET_FTP_ERR_DIRLIST_UNSUPPORTED', -31);/*** Error code to indicate failed disconnecting* This error code indicates, that disconnection was not possible.** @since 1.3* @name NET_FTP_ERR_DISCONNECT_FAILED* @see Net_FTP::disconnect()*/define('NET_FTP_ERR_DISCONNECT_FAILED', -32);/*** Error code to indicate that the username you provided was invalid.* Check that you provided a non-empty string as the username.** @since 1.3* @name NET_FTP_ERR_USERNAMENOSTRING* @see Net_FTP::setUsername()*/define('NET_FTP_ERR_USERNAMENOSTRING', -33);/*** Error code to indicate that the username you provided was invalid.* Check that you provided a non-empty string as the username.** @since 1.3* @name NET_FTP_ERR_PASSWORDNOSTRING* @see Net_FTP::setPassword()*/define('NET_FTP_ERR_PASSWORDNOSTRING', -33);/*** Class for comfortable FTP-communication** This class provides comfortable communication with FTP-servers. You may do everything* enabled by the PHP-FTP-extension and further functionalities, like recursive-deletion,* -up- and -download. Another feature is to create directories recursively.** @license http://www.php.net/license/3_0.txt PHP License 3.0* @category Networking* @package FTP* @author Tobias Schlitt <toby@php.net>* @copyright 1997-2005 The PHP Group* @version Release: @package_version@* @link http://pear.php.net/package/Net_FTP* @since 0.0.1* @access public*/class Net_FTP extends PEAR{/*** The host to connect to** @access private* @var string*/var $_hostname;/*** The port for ftp-connection (standard is 21)** @access private* @var int*/var $_port = 21;/*** The username for login** @access private* @var string*/var $_username;/*** The password for login** @access private* @var string*/var $_password;/*** Determine whether to use passive-mode (true) or active-mode (false)** @access private* @var bool*/var $_passv;/*** The standard mode for ftp-transfer** @access private* @var int*/var $_mode = FTP_BINARY;/*** This holds the handle for the ftp-connection** @access private* @var resource*/var $_handle;/*** Contains the timeout for FTP operations** @access private* @var int* @since 1.3*/var $_timeout = 90;/*** Saves file-extensions for ascii- and binary-mode** The array contains 2 sub-arrays ("ascii" and "binary"), which both contain* file-extensions without the "." (".php" = "php").** @access private* @var array*/var $_file_extensions;/*** ls match* Matches the ls entries against a regex and maps the resulting array to speaking names** @access private* @var array* @since 1.3*/var $_ls_match = array('unix' => array('pattern' => '/(?:(d)|.)([rwxt-]+)\s+(\w+)\s+([\w\d-]+)\s+([\w\d-]+)\s+(\w+)\s+(\S+\s+\S+\s+\S+)\s+(.+)/','map' => array('is_dir' => 1,'rights' => 2,'files_inside' => 3,'user' => 4,'group' => 5,'size' => 6,'date' => 7,'name' => 8,)),'windows' => array('pattern' => '/(.+)\s+(.+)\s+((<DIR>)|[0-9]+)\s+(.+)/','map' => array('name' => 5,'date' => 1,'size' => 3,'is_dir' => 4,)));/*** matcher* Stores the matcher for the current connection** @access private* @var array* @since 1.3*/var $_matcher = null;/*** Holds all Net_FTP_Observer objects* that wish to be notified of new messages.** @var array* @access private* @since 1.3*/var $_listeners = array();/*** This generates a new FTP-Object. The FTP-connection will not be established, yet.* You can leave $host and $port blank, if you want. The $host will not be set* and the $port will be left at 21. You have to set the $host manualy before* trying to connect or with the connect() method.** @access public* @param string $host (optional) The hostname* @param int $port (optional) The port* @param int $timeout (optional) Sets the standard timeout* @return void* @see Net_FTP::setHostname(), Net_FTP::setPort(), Net_FTP::connect()*/function Net_FTP($host = null, $port = null, $timeout = 90){$this->PEAR();if (isset($host)) {$this->setHostname($host);}if (isset($port)) {$this->setPort($port);}$this->_timeout = $timeout;$this->_file_extensions[FTP_ASCII] = array();$this->_file_extensions[FTP_BINARY] = array();}/*** This function generates the FTP-connection. You can optionally define a* hostname and/or a port. If you do so, this data is stored inside the object.** @access public* @param string $host (optional) The Hostname* @param int $port (optional) The Port* @return mixed True on success, otherwise PEAR::Error* @see NET_FTP_ERR_CONNECT_FAILED*/function connect($host = null, $port = null){$this->_matcher = null;if (isset($host)) {$this->setHostname($host);}if (isset($port)) {$this->setPort($port);}$handle = @ftp_connect($this->getHostname(), $this->getPort(), $this->_timeout);if (!$handle) {return $this->raiseError("Connection to host failed", NET_FTP_ERR_CONNECT_FAILED);} else {$this->_handle =& $handle;return true;}}/*** This function close the FTP-connection** @access public* @return bool|PEAR_Error Returns true on success, PEAR_Error on failure*/function disconnect(){$res = @ftp_close($this->_handle);if (!$res) {return PEAR::raiseError('Disconnect failed.', NET_FTP_ERR_DISCONNECT_FAILED);}return true;}/*** This logges you into the ftp-server. You are free to specify username and password* in this method. If you specify it, the values will be taken into the corresponding* attributes, if do not specify, the attributes are taken.** @access public* @param string $username (optional) The username to use* @param string $password (optional) The password to use* @return mixed True on success, otherwise PEAR::Error* @see NET_FTP_ERR_LOGIN_FAILED*/function login($username = null, $password = null){if (!isset($username)) {$username = $this->getUsername();} else {$this->setUsername($username);}if (!isset($password)) {$password = $this->getPassword();} else {$this->setPassword($password);}$res = @ftp_login($this->_handle, $username, $password);if (!$res) {return $this->raiseError("Unable to login", NET_FTP_ERR_LOGIN_FAILED);} else {return true;}}/*** This changes the currently used directory. You can use either an absolute* directory-path (e.g. "/home/blah") or a relative one (e.g. "../test").** @access public* @param string $dir The directory to go to.* @return mixed True on success, otherwise PEAR::Error* @see NET_FTP_ERR_DIRCHANGE_FAILED*/function cd($dir){$erg = @ftp_chdir($this->_handle, $dir);if (!$erg) {return $this->raiseError("Directory change failed", NET_FTP_ERR_DIRCHANGE_FAILED);} else {return true;}}/*** Show's you the actual path on the server* This function questions the ftp-handle for the actual selected path and returns it.** @access public* @return mixed The actual path or PEAR::Error* @see NET_FTP_ERR_DETERMINEPATH_FAILED*/function pwd(){$res = @ftp_pwd($this->_handle);if (!$res) {return $this->raiseError("Could not determine the actual path.", NET_FTP_ERR_DETERMINEPATH_FAILED);} else {return $res;}}/*** This works similar to the mkdir-command on your local machine. You can either give* it an absolute or relative path. The relative path will be completed with the actual* selected server-path. (see: pwd())** @access public* @param string $dir Absolute or relative dir-path* @param bool $recursive (optional) Create all needed directories* @return mixed True on success, otherwise PEAR::Error* @see NET_FTP_ERR_CREATEDIR_FAILED*/function mkdir($dir, $recursive = false){$dir = $this->_construct_path($dir);$savedir = $this->pwd();$this->pushErrorHandling(PEAR_ERROR_RETURN);$e = $this->cd($dir);$this->popErrorHandling();if ($e === true) {$this->cd($savedir);return true;}$this->cd($savedir);if ($recursive === false){$res = @ftp_mkdir($this->_handle, $dir);if (!$res) {return $this->raiseError("Creation of '$dir' failed", NET_FTP_ERR_CREATEDIR_FAILED);} else {return true;}} else {if(strpos($dir, '/') === false) {return $this->mkdir($dir,false);}$pos = 0;$res = $this->mkdir(dirname($dir), true);$res = $this->mkdir($dir, false);if ($res !== true) {return $res;}return true;}}/*** This method tries executing a command on the ftp, using SITE EXEC.** @access public* @param string $command The command to execute* @return mixed The result of the command (if successfull), otherwise PEAR::Error* @see NET_FTP_ERR_EXEC_FAILED*/function execute($command){$res = @ftp_exec($this->_handle, $command);if (!$res) {return $this->raiseError("Execution of command '$command' failed.", NET_FTP_ERR_EXEC_FAILED);} else {return $res;}}/*** Execute a SITE command on the server* This method tries to execute a SITE command on the ftp server.** @access public* @param string $command The command with parameters to execute* @return mixed True if successful, otherwise PEAR::Error* @see NET_FTP_ERR_SITE_FAILED*/function site($command){$res = @ftp_site($this->_handle, $command);if (!$res) {return $this->raiseError("Execution of SITE command '$command' failed.", NET_FTP_ERR_SITE_FAILED);} else {return $res;}}/*** This method will try to chmod the file specified on the server* Currently, you must give a number as the the permission argument (777 or* similar). The file can be either a relative or absolute path.* NOTE: Some servers do not support this feature. In that case, you will* get a PEAR error object returned. If successful, the method returns true** @access public* @param mixed $target The file or array of files to set permissions for* @param integer $permissions The mode to set the file permissions to* @return mixed True if successful, otherwise PEAR::Error* @see NET_FTP_ERR_CHMOD_FAILED*/function chmod($target, $permissions){// If $target is an array: Loop through it.if (is_array($target)) {for ($i = 0; $i < count($target); $i++) {$res = $this->chmod($target[$i], $permissions);if (PEAR::isError($res)) {return $res;} // end if isError} // end for i < count($target)} else {$res = $this->site("CHMOD " . $permissions . " " . $target);if (!$res) {return PEAR::raiseError("CHMOD " . $permissions . " " . $target . " failed", NET_FTP_ERR_CHMOD_FAILED);} else {return $res;}} // end if is_array} // end method chmod/*** This method will try to chmod a folder and all of its contents* on the server. The target argument must be a folder or an array of folders* and the permissions argument have to be an integer (i.e. 777).* The file can be either a relative or absolute path.* NOTE: Some servers do not support this feature. In that case, you* will get a PEAR error object returned. If successful, the method* returns true** @access public* @param mixed $target The folder or array of folders to* set permissions for* @param integer $permissions The mode to set the folder* and file permissions to* @return mixed True if successful, otherwise PEAR::Error* @see NET_FTP_ERR_CHMOD_FAILED, NET_FTP_ERR_DETERMINEPATH_FAILED, NET_FTP_ERR_RAWDIRLIST_FAILED, NET_FTP_ERR_DIRLIST_UNSUPPORTED*/function chmodRecursive($target, $permissions){static $dir_permissions;if(!isset($dir_permissions)){ // Making directory specific permissions$dir_permissions = $this->_makeDirPermissions($permissions);}// If $target is an array: Loop through itif (is_array($target)) {for ($i = 0; $i < count($target); $i++) {$res = $this->chmodRecursive($target[$i], $permissions);if (PEAR::isError($res)) {return $res;} // end if isError} // end for i < count($target)} else {$remote_path = $this->_construct_path($target);// Chmod the directory itself$result = $this->chmod($remote_path, $dir_permissions);if (PEAR::isError($result)) {return $result;}// If $remote_path last character is not a slash, add oneif (substr($remote_path, strlen($remote_path)-1) != "/") {$remote_path .= "/";}$dir_list = array();$mode = NET_FTP_DIRS_ONLY;$dir_list = $this->ls($remote_path, $mode);foreach ($dir_list as $dir_entry) {if ($dir_entry == '.' || $dir_entry == '..') {;continue;}$remote_path_new = $remote_path.$dir_entry["name"]."/";// Chmod the directory we're about to enter$result = $this->chmod($remote_path_new, $dir_permissions);if (PEAR::isError($result)) {return $result;}$result = $this->chmodRecursive($remote_path_new, $permissions);if (PEAR::isError($result)) {return $result;}} // end foreach dir_list as dir_entry$file_list = array();$mode = NET_FTP_FILES_ONLY;$file_list = $this->ls($remote_path, $mode);foreach ($file_list as $file_entry) {$remote_file = $remote_path.$file_entry["name"];$result = $this->chmod($remote_file, $permissions);if (PEAR::isError($result)) {return $result;}} // end foreach $file_list} // end if is_arrayreturn true; // No errors} // end method chmodRecursive/*** Rename or move a file or a directory from the ftp-server** @access public* @param string $remote_from The remote file or directory original to rename or move* @param string $remote_to The remote file or directory final to rename or move* @return bool $res True on success, otherwise PEAR::Error* @see NET_FTP_ERR_RENAME_FAILED*/function rename ($remote_from, $remote_to){$res = @ftp_rename($this->_handle, $remote_from, $remote_to);if(!$res) {return $this->raiseError("Could not rename ".$remote_from." to ".$remote_to." !", NET_FTP_ERR_RENAME_FAILED);}return true;}/*** This will return logical permissions mask for directory.* if directory have to be writeable it have also be executable** @access private* @param string $permissions File permissions in digits for file (i.e. 666)* @return string File permissions in digits for directory (i.e. 777)*/function _makeDirPermissions($permissions){$permissions = (string)$permissions;for($i = 0; $i < strlen($permissions); $i++){ // going through (user, group, world)if((int)$permissions{$i} & 4 and !((int)$permissions{$i} & 1)){ // Read permission is set// but execute not yet(int)$permissions{$i} = (int)$permissions{$i} + 1; // Adding execute flag}}return (string)$permissions;}/*** This will return the last modification-time of a file. You can either give this* function a relative or an absolute path to the file to check.* NOTE: Some servers will not support this feature and the function works* only on files, not directories! When successful,* it will return the last modification-time as a unix-timestamp or, when $format is* specified, a preformated timestring.** @access public* @param string $file The file to check* @param string $format (optional) The format to give the date back* if not set, it will return a Unix timestamp* @return mixed Unix timestamp, a preformated date-string or PEAR::Error* @see NET_FTP_ERR_MDTMDIR_UNSUPPORTED, NET_FTP_ERR_MDTM_FAILED, NET_FTP_ERR_DATEFORMAT_FAILED*/function mdtm($file, $format = null){$file = $this->_construct_path($file);if ($this->_check_dir($file)) {return $this->raiseError("Filename '$file' seems to be a directory.", NET_FTP_ERR_MDTMDIR_UNSUPPORTED);}$res = @ftp_mdtm($this->_handle, $file);if ($res == -1) {return $this->raiseError("Could not get last-modification-date of '$file'.", NET_FTP_ERR_MDTM_FAILED);}if (isset($format)) {$res = date($format, $res);if (!$res) {return $this->raiseError("Date-format failed on timestamp '$res'.", NET_FTP_ERR_DATEFORMAT_FAILED);}}return $res;}/*** This will return the size of a given file in bytes. You can either give this function* a relative or an absolute file-path. NOTE: Some servers do not support this feature!** @access public* @param string $file The file to check* @return mixed Size in bytes or PEAR::Error* @see NET_FTP_ERR_SIZE_FAILED*/function size($file){$file = $this->_construct_path($file);$res = @ftp_size($this->_handle, $file);if ($res == -1) {return $this->raiseError("Could not determine filesize of '$file'.", NET_FTP_ERR_SIZE_FAILED);} else {return $res;}}/*** This method returns a directory-list of the current directory or given one.* To display the current selected directory, simply set the first parameter to null* or leave it blank, if you do not want to use any other parameters.* <BR><BR>* There are 4 different modes of listing directories. Either to list only* the files (using NET_FTP_FILES_ONLY), to list only directories (using* NET_FTP_DIRS_ONLY) or to show both (using NET_FTP_DIRS_FILES, which is default).* <BR><BR>* The 4th one is the NET_FTP_RAWLIST, which returns just the array created by the* ftp_rawlist()-function build into PHP.* <BR><BR>* The other function-modes will return an array containing the requested data.* The files and dirs are listed in human-sorted order, but if you select* NET_FTP_DIRS_FILES the directories will be added above the files,* but although both sorted.* <BR><BR>* All elements in the arrays are associative arrays themselves. The have the following* structure:* <BR><BR>* Dirs:<BR>* ["name"] => string The name of the directory<BR>* ["rights"] => string The rights of the directory (in style "rwxr-xr-x")<BR>* ["user"] => string The owner of the directory<BR>* ["group"] => string The group-owner of the directory<BR>* ["files_inside"]=> string The number of files/dirs inside the directory* excluding "." and ".."<BR>* ["date"] => int The creation-date as Unix timestamp<BR>* ["is_dir"] => bool true, cause this is a dir<BR>* <BR><BR>* Files:<BR>* ["name"] => string The name of the file<BR>* ["size"] => int Size in bytes<BR>* ["rights"] => string The rights of the file (in style "rwxr-xr-x")<BR>* ["user"] => string The owner of the file<BR>* ["group"] => string The group-owner of the file<BR>* ["date"] => int The creation-date as Unix timestamp<BR>* ["is_dir"] => bool false, cause this is a file<BR>** @access public* @param string $dir (optional) The directory to list or null, when listing the current directory.* @param int $mode (optional) The mode which types to list (files, directories or both).* @return mixed The directory list as described above or PEAR::Error on failure.* @see NET_FTP_DIRS_FILES, NET_FTP_DIRS_ONLY, NET_FTP_FILES_ONLY, NET_FTP_RAWLIST, NET_FTP_ERR_DETERMINEPATH_FAILED, NET_FTP_ERR_RAWDIRLIST_FAILED, NET_FTP_ERR_DIRLIST_UNSUPPORTED*/function ls($dir = null, $mode = NET_FTP_DIRS_FILES){if (!isset($dir)) {$dir = @ftp_pwd($this->_handle);if (!$dir) {return $this->raiseError("Could not retrieve current directory", NET_FTP_ERR_DETERMINEPATH_FAILED);}}if (($mode != NET_FTP_FILES_ONLY) && ($mode != NET_FTP_DIRS_ONLY) && ($mode != NET_FTP_RAWLIST)) {$mode = NET_FTP_DIRS_FILES;}switch ($mode) {case NET_FTP_DIRS_FILES: $res = $this->_ls_both ( $dir );break;case NET_FTP_DIRS_ONLY: $res = $this->_ls_dirs ( $dir );break;case NET_FTP_FILES_ONLY: $res = $this->_ls_files ( $dir );break;case NET_FTP_RAWLIST: $res = @ftp_rawlist($this->_handle, $dir);break;}return $res;}/*** This method will delete the given file or directory ($path) from the server* (maybe recursive).** Whether the given string is a file or directory is only determined by the last* sign inside the string ("/" or not).** If you specify a directory, you can optionally specify $recursive as true,* to let the directory be deleted recursive (with all sub-directories and files* inherited).** You can either give a absolute or relative path for the file / dir. If you choose to* use the relative path, it will be automatically completed with the actual* selected directory.** @access public* @param string $path The absolute or relative path to the file / directory.* @param bool $recursive (optional)* @return mixed True on success, otherwise PEAR::Error* @see NET_FTP_ERR_DELETEFILE_FAILED, NET_FTP_ERR_DELETEDIR_FAILED, NET_FTP_ERR_REMOTEPATHNODIR*/function rm($path, $recursive = false){$path = $this->_construct_path($path);if ($this->_check_dir($path)) {if ($recursive) {return $this->_rm_dir_recursive($path);} else {return $this->_rm_dir($path);}} else {return $this->_rm_file($path);}}/*** This function will download a file from the ftp-server. You can either spcify a absolute* path to the file (beginning with "/") or a relative one, which will be completed* with the actual directory you selected on the server. You can specify* the path to which the file will be downloaded on the local* maschine, if the file should be overwritten if it exists (optionally, default is* no overwriting) and in which mode (FTP_ASCII or FTP_BINARY) the file should be* downloaded (if you do not specify this, the method tries to determine it automatically* from the mode-directory or uses the default-mode, set by you). If you give a relative* path to the local-file, the script-path is used as basepath.** @access public* @param string $remote_file The absolute or relative path to the file to download* @param string $local_file The local file to put the downloaded in* @param bool $overwrite (optional) Whether to overwrite existing file* @param int $mode (optional) Either FTP_ASCII or FTP_BINARY* @return mixed True on success, otherwise PEAR::Error* @see NET_FTP_ERR_OVERWRITELOCALFILE_FORBIDDEN, NET_FTP_ERR_OVERWRITELOCALFILE_FAILED, NET_FTP_ERR_OVERWRITELOCALFILE_FAILED*/function get($remote_file, $local_file, $overwrite = false, $mode = null){if (!isset($mode)) {$mode = $this->checkFileExtension($remote_file);}$remote_file = $this->_construct_path($remote_file);if (@file_exists($local_file) && !$overwrite) {return $this->raiseError("Local file '$local_file' exists and may not be overwriten.", NET_FTP_ERR_OVERWRITELOCALFILE_FORBIDDEN);}if (@file_exists($local_file) && !@is_writeable($local_file) && $overwrite) {return $this->raiseError("Local file '$local_file' is not writeable. Can not overwrite.", NET_FTP_ERR_OVERWRITELOCALFILE_FAILED);}if (@function_exists('ftp_nb_get')){$res = @ftp_nb_get($this->_handle, $local_file, $remote_file, $mode);while ($res == FTP_MOREDATA) {$this->_announce('nb_get');$res = @ftp_nb_continue ($this->_handle);}} else {$res = @ftp_get($this->_handle, $local_file, $remote_file, $mode);}if (!$res) {return $this->raiseError("File '$remote_file' could not be downloaded to '$local_file'.", NET_FTP_ERR_OVERWRITELOCALFILE_FAILED);} else {return true;}}/*** This function will upload a file to the ftp-server. You can either specify a absolute* path to the remote-file (beginning with "/") or a relative one, which will be completed* with the actual directory you selected on the server. You can specify* the path from which the file will be uploaded on the local* maschine, if the file should be overwritten if it exists (optionally, default is* no overwriting) and in which mode (FTP_ASCII or FTP_BINARY) the file should be* downloaded (if you do not specify this, the method tries to determine it automatically* from the mode-directory or uses the default-mode, set by you). If you give a relative* path to the local-file, the script-path is used as basepath.** @access public* @param string $local_file The local file to upload* @param string $remote_file The absolute or relative path to the file to upload to* @param bool $overwrite (optional) Whether to overwrite existing file* @param int $mode (optional) Either FTP_ASCII or FTP_BINARY* @return mixed True on success, otherwise PEAR::Error* @see NET_FTP_ERR_LOCALFILENOTEXIST, NET_FTP_ERR_OVERWRITEREMOTEFILE_FORBIDDEN, NET_FTP_ERR_UPLOADFILE_FAILED*/function put($local_file, $remote_file, $overwrite = false, $mode = null){if (!isset($mode)) {$mode = $this->checkFileExtension($local_file);}$remote_file = $this->_construct_path($remote_file);if (!@file_exists($local_file)) {return $this->raiseError("Local file '$local_file' does not exist.", NET_FTP_ERR_LOCALFILENOTEXIST);}if ((@ftp_size($this->_handle, $remote_file) != -1) && !$overwrite) {return $this->raiseError("Remote file '$remote_file' exists and may not be overwriten.", NET_FTP_ERR_OVERWRITEREMOTEFILE_FORBIDDEN);}if (function_exists('ftp_nb_put')){$res = @ftp_nb_put($this->_handle, $remote_file, $local_file, $mode);while ($res == FTP_MOREDATA) {$this->_announce('nb_put');$res = @ftp_nb_continue($this->_handle);}} else {$res = @ftp_put($this->_handle, $remote_file, $local_file, $mode);}if (!$res) {return $this->raiseError("File '$local_file' could not be uploaded to '$remote_file'.", NET_FTP_ERR_UPLOADFILE_FAILED);} else {return true;}}/*** This functionality allows you to transfer a whole directory-structure from the* remote-ftp to your local host. You have to give a remote-directory (ending with* '/') and the local directory (ending with '/') where to put the files you download.* The remote path is automatically completed with the current-remote-dir, if you give* a relative path to this function. You can give a relative path for the $local_path,* too. Then the script-basedir will be used for comletion of the path.* The parameter $overwrite will determine, whether to overwrite existing files or not.* Standard for this is false. Fourth you can explicitly set a mode for all transfer-* actions done. If you do not set this, the method tries to determine the transfer-* mode by checking your mode-directory for the file-extension. If the extension is not* inside the mode-directory, it will get your default-mode.** @access public* @param string $remote_path The path to download* @param string $local_path The path to download to* @param bool $overwrite (optional) Whether to overwrite existing files (true) or not (false, standard).* @param int $mode (optional) The transfermode (either FTP_ASCII or FTP_BINARY).* @return mixed True on succes, otherwise PEAR::Error* @see NET_FTP_ERR_OVERWRITELOCALFILE_FORBIDDEN, NET_FTP_ERR_OVERWRITELOCALFILE_FAILED, NET_FTP_ERR_OVERWRITELOCALFILE_FAILED, NET_FTP_ERR_REMOTEPATHNODIR, NET_FTP_ERR_LOCALPATHNODIR,NET_FTP_ERR_CREATELOCALDIR_FAILED*/function getRecursive($remote_path, $local_path, $overwrite = false, $mode = null){$remote_path = $this->_construct_path($remote_path);if (!$this->_check_dir($remote_path)) {return $this->raiseError("Given remote-path '$remote_path' seems not to be a directory.", NET_FTP_ERR_REMOTEPATHNODIR);}if (!$this->_check_dir($local_path)) {return $this->raiseError("Given local-path '$local_path' seems not to be a directory.", NET_FTP_ERR_LOCALPATHNODIR);}if (!@is_dir($local_path)) {$res = @mkdir($local_path);if (!$res) {return $this->raiseError("Could not create dir '$local_path'", NET_FTP_ERR_CREATELOCALDIR_FAILED);}}$dir_list = array();$dir_list = $this->ls($remote_path, NET_FTP_DIRS_ONLY);foreach ($dir_list as $dir_entry) {if ($dir_entry['name'] != '.' && $dir_entry['name'] != '..') {$remote_path_new = $remote_path.$dir_entry["name"]."/";$local_path_new = $local_path.$dir_entry["name"]."/";$result = $this->getRecursive($remote_path_new, $local_path_new, $overwrite, $mode);if ($this->isError($result)) {return $result;}}}$file_list = array();$file_list = $this->ls($remote_path, NET_FTP_FILES_ONLY);foreach ($file_list as $file_entry) {$remote_file = $remote_path.$file_entry["name"];$local_file = $local_path.$file_entry["name"];$result = $this->get($remote_file, $local_file, $overwrite, $mode);if ($this->isError($result)) {return $result;}}return true;}/*** This functionality allows you to transfer a whole directory-structure from your* local host to the remote-ftp. You have to give a remote-directory (ending with* '/') and the local directory (ending with '/') where to put the files you download.* The remote path is automatically completed with the current-remote-dir, if you give* a relative path to this function. You can give a relative path for the $local_path,* too. Then the script-basedir will be used for comletion of the path.* The parameter $overwrite will determine, whether to overwrite existing files or not.* Standard for this is false. Fourth you can explicitly set a mode for all transfer-* actions done. If you do not set this, the method tries to determine the transfer-* mode by checking your mode-directory for the file-extension. If the extension is not* inside the mode-directory, it will get your default-mode.** @access public* @param string $remote_path The path to download* @param string $local_path The path to download to* @param bool $overwrite (optional) Whether to overwrite existing files (true) or not (false, standard).* @param int $mode (optional) The transfermode (either FTP_ASCII or FTP_BINARY).* @return mixed True on succes, otherwise PEAR::Error* @see NET_FTP_ERR_LOCALFILENOTEXIST, NET_FTP_ERR_OVERWRITEREMOTEFILE_FORBIDDEN, NET_FTP_ERR_UPLOADFILE_FAILED, NET_FTP_ERR_LOCALPATHNODIR, NET_FTP_ERR_REMOTEPATHNODIR*/function putRecursive($local_path, $remote_path, $overwrite = false, $mode = null){$remote_path = $this->_construct_path($remote_path);if (!$this->_check_dir($local_path) || !is_dir($local_path)) {return $this->raiseError("Given local-path '$local_path' seems not to be a directory.", NET_FTP_ERR_LOCALPATHNODIR);}if (!$this->_check_dir($remote_path)) {return $this->raiseError("Given remote-path '$remote_path' seems not to be a directory.", NET_FTP_ERR_REMOTEPATHNODIR);}$old_path = $this->pwd();if ($this->isError($this->cd($remote_path))) {$res = $this->mkdir($remote_path);if ($this->isError($res)) {return $res;}}$this->cd($old_path);$dir_list = $this->_ls_local($local_path);foreach ($dir_list["dirs"] as $dir_entry) {$remote_path_new = $remote_path.$dir_entry."/";$local_path_new = $local_path.$dir_entry."/";$result = $this->putRecursive($local_path_new, $remote_path_new, $overwrite, $mode);if ($this->isError($result)) {return $result;}}foreach ($dir_list["files"] as $file_entry) {$remote_file = $remote_path.$file_entry;$local_file = $local_path.$file_entry;$result = $this->put($local_file, $remote_file, $overwrite, $mode);if ($this->isError($result)) {return $result;}}return true;}/*** This checks, whether a file should be transfered in ascii- or binary-mode* by it's file-extension. If the file-extension is not set or* the extension is not inside one of the extension-dirs, the actual set* transfer-mode is returned.** @access public* @param string $filename The filename to be checked* @return int Either FTP_ASCII or FTP_BINARY*/function checkFileExtension($filename){$pattern = "/\.(.*)$/";$has_extension = preg_match($pattern, $filename, $eregs);if (!$has_extension) {return $this->_mode;} else {$ext = $eregs[1];}if (!empty($this->_file_extensions[$ext])) {return $this->_file_extensions[$ext];}return $this->_mode;}/*** Set the Hostname** @access public* @param string $host The Hostname to set* @return bool True on success, otherwise PEAR::Error* @see NET_FTP_ERR_HOSTNAMENOSTRING*/function setHostname($host){if (!is_string($host)) {return PEAR::raiseError("Hostname must be a string.", NET_FTP_ERR_HOSTNAMENOSTRING);}$this->_hostname = $host;return true;}/*** Set the Port** @access public* @param int $port The Port to set* @return bool True on success, otherwise PEAR::Error* @see NET_FTP_ERR_PORTLESSZERO*/function setPort($port){if (!is_int($port) || ($port < 0)) {PEAR::raiseError("Invalid port. Has to be integer >= 0", NET_FTP_ERR_PORTLESSZERO);}$this->_port = $port;return true;}/*** Set the Username** @access public* @param string $user The Username to set* @return mixed True on success, otherwise PEAR::Error* @see NET_FTP_ERR_USERNAMENOSTRING*/function setUsername($user){if (empty($user) || !is_string($user)) {return PEAR::raiseError('Username $user invalid.', NET_FTP_ERR_USERNAMENOSTRING);}$this->_username = $user;}/*** Set the Password** @access private* @param string $password The Password to set* @return void* @see NET_FTP_ERR_PASSWORDNOSTRING*/function setPassword($password){if (empty($password) || !is_string($password)) {return PEAR::raiseError('Password xxx invalid.', NET_FTP_ERR_PASSWORDNOSTRING);}$this->_password = $password;}/*** Set the transfer-mode. You can use the predefined constants* FTP_ASCII or FTP_BINARY. The mode will be stored for any further transfers.** @access public* @param int $mode The mode to set* @return mixed True on success, otherwise PEAR::Error* @see NET_FTP_ERR_NOMODECONST*/function setMode($mode){if (($mode == FTP_ASCII) || ($mode == FTP_BINARY)) {$this->_mode = $mode;return true;} else {return $this->raiseError('FTP-Mode has either to be FTP_ASCII or FTP_BINARY', NET_FTP_ERR_NOMODECONST);}}/*** Set the transfer-method to passive mode** @access public* @return void*/function setPassive(){$this->_passv = true;@ftp_pasv($this->_handle, true);}/*** Set the transfer-method to active mode** @access public* @return void*/function setActive(){$this->_passv = false;@ftp_pasv($this->_handle, false);}/*** Set the timeout for FTP operations* Use this method to set a timeout for FTP operation. Timeout has to be an integer.** @acess public* @param int $timeout the timeout to use* @return bool True on success, otherwise PEAR::Error* @see NET_FTP_ERR_TIMEOUTLESSZERO, NET_FTP_ERR_SETTIMEOUT_FAILED*/function setTimeout ( $timeout = 0 ){if (!is_int($timeout) || ($timeout < 0)) {return PEAR::raiseError("Timeout $timeout is invalid, has to be an integer >= 0", NET_FTP_ERR_TIMEOUTLESSZERO);}$this->_timeout = $timeout;if (isset($this->_handle) && is_resource($this->_handle)) {$res = @ftp_set_option($this->_handle, FTP_TIMEOUT_SEC, $timeout);} else {$res = true;}if (!$res) {return PEAR::raiseError("Set timeout failed.", NET_FTP_ERR_SETTIMEOUT_FAILED);}return true;}/*** Adds an extension to a mode-directory* The mode-directory saves file-extensions coresponding to filetypes* (ascii e.g.: 'php', 'txt', 'htm',...; binary e.g.: 'jpg', 'gif', 'exe',...).* The extensions have to be saved without the '.'. And* can be predefined in an external file (see: getExtensionsFile()).** The array is build like this: 'php' => FTP_ASCII, 'png' => FTP_BINARY** To change the mode of an extension, just add it again with the new mode!** @access public* @param int $mode Either FTP_ASCII or FTP_BINARY* @param string $ext Extension* @return void*/function addExtension($mode, $ext){$this->_file_extensions[$ext] = $mode;}/*** This function removes an extension from the mode-directories* (described above).** @access public* @param string $ext The extension to remove* @return void*/function removeExtension($ext){unset($this->_file_extensions[$ext]);}/*** This get's both (ascii- and binary-mode-directories) from the given file.* Beware, if you read a file into the mode-directory, all former set values* will be unset!** @access public* @param string $filename The file to get from* @return mixed True on success, otherwise PEAR::Error* @see NET_FTP_ERR_EXTFILENOTEXIST, NET_FTP_ERR_EXTFILEREAD_FAILED*/function getExtensionsFile($filename){if (!file_exists($filename)) {return $this->raiseError("Extensions-file '$filename' does not exist", NET_FTP_ERR_EXTFILENOTEXIST);}if (!is_readable($filename)) {return $this->raiseError("Extensions-file '$filename' is not readable", NET_FTP_ERR_EXTFILEREAD_FAILED);}$this->_file_extension = @parse_ini_file($filename);return true;}/*** Returns the Hostname** @access public* @return string The Hostname*/function getHostname(){return $this->_hostname;}/*** Returns the Port** @access public* @return int The Port*/function getPort(){return $this->_port;}/*** Returns the Username** @access public* @return string The Username*/function getUsername(){return $this->_username;}/*** Returns the Password** @access public* @return string The Password*/function getPassword(){return $this->_password;}/*** Returns the Transfermode** @access public* @return int The transfermode, either FTP_ASCII or FTP_BINARY.*/function getMode(){return $this->_mode;}/*** Returns, whether the connection is set to passive mode or not** @access public* @return bool True if passive-, false if active-mode*/function isPassive(){return $this->_passv;}/*** Returns the mode set for a file-extension** @access public* @param string $ext The extension you wanna ask for* @return int Either FTP_ASCII, FTP_BINARY or NULL (if not set a mode for it)*/function getExtensionMode($ext){return @$this->_file_extensions[$ext];}/*** Get the currently set timeout.* Returns the actual timeout set.** @access public* @return int The actual timeout*/function getTimeout ( ){return ftp_get_option($this->_handle, FTP_TIMEOUT_SEC);}/*** Adds a Net_FTP_Observer instance to the list of observers* that are listening for messages emitted by this Net_FTP instance.** @param object $observer The Net_FTP_Observer instance to attach* as a listener.* @return boolean True if the observer is successfully attached.* @access public* @since 1.3*/function attach(&$observer){if (!is_a($observer, 'Net_FTP_Observer')) {return false;}$this->_listeners[$observer->getId()] = &$observer;return true;}/*** Removes a Net_FTP_Observer instance from the list of observers.** @param object $observer The Net_FTP_Observer instance to detach* from the list of listeners.* @return boolean True if the observer is successfully detached.* @access public* @since 1.3*/function detach($observer){if (!is_a($observer, 'Net_FTP_Observer') ||!isset($this->_listeners[$observer->getId()])) {return false;}unset($this->_listeners[$observer->getId()]);return true;}/*** Informs each registered observer instance that a new message has been* sent.** @param mixed $event A hash describing the net event.* @access private* @since 1.3*/function _announce($event){foreach ($this->_listeners as $id => $listener) {$this->_listeners[$id]->notify($event);}}/*** Rebuild the path, if given relative** @access private* @param string $path The path to check and construct* @return string The build path*/function _construct_path($path){if ((substr($path, 0, 1) != "/") && (substr($path, 0, 2) != "./")) {$actual_dir = @ftp_pwd($this->_handle);if (substr($actual_dir, (strlen($actual_dir) - 2), 1) != "/") {$actual_dir .= "/";}$path = $actual_dir.$path;}return $path;}/*** Checks, whether a given string is a directory-path (ends with "/") or not.** @access private* @param string $path Path to check* @return bool True if $path is a directory, otherwise false*/function _check_dir($path){if (!empty($path) && substr($path, (strlen($path) - 1), 1) == "/") {return true;} else {return false;}}/*** This will remove a file** @access private* @param string $file The file to delete* @return mixed True on success, otherwise PEAR::Error* @see NET_FTP_ERR_DELETEFILE_FAILED*/function _rm_file($file){if (substr($file, 0, 1) != "/") {$actual_dir = @ftp_pwd($this->_handle);if (substr($actual_dir, (strlen($actual_dir) - 2), 1) != "/") {$actual_dir .= "/";}$file = $actual_dir.$file;}$res = @ftp_delete($this->_handle, $file);if (!$res) {return $this->raiseError("Could not delete file '$file'.", NET_FTP_ERR_DELETEFILE_FAILED);} else {return true;}}/*** This will remove a dir** @access private* @param string $dir The dir to delete* @return mixed True on success, otherwise PEAR::Error* @see NET_FTP_ERR_REMOTEPATHNODIR, NET_FTP_ERR_DELETEDIR_FAILED*/function _rm_dir($dir){if (substr($dir, (strlen($dir) - 1), 1) != "/") {return $this->raiseError("Directory name '$dir' is invalid, has to end with '/'", NET_FTP_ERR_REMOTEPATHNODIR);}$res = @ftp_rmdir($this->_handle, $dir);if (!$res) {return $this->raiseError("Could not delete directory '$dir'.", NET_FTP_ERR_DELETEDIR_FAILED);} else {return true;}}/*** This will remove a dir and all subdirs and -files** @access private* @param string $file The dir to delete recursively* @return mixed True on success, otherwise PEAR::Error* @see NET_FTP_ERR_REMOTEPATHNODIR, NET_FTP_ERR_DELETEDIR_FAILED*/function _rm_dir_recursive($dir){if (substr($dir, (strlen($dir) - 1), 1) != "/") {return $this->raiseError("Directory name '$dir' is invalid, has to end with '/'", NET_FTP_ERR_REMOTEPATHNODIR);}$file_list = $this->_ls_files($dir);foreach ($file_list as $file) {$file = $dir.$file["name"];$res = $this->rm($file);if ($this->isError($res)) {return $res;}}$dir_list = $this->_ls_dirs($dir);foreach ($dir_list as $new_dir) {if ($new_dir == '.' || $new_dir == '..') {continue;}$new_dir = $dir.$new_dir["name"]."/";$res = $this->_rm_dir_recursive($new_dir);if ($this->isError($res)) {return $res;}}$res = $this->_rm_dir($dir);if (PEAR::isError($res)) {return $res;} else {return true;}}/*** Lists up files and directories** @access private* @param string $dir The directory to list up* @return array An array of dirs and files*/function _ls_both($dir){$list_splitted = $this->_list_and_parse($dir);if (PEAR::isError($list_splitted)) {return $list_splitted;}if (!is_array($list_splitted["files"])) {$list_splitted["files"] = array();}if (!is_array($list_splitted["dirs"])) {$list_splitted["dirs"] = array();}$res = array();@array_splice($res, 0, 0, $list_splitted["files"]);@array_splice($res, 0, 0, $list_splitted["dirs"]);return $res;}/*** Lists up directories** @access private* @param string $dir The directory to list up* @return array An array of dirs*/function _ls_dirs($dir){$list = $this->_list_and_parse($dir);if (PEAR::isError($list)) {return $list;}return $list["dirs"];}/*** Lists up files** @access private* @param string $dir The directory to list up* @return array An array of files*/function _ls_files($dir){$list = $this->_list_and_parse($dir);if (PEAR::isError($list)) {return $list;}return $list["files"];}/*** This lists up the directory-content and parses the items into well-formated arrays* The results of this array are sorted (dirs on top, sorted by name;* files below, sorted by name).** @access private* @param string $dir The directory to parse* @return array Lists of dirs and files* @see NET_FTP_ERR_RAWDIRLIST_FAILED*/function _list_and_parse($dir){$dirs_list = array();$files_list = array();$dir_list = @ftp_rawlist($this->_handle, $dir);if (!is_array($dir_list)) {return PEAR::raiseError('Could not get raw directory listing.', NET_FTP_ERR_RAWDIRLIST_FAILED);}// Handle empty directoriesif (count($dir_list) == 0) {return array('dirs' => $dirs_list, 'files' => $files_list);}// Exception for some FTP servers seem to return this wiered result instead of an empty listif (count($dirs_list) == 1 && $dirs_list[0] == 'total 0') {return array('dirs' => array(), 'files' => $files_list);}if (!isset($this->_matcher) || PEAR::isError($this->_matcher)) {$this->_matcher = $this->_determine_os_match($dir_list);if (PEAR::isError($this->_matcher)) {return $this->_matcher;}}foreach ($dir_list as $entry) {if (!preg_match($this->_matcher['pattern'], $entry, $m)) {continue;}$entry = array();foreach ($this->_matcher['map'] as $key=>$val) {$entry[$key] = $m[$val];}$entry['stamp'] = $this->_parse_Date($entry['date']);if ($entry['is_dir']) {$dirs_list[] = $entry;} else {$files_list[] = $entry;}}@usort($dirs_list, array("Net_FTP", "_nat_sort"));@usort($files_list, array("Net_FTP", "_nat_sort"));$res["dirs"] = (is_array($dirs_list)) ? $dirs_list : array();$res["files"] = (is_array($files_list)) ? $files_list : array();return $res;}/*** Determine server OS* This determines the server OS and returns a valid regex to parse* ls() output.** @access private* @param array $dir_list The raw dir list to parse* @return mixed An array of 'pattern' and 'map' on success, otherwise PEAR::Error* @see NET_FTP_ERR_DIRLIST_UNSUPPORTED*/function _determine_os_match(&$dir_list) {foreach ($dir_list as $entry) {foreach ($this->_ls_match as $os => $match) {if (preg_match($match['pattern'], $entry)) {return $match;}}}$error = 'The list style of your server seems not to be supported. Please email a "$ftp->ls(NET_FTP_RAWLIST);" output plus info on the server to the maintainer of this package to get it supported! Thanks for your help!';return PEAR::raiseError($error, NET_FTP_ERR_DIRLIST_UNSUPPORTED);}/*** Lists a local directory** @access private* @param string $dir_path The dir to list* @return array The list of dirs and files*/function _ls_local($dir_path){$dir = dir($dir_path);$dir_list = array();$file_list = array();while (false !== ($entry = $dir->read())) {if (($entry != '.') && ($entry != '..')) {if (is_dir($dir_path.$entry)) {$dir_list[] = $entry;} else {$file_list[] = $entry;}}}$dir->close();$res['dirs'] = $dir_list;$res['files'] = $file_list;return $res;}/*** Function for use with usort().* Compares the list-array-elements by name.** @access private*/function _nat_sort($item_1, $item_2){return strnatcmp($item_1['name'], $item_2['name']);}/*** Parse dates to timestamps** @access private* @param string $date Date* @return int Timestamp* @see NET_FTP_ERR_DATEFORMAT_FAILED*/function _parse_Date($date){// Sep 10 22:06 => Sep 10, <year> 22:06if (preg_match('/([A-Za-z]+)[ ]+([0-9]+)[ ]+([0-9]+):([0-9]+)/', $date, $res)) {$year = date('Y');$month = $res[1];$day = $res[2];$hour = $res[3];$minute = $res[4];$date = "$month $day, $year $hour:$minute";$tmpDate = strtotime($date);if ($tmpDate > time()) {$year--;$date = "$month $day, $year $hour:$minute";}}// 09-10-04 => 09/10/04elseif (preg_match('/^\d\d-\d\d-\d\d/',$date)) {$date = str_replace('-','/',$date);}$res = strtotime($date);if (!$res) {return $this->raiseError('Dateconversion failed.', NET_FTP_ERR_DATEFORMAT_FAILED);}return $res;}}?>