"\n", 'MAC' => "\r", 'WIN' => "\r\n"); /** * JFTP object constructor * * @access protected * @param array $options Associative array of options to set * @since 1.5 */ function __construct($options=array()) { // If default transfer type is no set, set it to autoascii detect if (!isset ($options['type'])) { $options['type'] = FTP_BINARY; } $this->setOptions($options); if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') { $this->_OS = 'WIN'; } elseif (strtoupper(substr(PHP_OS, 0, 3)) === 'MAC') { $this->_OS = 'MAC'; } else { $this->_OS = 'UNIX'; } if (FTP_NATIVE) { // Import the generic buffer stream handler jimport('joomla.utilities.buffer'); // Autoloading fails for JBuffer as the class is used as a stream handler JLoader::load('JBuffer'); } // Register faked "destructor" in PHP4 to close all connections we might have made if (version_compare(PHP_VERSION, '5') == -1) { register_shutdown_function(array(&$this, '__destruct')); } } /** * JFTP object destructor * * Closes an existing connection, if we have one * * @access protected * @since 1.5 */ function __destruct() { if (is_resource($this->_conn)) { $this->quit(); } } /** * Returns a reference to the global FTP connector object, only creating it * if it doesn't already exist. * * This method must be invoked as: *
$ftp = &JFTP::getInstance($host);* * You may optionally specify a username and password in the parameters. If you do so, * you may not login() again with different credentials using the same object. * If you do not use this option, you must quit() the current connection when you * are done, to free it for use by others. * * @param string $host Host to connect to * @param string $port Port to connect to * @param array $options Array with any of these options: type=>[FTP_AUTOASCII|FTP_ASCII|FTP_BINARY], timeout=>(int) * @param string $user Username to use for a connection * @param string $pass Password to use for a connection * @return JFTP The FTP Client object. * @since 1.5 */ function &getInstance($host = '127.0.0.1', $port = '21', $options = null, $user = null, $pass = null) { static $instances = array(); $signature = $user.':'.$pass.'@'.$host.":".$port; // Create a new instance, or set the options of an existing one if (!isset ($instances[$signature]) || !is_object($instances[$signature])) { $instances[$signature] = new JFTP($options); } else { $instances[$signature]->setOptions($options); } // Connect to the server, and login, if requested if (!$instances[$signature]->isConnected()) { $return = $instances[$signature]->connect($host, $port); if ($return && $user !== null && $pass !== null) { $instances[$signature]->login($user, $pass); } } return $instances[$signature]; } /** * Set client options * * @access public * @param array $options Associative array of options to set * @return boolean True if successful */ function setOptions($options) { if (isset ($options['type'])) { $this->_type = $options['type']; } if (isset ($options['timeout'])) { $this->_timeout = $options['timeout']; } return true; } /** * Method to connect to a FTP server * * @access public * @param string $host Host to connect to [Default: 127.0.0.1] * @param string $port Port to connect on [Default: port 21] * @return boolean True if successful */ function connect($host = '127.0.0.1', $port = 21) { // Initialize variables $errno = null; $err = null; // If already connected, return if (is_resource($this->_conn)) { return true; } // If native FTP support is enabled lets use it... if (FTP_NATIVE) { $this->_conn = @ftp_connect($host, $port, $this->_timeout); if ($this->_conn === false) { JError::raiseWarning('30', 'JFTP::connect: Could not connect to host "'.$host.'" on port '.$port); return false; } // Set the timeout for this connection ftp_set_option($this->_conn, FTP_TIMEOUT_SEC, $this->_timeout); return true; } // Connect to the FTP server. $this->_conn = @ fsockopen($host, $port, $errno, $err, $this->_timeout); if (!$this->_conn) { JError::raiseWarning('30', 'JFTP::connect: Could not connect to host "'.$host.'" on port '.$port, 'Socket error number '.$errno.' and error message: '.$err); return false; } // Set the timeout for this connection socket_set_timeout($this->_conn, $this->_timeout); // Check for welcome response code if (!$this->_verifyResponse(220)) { JError::raiseWarning('35', 'JFTP::connect: Bad response', 'Server response: '.$this->_response.' [Expected: 220]'); return false; } return true; } /** * Method to determine if the object is connected to an FTP server * * @access public * @return boolean True if connected * @since 1.5 */ function isConnected() { return is_resource($this->_conn); } /** * Method to login to a server once connected * * @access public * @param string $user Username to login to the server * @param string $pass Password to login to the server * @return boolean True if successful */ function login($user = 'anonymous', $pass = 'jftp@joomla.org') { // If native FTP support is enabled lets use it... if (FTP_NATIVE) { if (@ftp_login($this->_conn, $user, $pass) === false) { JError::raiseWarning('30', 'JFTP::login: Unable to login' ); return false; } return true; } // Send the username if (!$this->_putCmd('USER '.$user, array(331, 503))) { JError::raiseWarning('33', 'JFTP::login: Bad Username', 'Server response: '.$this->_response.' [Expected: 331] Username sent: '.$user ); return false; } // If we are already logged in, continue :) if ($this->_responseCode == 503) { return true; } // Send the password if (!$this->_putCmd('PASS '.$pass, 230)) { JError::raiseWarning('34', 'JFTP::login: Bad Password', 'Server response: '.$this->_response.' [Expected: 230] Password sent: '.str_repeat('*', strlen($pass))); return false; } return true; } /** * Method to quit and close the connection * * @access public * @return boolean True if successful */ function quit() { // If native FTP support is enabled lets use it... if (FTP_NATIVE) { @ftp_close($this->_conn); return true; } // Logout and close connection @fwrite($this->_conn, "QUIT\r\n"); @fclose($this->_conn); return true; } /** * Method to retrieve the current working directory on the FTP server * * @access public * @return string Current working directory */ function pwd() { // If native FTP support is enabled lets use it... if (FTP_NATIVE) { if (($ret = @ftp_pwd($this->_conn)) === false) { JError::raiseWarning('35', 'JFTP::pwd: Bad response' ); return false; } return $ret; } // Initialize variables $match = array (null); // Send print working directory command and verify success if (!$this->_putCmd('PWD', 257)) { JError::raiseWarning('35', 'JFTP::pwd: Bad response', 'Server response: '.$this->_response.' [Expected: 257]' ); return false; } // Match just the path preg_match('/"[^"\r\n]*"/', $this->_response, $match); // Return the cleaned path return preg_replace("/\"/", "", $match[0]); } /** * Method to system string from the FTP server * * @access public * @return string System identifier string */ function syst() { // If native FTP support is enabled lets use it... if (FTP_NATIVE) { if (($ret = @ftp_systype($this->_conn)) === false) { JError::raiseWarning('35', 'JFTP::syst: Bad response' ); return false; } } else { // Send print working directory command and verify success if (!$this->_putCmd('SYST', 215)) { JError::raiseWarning('35', 'JFTP::syst: Bad response', 'Server response: '.$this->_response.' [Expected: 215]' ); return false; } $ret = $this->_response; } // Match the system string to an OS if (strpos(strtoupper($ret), 'MAC') !== false) { $ret = 'MAC'; } elseif (strpos(strtoupper($ret), 'WIN') !== false) { $ret = 'WIN'; } else { $ret = 'UNIX'; } // Return the os type return $ret; } /** * Method to change the current working directory on the FTP server * * @access public * @param string $path Path to change into on the server * @return boolean True if successful */ function chdir($path) { // If native FTP support is enabled lets use it... if (FTP_NATIVE) { if (@ftp_chdir($this->_conn, $path) === false) { JError::raiseWarning('35', 'JFTP::chdir: Bad response' ); return false; } return true; } // Send change directory command and verify success if (!$this->_putCmd('CWD '.$path, 250)) { JError::raiseWarning('35', 'JFTP::chdir: Bad response', 'Server response: '.$this->_response.' [Expected: 250] Path sent: '.$path ); return false; } return true; } /** * Method to reinitialize the server, ie. need to login again * * NOTE: This command not available on all servers * * @access public * @return boolean True if successful */ function reinit() { // If native FTP support is enabled lets use it... if (FTP_NATIVE) { if (@ftp_site($this->_conn, 'REIN') === false) { JError::raiseWarning('35', 'JFTP::reinit: Bad response' ); return false; } return true; } // Send reinitialize command to the server if (!$this->_putCmd('REIN', 220)) { JError::raiseWarning('35', 'JFTP::reinit: Bad response', 'Server response: '.$this->_response.' [Expected: 220]' ); return false; } return true; } /** * Method to rename a file/folder on the FTP server * * @access public * @param string $from Path to change file/folder from * @param string $to Path to change file/folder to * @return boolean True if successful */ function rename($from, $to) { // If native FTP support is enabled lets use it... if (FTP_NATIVE) { if (@ftp_rename($this->_conn, $from, $to) === false) { JError::raiseWarning('35', 'JFTP::rename: Bad response' ); return false; } return true; } // Send rename from command to the server if (!$this->_putCmd('RNFR '.$from, 350)) { JError::raiseWarning('35', 'JFTP::rename: Bad response', 'Server response: '.$this->_response.' [Expected: 320] From path sent: '.$from ); return false; } // Send rename to command to the server if (!$this->_putCmd('RNTO '.$to, 250)) { JError::raiseWarning('35', 'JFTP::rename: Bad response', 'Server response: '.$this->_response.' [Expected: 250] To path sent: '.$to ); return false; } return true; } /** * Method to change mode for a path on the FTP server * * @access public * @param string $path Path to change mode on * @param string/int $mode Octal value to change mode to, e.g. '0777', 0777 or 511 * @return boolean True if successful */ function chmod($path, $mode) { // If no filename is given, we assume the current directory is the target if ($path == '') { $path = '.'; } // Convert the mode to a string if (is_int($mode)) { $mode = decoct($mode); } // If native FTP support is enabled lets use it... if (FTP_NATIVE) { if (@ftp_site($this->_conn, 'CHMOD '.$mode.' '.$path) === false) { if($this->_OS != 'WIN') { JError::raiseWarning('35', 'JFTP::chmod: Bad response' ); } return false; } return true; } // Send change mode command and verify success [must convert mode from octal] if (!$this->_putCmd('SITE CHMOD '.$mode.' '.$path, array(200, 250))) { if($this->_OS != 'WIN') { JError::raiseWarning('35', 'JFTP::chmod: Bad response', 'Server response: '.$this->_response.' [Expected: 200 or 250] Path sent: '.$path.' Mode sent: '.$mode); } return false; } return true; } /** * Method to delete a path [file/folder] on the FTP server * * @access public * @param string $path Path to delete * @return boolean True if successful */ function delete($path) { // If native FTP support is enabled lets use it... if (FTP_NATIVE) { if (@ftp_delete($this->_conn, $path) === false) { if (@ftp_rmdir($this->_conn, $path) === false) { JError::raiseWarning('35', 'JFTP::delete: Bad response' ); return false; } } return true; } // Send delete file command and if that doesn't work, try to remove a directory if (!$this->_putCmd('DELE '.$path, 250)) { if (!$this->_putCmd('RMD '.$path, 250)) { JError::raiseWarning('35', 'JFTP::delete: Bad response', 'Server response: '.$this->_response.' [Expected: 250] Path sent: '.$path ); return false; } } return true; } /** * Method to create a directory on the FTP server * * @access public * @param string $path Directory to create * @return boolean True if successful */ function mkdir($path) { // If native FTP support is enabled lets use it... if (FTP_NATIVE) { if (@ftp_mkdir($this->_conn, $path) === false) { JError::raiseWarning('35', 'JFTP::mkdir: Bad response' ); return false; } return true; } // Send change directory command and verify success if (!$this->_putCmd('MKD '.$path, 257)) { JError::raiseWarning('35', 'JFTP::mkdir: Bad response', 'Server response: '.$this->_response.' [Expected: 257] Path sent: '.$path ); return false; } return true; } /** * Method to restart data transfer at a given byte * * @access public * @param int $point Byte to restart transfer at * @return boolean True if successful */ function restart($point) { // If native FTP support is enabled lets use it... if (FTP_NATIVE) { if (@ftp_site($this->_conn, 'REST '.$point) === false) { JError::raiseWarning('35', 'JFTP::restart: Bad response' ); return false; } return true; } // Send restart command and verify success if (!$this->_putCmd('REST '.$point, 350)) { JError::raiseWarning('35', 'JFTP::restart: Bad response', 'Server response: '.$this->_response.' [Expected: 350] Restart point sent: '.$point ); return false; } return true; } /** * Method to create an empty file on the FTP server * * @access public * @param string $path Path local file to store on the FTP server * @return boolean True if successful */ function create($path) { // If native FTP support is enabled lets use it... if (FTP_NATIVE) { // turn passive mode on if (@ftp_pasv($this->_conn, true) === false) { JError::raiseWarning('36', 'JFTP::create: Unable to use passive mode' ); return false; } $buffer = fopen('buffer://tmp', 'r'); if (@ftp_fput($this->_conn, $path, $buffer, FTP_ASCII) === false) { JError::raiseWarning('35', 'JFTP::create: Bad response' ); fclose($buffer); return false; } fclose($buffer); return true; } // Start passive mode if (!$this->_passive()) { JError::raiseWarning('36', 'JFTP::create: Unable to use passive mode' ); return false; } if (!$this->_putCmd('STOR '.$path, array (150, 125))) { @ fclose($this->_dataconn); JError::raiseWarning('35', 'JFTP::create: Bad response', 'Server response: '.$this->_response.' [Expected: 150 or 125] Path sent: '.$path ); return false; } // To create a zero byte upload close the data port connection fclose($this->_dataconn); if (!$this->_verifyResponse(226)) { JError::raiseWarning('37', 'JFTP::create: Transfer Failed', 'Server response: '.$this->_response.' [Expected: 226] Path sent: '.$path ); return false; } return true; } /** * Method to read a file from the FTP server's contents into a buffer * * @access public * @param string $remote Path to remote file to read on the FTP server * @param string $buffer Buffer variable to read file contents into * @return boolean True if successful */ function read($remote, &$buffer) { // Determine file type $mode = $this->_findMode($remote); // If native FTP support is enabled lets use it... if (FTP_NATIVE) { // turn passive mode on if (@ftp_pasv($this->_conn, true) === false) { JError::raiseWarning('36', 'JFTP::read: Unable to use passive mode' ); return false; } $tmp = fopen('buffer://tmp', 'br+'); if (@ftp_fget($this->_conn, $tmp, $remote, $mode) === false) { fclose($tmp); JError::raiseWarning('35', 'JFTP::read: Bad response' ); return false; } // Read tmp buffer contents rewind($tmp); $buffer = ''; while (!feof($tmp)) { $buffer .= fread($tmp, 8192); } fclose($tmp); return true; } $this->_mode($mode); // Start passive mode if (!$this->_passive()) { JError::raiseWarning('36', 'JFTP::read: Unable to use passive mode' ); return false; } if (!$this->_putCmd('RETR '.$remote, array (150, 125))) { @ fclose($this->_dataconn); JError::raiseWarning('35', 'JFTP::read: Bad response', 'Server response: '.$this->_response.' [Expected: 150 or 125] Path sent: '.$remote ); return false; } // Read data from data port connection and add to the buffer $buffer = ''; while (!feof($this->_dataconn)) { $buffer .= fread($this->_dataconn, 4096); } // Close the data port connection fclose($this->_dataconn); // Let's try to cleanup some line endings if it is ascii if ($mode == FTP_ASCII) { $buffer = preg_replace("/".CRLF."/", $this->_lineEndings[$this->_OS], $buffer); } if (!$this->_verifyResponse(226)) { JError::raiseWarning('37', 'JFTP::read: Transfer Failed', 'Server response: '.$this->_response.' [Expected: 226] Path sent: '.$remote ); return false; } return true; } /** * Method to get a file from the FTP server and save it to a local file * * @access public * @param string $local Path to local file to save remote file as * @param string $remote Path to remote file to get on the FTP server * @return boolean True if successful */ function get($local, $remote) { // Determine file type $mode = $this->_findMode($remote); // If native FTP support is enabled lets use it... if (FTP_NATIVE) { // turn passive mode on if (@ftp_pasv($this->_conn, true) === false) { JError::raiseWarning('36', 'JFTP::get: Unable to use passive mode' ); return false; } if (@ftp_get($this->_conn, $local, $remote, $mode) === false) { JError::raiseWarning('35', 'JFTP::get: Bad response' ); return false; } return true; } $this->_mode($mode); // Check to see if the local file can be opened for writing $fp = fopen($local, "wb"); if (!$fp) { JError::raiseWarning('38', 'JFTP::get: Unable to open local file for writing', 'Local path: '.$local ); return false; } // Start passive mode if (!$this->_passive()) { JError::raiseWarning('36', 'JFTP::get: Unable to use passive mode' ); return false; } if (!$this->_putCmd('RETR '.$remote, array (150, 125))) { @ fclose($this->_dataconn); JError::raiseWarning('35', 'JFTP::get: Bad response', 'Server response: '.$this->_response.' [Expected: 150 or 125] Path sent: '.$remote ); return false; } // Read data from data port connection and add to the buffer while (!feof($this->_dataconn)) { $buffer = fread($this->_dataconn, 4096); $ret = fwrite($fp, $buffer, 4096); } // Close the data port connection and file pointer fclose($this->_dataconn); fclose($fp); if (!$this->_verifyResponse(226)) { JError::raiseWarning('37', 'JFTP::get: Transfer Failed', 'Server response: '.$this->_response.' [Expected: 226] Path sent: '.$remote ); return false; } return true; } /** * Method to store a file to the FTP server * * @access public * @param string $local Path to local file to store on the FTP server * @param string $remote FTP path to file to create * @return boolean True if successful */ function store($local, $remote = null) { // If remote file not given, use the filename of the local file in the current // working directory if ($remote == null) { $remote = basename($local); } // Determine file type $mode = $this->_findMode($remote); // If native FTP support is enabled lets use it... if (FTP_NATIVE) { // turn passive mode on if (@ftp_pasv($this->_conn, true) === false) { JError::raiseWarning('36', 'JFTP::store: Unable to use passive mode' ); return false; } if (@ftp_put($this->_conn, $remote, $local, $mode) === false) { JError::raiseWarning('35', 'JFTP::store: Bad response' ); return false; } return true; } $this->_mode($mode); // Check to see if the local file exists and open for reading if so if (@ file_exists($local)) { $fp = fopen($local, "rb"); if (!$fp) { JError::raiseWarning('38', 'JFTP::store: Unable to open local file for reading', 'Local path: '.$local ); return false; } } else { JError::raiseWarning('38', 'JFTP::store: Unable to find local path', 'Local path: '.$local ); return false; } // Start passive mode if (!$this->_passive()) { @ fclose($fp); JError::raiseWarning('36', 'JFTP::store: Unable to use passive mode' ); return false; } // Send store command to the FTP server if (!$this->_putCmd('STOR '.$remote, array (150, 125))) { @ fclose($fp); @ fclose($this->_dataconn); JError::raiseWarning('35', 'JFTP::store: Bad response', 'Server response: '.$this->_response.' [Expected: 150 or 125] Path sent: '.$remote ); return false; } // Do actual file transfer, read local file and write to data port connection while (!feof($fp)) { $line = fread($fp, 4096); do { if (($result = @ fwrite($this->_dataconn, $line)) === false) { JError::raiseWarning('37', 'JFTP::store: Unable to write to data port socket' ); return false; } $line = substr($line, $result); } while ($line != ""); } fclose($fp); fclose($this->_dataconn); if (!$this->_verifyResponse(226)) { JError::raiseWarning('37', 'JFTP::store: Transfer Failed', 'Server response: '.$this->_response.' [Expected: 226] Path sent: '.$remote ); return false; } return true; } /** * Method to write a string to the FTP server * * @access public * @param string $remote FTP path to file to write to * @param string $buffer Contents to write to the FTP server * @return boolean True if successful */ function write($remote, $buffer) { // Determine file type $mode = $this->_findMode($remote); // If native FTP support is enabled lets use it... if (FTP_NATIVE) { // turn passive mode on if (@ftp_pasv($this->_conn, true) === false) { JError::raiseWarning('36', 'JFTP::write: Unable to use passive mode' ); return false; } $tmp = fopen('buffer://tmp', 'br+'); fwrite($tmp, $buffer); rewind($tmp); if (@ftp_fput($this->_conn, $remote, $tmp, $mode) === false) { fclose($tmp); JError::raiseWarning('35', 'JFTP::write: Bad response' ); return false; } fclose($tmp); return true; } // First we need to set the transfer mode $this->_mode($mode); // Start passive mode if (!$this->_passive()) { JError::raiseWarning('36', 'JFTP::write: Unable to use passive mode' ); return false; } // Send store command to the FTP server if (!$this->_putCmd('STOR '.$remote, array (150, 125))) { JError::raiseWarning('35', 'JFTP::write: Bad response', 'Server response: '.$this->_response.' [Expected: 150 or 125] Path sent: '.$remote ); @ fclose($this->_dataconn); return false; } // Write buffer to the data connection port do { if (($result = @ fwrite($this->_dataconn, $buffer)) === false) { JError::raiseWarning('37', 'JFTP::write: Unable to write to data port socket' ); return false; } $buffer = substr($buffer, $result); } while ($buffer != ""); // Close the data connection port [Data transfer complete] fclose($this->_dataconn); // Verify that the server recieved the transfer if (!$this->_verifyResponse(226)) { JError::raiseWarning('37', 'JFTP::write: Transfer Failed', 'Server response: '.$this->_response.' [Expected: 226] Path sent: '.$remote ); return false; } return true; } /** * Method to list the filenames of the contents of a directory on the FTP server * * Note: Some servers also return folder names. However, to be sure to list folders on all * servers, you should use listDetails() instead, if you also need to deal with folders * * @access public * @param string $path Path local file to store on the FTP server * @return string Directory listing */ function listNames($path = null) { // Initialize variables $data = null; // If native FTP support is enabled lets use it... if (FTP_NATIVE) { // turn passive mode on if (@ftp_pasv($this->_conn, true) === false) { JError::raiseWarning('36', 'JFTP::listNames: Unable to use passive mode' ); return false; } if (($list = @ftp_nlist($this->_conn,$path)) === false) { // Workaround for empty directories on some servers if ($this->listDetails($path, 'files') === array()) { return array(); } JError::raiseWarning('35', 'JFTP::listNames: Bad response' ); return false; } $list = preg_replace('#^'.preg_quote($path, '#').'[/\\\\]?#', '', $list); if ($keys = array_merge(array_keys($list, '.'), array_keys($list, '..'))) { foreach ($keys as $key) { unset($list[$key]); } } return $list; } /* * If a path exists, prepend a space */ if ($path != null) { $path = ' ' . $path; } // Start passive mode if (!$this->_passive()) { JError::raiseWarning('36', 'JFTP::listNames: Unable to use passive mode' ); return false; } if (!$this->_putCmd('NLST'.$path, array (150, 125))) { @ fclose($this->_dataconn); // Workaround for empty directories on some servers if ($this->listDetails($path, 'files') === array()) { return array(); } JError::raiseWarning('35', 'JFTP::listNames: Bad response', 'Server response: '.$this->_response.' [Expected: 150 or 125] Path sent: '.$path ); return false; } // Read in the file listing. while (!feof($this->_dataconn)) { $data .= fread($this->_dataconn, 4096); } fclose($this->_dataconn); // Everything go okay? if (!$this->_verifyResponse(226)) { JError::raiseWarning('37', 'JFTP::listNames: Transfer Failed', 'Server response: '.$this->_response.' [Expected: 226] Path sent: '.$path ); return false; } $data = preg_split("/[".CRLF."]+/", $data, -1, PREG_SPLIT_NO_EMPTY); $data = preg_replace('#^'.preg_quote(substr($path, 1), '#').'[/\\\\]?#', '', $data); if ($keys = array_merge(array_keys($data, '.'), array_keys($data, '..'))) { foreach ($keys as $key) { unset($data[$key]); } } return $data; } /** * Method to list the contents of a directory on the FTP server * * @access public * @param string $path Path local file to store on the FTP server * @param string $type Return type [raw|all|folders|files] * @param boolean $search Recursively search subdirectories * @return mixed : if $type is raw: string Directory listing, otherwise array of string with file-names */ function listDetails($path = null, $type = 'all') { // Initialize variables $dir_list = array(); $data = null; $regs = null; // TODO: Deal with recurse -- nightmare // For now we will just set it to false $recurse = false; // If native FTP support is enabled lets use it... if (FTP_NATIVE) { // turn passive mode on if (@ftp_pasv($this->_conn, true) === false) { JError::raiseWarning('36', 'JFTP::listDetails: Unable to use passive mode' ); return false; } if (($contents = @ftp_rawlist($this->_conn, $path)) === false) { JError::raiseWarning('35', 'JFTP::listDetails: Bad response' ); return false; } } else { // Non Native mode // Start passive mode if (!$this->_passive()) { JError::raiseWarning('36', 'JFTP::listDetails: Unable to use passive mode' ); return false; } // If a path exists, prepend a space if ($path != null) { $path = ' ' . $path; } // Request the file listing if (!$this->_putCmd(($recurse == true) ? 'LIST -R' : 'LIST'.$path, array (150, 125))) { JError::raiseWarning('35', 'JFTP::listDetails: Bad response', 'Server response: '.$this->_response.' [Expected: 150 or 125] Path sent: '.$path ); @ fclose($this->_dataconn); return false; } // Read in the file listing. while (!feof($this->_dataconn)) { $data .= fread($this->_dataconn, 4096); } fclose($this->_dataconn); // Everything go okay? if (!$this->_verifyResponse(226)) { JError::raiseWarning('37', 'JFTP::listDetails: Transfer Failed', 'Server response: '.$this->_response.' [Expected: 226] Path sent: '.$path ); return false; } $contents = explode(CRLF, $data); } // If only raw output is requested we are done if ($type == 'raw') { return $data; } // If we received the listing of an emtpy directory, we are done as well if (empty($contents[0])) { return $dir_list; } // If the server returned the number of results in the first response, let's dump it if (strtolower(substr($contents[0], 0, 6)) == 'total ') { array_shift($contents); if (!isset($contents[0]) || empty($contents[0])) { return $dir_list; } } // Regular expressions for the directory listing parsing $regexps['UNIX'] = '([-dl][rwxstST-]+).* ([0-9]*) ([a-zA-Z0-9]+).* ([a-zA-Z0-9]+).* ([0-9]*) ([a-zA-Z]+[0-9: ]*[0-9])[ ]+(([0-9]{1,2}:[0-9]{2})|[0-9]{4}) (.+)'; $regexps['MAC'] = '([-dl][rwxstST-]+).* ?([0-9 ]* )?([a-zA-Z0-9]+).* ([a-zA-Z0-9]+).* ([0-9]*) ([a-zA-Z]+[0-9: ]*[0-9])[ ]+(([0-9]{2}:[0-9]{2})|[0-9]{4}) (.+)'; $regexps['WIN'] = '([0-9]{2})-([0-9]{2})-([0-9]{2}) +([0-9]{2}):([0-9]{2})(AM|PM) +([0-9]+|