Source for file FTP.php
Documentation is available at FTP.php
// +----------------------------------------------------------------------+
// | Net_FTP Version 1.3 |
// +----------------------------------------------------------------------+
// | Copyright (c) 2001-2004 Tobias Schlitt |
// +----------------------------------------------------------------------+
// | This source file is subject to version 3.0 of the PHP license, |
// | that is available at through the world-wide-web at |
// | 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 world-wide-web, please send a note to |
// | license@php.net so we can mail you a copy immediately. |
// +----------------------------------------------------------------------+
// | Authors: Tobias Schlitt <toby@php.net> |
// +----------------------------------------------------------------------+
// $Id: FTP.php,v 1.26 2004/06/14 22:26:48 toby Exp $
* Option to let the ls() method return only files.
* @name NET_FTP_FILES_ONLY
define('NET_FTP_FILES_ONLY', 0 , true );
* Option to let the ls() method return only directories.
* @name NET_FTP_DIRS_ONLY
define('NET_FTP_DIRS_ONLY', 1 , true );
* Option to let the ls() method return directories and files (default).
* @name NET_FTP_DIRS_FILES
define('NET_FTP_DIRS_FILES', 2 , true );
* Option to let the ls() method return the raw directory listing from ftp_rawlist().
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)!
* @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).
* @name NET_FTP_ERR_LOGIN_FAILED
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.
* @name NET_FTP_ERR_DIRCHANGE_FAILED
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
* @name NET_FTP_ERR_DETERMINEPATH_FAILED
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!
* @name NET_FTP_ERR_CREATEDIR_FAILED
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.
* @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.
* @name NET_FTP_ERR_SITE_FAILED
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.
* @name NET_FTP_ERR_CHMOD_FAILED
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.
* @name NET_FTP_ERR_RENAME_FAILED
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.
* @name NET_FTP_ERR_MDTMDIR_UNSUPPORTED
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.
* @name NET_FTP_ERR_MDTM_FAILED
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.
* @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
* @name NET_FTP_ERR_SIZE_FAILED
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
* @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.
* @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.
* @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
* @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.
* @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
* @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
* @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
* @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.
* @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.
* @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.
* @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
* @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
* @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.
* @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
* @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.
* @name NET_FTP_ERR_EXTFILEREAD_FAILED
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.
* @name NET_FTP_ERR_EXTFILEREAD_FAILED
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.
* @name NET_FTP_ERR_RAWDIRLIST_FAILED
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.
* @name NET_FTP_ERR_DIRLIST_UNSUPPORTED
define('NET_FTP_ERR_DIRLIST_UNSUPPORTED', -31 );
* Error code to indicate failed disconnecting
* This error code indicates, that disconnection was not possible.
* @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.
* @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.
* @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.
* @author Tobias Schlitt <toby@php.net>
* @see http://www.schlitt.info
* @license http://www.php.net/license/3_0.txt PHP License 3.0
class Net_FTP extends PEAR
* The port for ftp-connection (standard is 21)
* Determine whether to use passive-mode (true) or active-mode (false)
* The standard mode for ftp-transfer
* This holds the handle for the ftp-connection
* Contains the timeout for FTP operations
* 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").
* Matches the ls entries against a regex and maps the resulting array to speaking names
'pattern' => '/(?:(d)|.)([rwxt-]+)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\S+\s+\S+\s+\S+)\s+(.+)/',
'map' => array ('name'=>8 ,'size'=>6 ,'rights'=>2 ,'user'=>4 ,'group'=>5 ,
'files_inside'=>3 ,'date'=>7 ,'is_dir'=>1 )
'pattern' => '/(.+)\s+(.+)\s+((<DIR>)|[0-9]+)\s+(.+)/',
'map' => array ('name'=>5 ,'date'=>1 ,'is_dir'=>3 )
* Stores the matcher for the current connection
* Holds all Net_FTP_Observer objects
* that wish to be notified of new messages.
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.
* @param string $host (optional) The hostname
* @param int $port (optional) The port
* @param int $timeout (optional) Sets the standard timeout
* @see Net_FTP::setHostname(), Net_FTP::setPort(), Net_FTP::connect()
function Net_FTP ($host = null , $port = null , $timeout = 90 )
$this->setHostname ($host);
$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.
* @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->setHostname ($host);
$handle = @ftp_connect($this->getHostname (), $this->getPort (), $this->_timeout);
$this->_handle = & $handle;
* This function close the FTP-connection
* @return bool|PEAR_ErrorReturns true on success, PEAR_Error on failure
* 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.
* @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 )
$username = $this->getUsername ();
$this->setUsername ($username);
$password = $this->getPassword ();
$this->setPassword ($password);
$res = @ftp_login($this->_handle, $username, $password);
* 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").
* @param string $dir The directory to go to.
* @return mixed True on success, otherwise PEAR::Error
* @see NET_FTP_ERR_DIRCHANGE_FAILED
* Show's you the actual path on the server
* This function questions the ftp-handle for the actual selected path and returns it.
* @return mixed The actual path or PEAR::Error
* @see NET_FTP_ERR_DETERMINEPATH_FAILED
* 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())
* @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);
if ($recursive === false ){
if(strpos($dir, '/') === false ) {
return $this->mkdir ($dir,false );
while (false !== ($pos = strpos($dir, '/', $pos + 1 ))){
$elements[] = substr($dir, 0 , $pos);
foreach ($elements as $element){
$res = $this->mkdir ($element, false );
* This method tries executing a command on the ftp, using SITE EXEC.
* @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);
* Execute a SITE command on the server
* This method tries to execute a SITE command on the ftp server.
* @param string $command The command with parameters to execute
* @return mixed True if successful, otherwise PEAR::Error
* @see NET_FTP_ERR_SITE_FAILED
$res = @ftp_site($this->_handle, $command);
* 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
* @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.
for ($i = 0; $i < count($target); $i++ ) {
$res = $this->chmod ($target[$i], $permissions);
if (PEAR ::isError ($res)) {
} // end for i < count($target)
$res = $this->site ("CHMOD " . $permissions . " " . $target);
* 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
* @param mixed $target The folder or array of folders to
* @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)
if(!isset ($dir_permissions)){ // Making directory specific permissions
$dir_permissions = $this->_makeDirPermissions ($permissions);
// If $target is an array: Loop through it
for ($i = 0; $i < count($target); $i++ ) {
$res = $this->chmodRecursive ($target[$i], $permissions);
if (PEAR ::isError ($res)) {
} // end for i < count($target)
$remote_path = $this->_construct_path ($target);
// Chmod the directory itself
$result = $this->chmod ($remote_path, $dir_permissions);
if (PEAR ::isError ($result)) {
// If $remote_path last character is not a slash, add one
$dir_list = $this->ls ($remote_path, $mode);
foreach ($dir_list as $dir_entry) {
$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)) {
$result = $this->chmodRecursive ($remote_path_new, $permissions);
if (PEAR ::isError ($result)) {
} // end foreach dir_list as dir_entry
$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)) {
} // end foreach $file_list
return true; // No errors
} // end method chmodRecursive
* Rename or move a file or a directory from the ftp-server
* @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);
* This will return logical permissions mask for directory.
* if directory have to be writeable it have also be executable
* @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
(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.
* @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)) {
$res = @ftp_mdtm($this->_handle, $file);
$res = date($format, $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!
* @param string $file The file to check
* @return mixed Size in bytes or PEAR::Error
* @see NET_FTP_ERR_SIZE_FAILED
$file = $this->_construct_path ($file);
$res = @ftp_size($this->_handle, $file);
* 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.
* 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).
* The 4th one is the NET_FTP_RAWLIST, which returns just the array created by the
* ftp_rawlist()-function build into PHP.
* 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.
* All elements in the arrays are associative arrays themselves. The have the following
* ["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>
* ["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>
* @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 )
* This method will delete the given file or directory ($path) from the server
* 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
* 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
* @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)) {
return $this->_rm_dir_recursive ($path);
return $this->_rm_dir ($path);
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.
* @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 )
$mode = $this->checkFileExtension ($remote_file);
$remote_file = $this->_construct_path ($remote_file);
$res = @ftp_nb_get($this->_handle, $local_file, $remote_file, $mode);
while ($res == FTP_MOREDATA ) {
$this->_announce ('nb_get');
$res = @ftp_get($this->_handle, $local_file, $remote_file, $mode);
* 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.
* @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 )
$mode = $this->checkFileExtension ($local_file);
$remote_file = $this->_construct_path ($remote_file);
if ((@ftp_size($this->_handle, $remote_file) != -1 ) && !$overwrite) {
$res = @ftp_nb_put($this->_handle, $remote_file, $local_file, $mode);
while ($res == FTP_MOREDATA ) {
$this->_announce ('nb_put');
$res = @ftp_put($this->_handle, $remote_file, $local_file, $mode);
* 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.
* @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)) {
if (!$this->_check_dir ($local_path)) {
$res = @mkdir($local_path);
foreach ($dir_list as $dir_entry) {
$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)) {
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)) {
* 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.
* @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)) {
if (!$this->_check_dir ($remote_path)) {
$old_path = $this->pwd ();
if ($this->isError ($this->cd ($remote_path))) {
$res = $this->mkdir ($remote_path);
if ($this->isError ($res)) {
$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)) {
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)) {
* 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.
* @param string $filename The filename to be checked
* @return int Either FTP_ASCII or FTP_BINARY
function checkFileExtension ($filename)
$has_extension = preg_match($pattern, $filename, $eregs);
if (!empty ($this->_file_extensions[$ext])) {
return $this->_file_extensions[$ext];
* @param string $host The Hostname to set
* @return bool True on success, otherwise PEAR::Error
* @see NET_FTP_ERR_HOSTNAMENOSTRING
function setHostname ($host)
$this->_hostname = $host;
* @param int $port The Port to set
* @return bool True on success, otherwise PEAR::Error
* @see NET_FTP_ERR_PORTLESSZERO
if (!is_int($port) || ($port < 0 )) {
* @param string $user The Username to set
* @return mixed True on success, otherwise PEAR::Error
* @see NET_FTP_ERR_USERNAMENOSTRING
function setUsername ($user)
$this->_username = $user;
* @param string $password The Password to set
* @see NET_FTP_ERR_PASSWORDNOSTRING
function setPassword ($password)
if (empty ($password) || !is_string($password)) {
$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.
* @param int $mode The mode to set
* @return mixed True on success, otherwise PEAR::Error
* @see NET_FTP_ERR_NOMODECONST
if (($mode == FTP_ASCII ) || ($mode == FTP_BINARY )) {
* Set the transfer-method to passive mode
* Set the transfer-method to active mode
* Set the timeout for FTP operations
* Use this method to set a timeout for FTP operation. Timeout has to be an integer.
* @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 )) {
$this->_timeout = $timeout;
if (isset ($this->_handle) && is_resource($this->_handle)) {
* 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!
* @param int $mode Either FTP_ASCII or FTP_BINARY
* @param string $ext Extension
function addExtension ($mode, $ext)
$this->_file_extensions[$ext] = $mode;
* This function removes an extension from the mode-directories
* @param string $ext The extension to remove
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
* @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)
* @return string The Hostname
* @return string The Username
* @return string The Password
* Returns the Transfermode
* @return int The transfermode, either FTP_ASCII or FTP_BINARY.
* Returns, whether the connection is set to passive mode or not
* @return bool True if passive-, false if active-mode
* Returns the mode set for a file-extension
* @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.
* @return int The actual timeout
* 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
* @return boolean True if the observer is successfully attached.
function attach (&$observer)
if (!is_a($observer, 'Net_FTP_Observer')) {
$this->_listeners[$observer->getId ()] = &$observer;
* 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.
function detach ($observer)
if (!is_a($observer, 'Net_FTP_Observer') ||
!isset ($this->_listeners[$observer->getId ()])) {
unset ($this->_listeners[$observer->getId ()]);
* Informs each registered observer instance that a new message has been
* @param mixed $event A hash describing the net event.
function _announce ($event)
foreach ($this->_listeners as $id => $listener) {
$this->_listeners[$id]->notify ($event);
* Rebuild the path, if given relative
* @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 ) != "/") {
$path = $actual_dir. $path;
* Checks, whether a given string is a directory-path (ends with "/") or not.
* @param string $path Path to check
* @return bool True if $path is a directory, otherwise false
function _check_dir ($path)
* This will remove a file
* @param string $file The file to delete
* @return mixed True on success, otherwise PEAR::Error
* @see NET_FTP_ERR_DELETEFILE_FAILED
if (substr($file, 0 , 1 ) == "/") {
$actual_dir = @ftp_pwd($this->_handle);
if (substr($actual_dir, (strlen($actual_dir) - 2 ), 1 ) != "/") {
$file = $actual_dir. $file;
* @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
* This will remove a dir and all subdirs and -files
* @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)
$file_list = $this->_ls_files ($dir);
foreach ($file_list as $file) {
$file = $dir. $file["name"];
if ($this->isError ($res)) {
$dir_list = $this->_ls_dirs ($dir);
foreach ($dir_list as $new_dir) {
$new_dir = $dir. $new_dir["name"]. "/";
$res = $this->_rm_dir_recursive ($new_dir);
if ($this->isError ($res)) {
$res = $this->_rm_dir ($dir);
* Lists up files and directories
* @param string $dir The directory to list up
* @return array An array of dirs and files
$list_splitted = $this->_list_and_parse ($dir);
if (!is_array($list_splitted["files"])) {
$list_splitted["files"] = array ();
if (!is_array($list_splitted["dirs"])) {
$list_splitted["dirs"] = array ();
* @param string $dir The directory to list up
* @return array An array of dirs
$list = $this->_list_and_parse ($dir);
* @param string $dir The directory to list up
* @return array An array of files
$list = $this->_list_and_parse ($dir);
$list["files"] = array ();
* 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).
* @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)
if ($dir_list === false ) {
if (!isset ($this->_matcher)) {
$this->_matcher = $this->_determine_os_match ($dir_list);
if (PEAR ::isError ($this->_matcher)) {
foreach ($dir_list as $entry) {
if (!preg_match($this->_matcher['pattern'], $entry, $m)) {
foreach ($this->_matcher['map'] as $key=> $val) {
$entry['stamp'] = $this->_parse_Date ($entry['date']);
@usort($dirs_list, array ("Net_FTP", "_nat_sort"));
@usort($files_list, array ("Net_FTP", "_nat_sort"));
$res["dirs"] = $dirs_list;
$res["files"] = $files_list;
* This determines the server OS and returns a valid regex to parse
* @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) {
$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!';
* Lists a local directory
* @param string $dir_path The dir to list
* @return array The list of dirs and files
function _ls_local ($dir_path)
while (false !== ($entry = $dir->read ())) {
if (($entry != '.') && ($entry != '..')) {
if (is_dir($dir_path. $entry)) {
$res['dirs'] = $dir_list;
$res['files'] = $file_list;
* Function for use with usort().
* Compares the list-array-elements by name.
function _nat_sort ($item_1, $item_2)
return strnatcmp($item_1['name'], $item_2['name']);
* Parse dates to timestamps
* @param string $date Date
* @see NET_FTP_ERR_DATEFORMAT_FAILED
function _parse_Date ($date)
// Sep 10 22:06 => Sep 10, <year> 22:06
if (preg_match('/([A-Za-z]+)[ ]+([0-9]+)[ ]+([0-9]+):([0-9]+)/', $date, $res)) {
$date = " $month $day, $year $hour:$minute";
$date = " $month $day, $year $hour:$minute";
Documentation generated on Mon, 11 Mar 2019 13:52:26 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.
|