ftphost = $host; $this->ftpport = $port; $this->ftpuser = $user; $this->ftppass = $pass; if(substr($dir,0,1) != '/') $dir = '/'.$dir; $this->ftpdir = is_null($dir) ? '' : $dir; } /** * Singleton implementation * @param $host string The FTP hostname. If it's non empty, it forcibly creates a new instance * @param $port int The FTP port number * @param $user string The FTP user name * @param $pass string The FTP password * @param $dir string The FTP initial directory * @return FTPConnector */ static function &getInstance($host = '', $port = '', $user = '', $pass = '', $dir = '') { static $instance; // Forcibly create new instance if host parameter exists if(!empty($host)) { if(is_object($instance)) $instance->disconnect(); $instance = null; } // Create a new isntance if it doesn't exist if( !is_object($instance) || (!empty($host)) ) { $instance = new ABIFtp($host, $port, $user, $pass, $dir); } return $instance; } /** * Returns the last error message * @return string The error message */ function getError() { return $this->error; } /** * Tries to connect to the FTP server * @return bool True on success */ function connect($ignoredir = false) { if($this->ftpdir == '') $ignoredir = true; // If no initial directory was passed, skip changing to it (quite obvious why is that) // Connect to server $this->_handle = @ftp_connect($this->ftphost, $his->ftpport); if($this->_handle === false) { $this->error='Wrong FTP host'; return false; } // Login if(! @ftp_login($this->_handle, $this->ftpuser, $this->ftppass)) { $this->error='Wrong FTP username and/or password'; @ftp_close($this->_handle); return false; } if(!$ignoredir) { // Change to initial directory if(! @ftp_chdir($this->_handle, $this->ftpdir)) { $this->error='Wrong FTP initial directory'; @ftp_close($this->_handle); return false; } } // Use passive mode @ftp_pasv($this->_handle, true); return true; } /** * Disconnects from the FTP server */ function disconnect() { @ftp_close($this->_handle); } /** * Returns true if the given FTP directory exists * @param $dir string The directory to check for * @return bool True if the directory exists */ function is_dir( $dir ) { return @ftp_chdir( $this->_handle, $dir ); } /** * Recursively creates an FTP directory if it doesn't exist * @param $dir The directory to create * @return bool True on success, false if creation failed */ function makeDirectory( $dir ) { $check = '/'.trim($this->ftpdir,'/').'/'.$dir; if($this->is_dir($check)) return true; $alldirs = explode('/', $dir); $previousDir = '/'.trim($this->ftpdir); foreach($alldirs as $curdir) { $check = $previousDir.'/'.$curdir; if(!$this->is_dir($check)) { if(@ftp_mkdir($this->_handle, $check) === false) { $this->error = 'Could not create directory '.$dir; return false; } @ftp_chmod($this->_handle, 0755, $check); } $previousDir = $check; } return true; } function changeToInitialDirectory() { return @ftp_chdir($this->_handle, $this->ftpdir); } function getPwd() { return @ftp_pwd($this->_handle); } function listDetails($path = null, $type = 'all') { // Adapted from Joomla!'s FTP class // 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 (($contents = @ftp_rawlist($this->_handle, $path)) === false) { return false; } // 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]+|) +(.+)'; // Find out the format of the directory listing by matching one of the regexps $osType = null; foreach ($regexps as $k=>$v) { if (ereg($v, $contents[0])) { $osType = $k; $regexp = $v; break; } } if (!$osType) { return false; } /* * Here is where it is going to get dirty.... */ if ($osType == 'UNIX') { foreach ($contents as $file) { $tmp_array = null; if (ereg($regexp, $file, $regs)) { $fType = (int) strpos("-dl", $regs[1] { 0 }); //$tmp_array['line'] = $regs[0]; $tmp_array['type'] = $fType; $tmp_array['rights'] = $regs[1]; //$tmp_array['number'] = $regs[2]; $tmp_array['user'] = $regs[3]; $tmp_array['group'] = $regs[4]; $tmp_array['size'] = $regs[5]; $tmp_array['date'] = date("m-d", strtotime($regs[6])); $tmp_array['time'] = $regs[7]; $tmp_array['name'] = $regs[9]; } // If we just want files, do not add a folder if ($type == 'files' && $tmp_array['type'] == 1) { continue; } // If we just want folders, do not add a file if ($type == 'folders' && $tmp_array['type'] == 0) { continue; } if (is_array($tmp_array) && $tmp_array['name'] != '.' && $tmp_array['name'] != '..') { $dir_list[] = $tmp_array; } } } elseif ($osType == 'MAC') { foreach ($contents as $file) { $tmp_array = null; if (ereg($regexp, $file, $regs)) { $fType = (int) strpos("-dl", $regs[1] { 0 }); //$tmp_array['line'] = $regs[0]; $tmp_array['type'] = $fType; $tmp_array['rights'] = $regs[1]; //$tmp_array['number'] = $regs[2]; $tmp_array['user'] = $regs[3]; $tmp_array['group'] = $regs[4]; $tmp_array['size'] = $regs[5]; $tmp_array['date'] = date("m-d", strtotime($regs[6])); $tmp_array['time'] = $regs[7]; $tmp_array['name'] = $regs[9]; } // If we just want files, do not add a folder if ($type == 'files' && $tmp_array['type'] == 1) { continue; } // If we just want folders, do not add a file if ($type == 'folders' && $tmp_array['type'] == 0) { continue; } if (is_array($tmp_array) && $tmp_array['name'] != '.' && $tmp_array['name'] != '..') { $dir_list[] = $tmp_array; } } } else { foreach ($contents as $file) { $tmp_array = null; if (ereg($regexp, $file, $regs)) { $fType = (int) ($regs[7] == ''); $timestamp = strtotime("$regs[3]-$regs[1]-$regs[2] $regs[4]:$regs[5]$regs[6]"); //$tmp_array['line'] = $regs[0]; $tmp_array['type'] = $fType; $tmp_array['rights'] = ''; //$tmp_array['number'] = 0; $tmp_array['user'] = ''; $tmp_array['group'] = ''; $tmp_array['size'] = (int) $regs[7]; $tmp_array['date'] = date('m-d', $timestamp); $tmp_array['time'] = date('H:i', $timestamp); $tmp_array['name'] = $regs[8]; } // If we just want files, do not add a folder if ($type == 'files' && $tmp_array['type'] == 1) { continue; } // If we just want folders, do not add a file if ($type == 'folders' && $tmp_array['type'] == 0) { continue; } if (is_array($tmp_array) && $tmp_array['name'] != '.' && $tmp_array['name'] != '..') { $dir_list[] = $tmp_array; } } } return $dir_list; } function read($remote, &$buffer) { $tmpFile = tmpfile(); if(@$tmpFile === false) { return false; } if(@ftp_fget($this->_handle, $tmpFile, $remote, FTP_BINARY) === false) { fclose($tmpFile); return false; } // Read tmp buffer contents rewind($tmpFile); $buffer = ''; while (!feof($tmpFile)) { $buffer .= fread($tmpFile, 8192); } fclose($tmpFile); return true; } function write($remote, &$buffer) { $tmpFile = tmpfile(); if(@$tmpFile === false) { return false; } @fwrite($tmpFile, $buffer); @fflush($tmpFile); @fseek($tmpFile, 0); $result = @ftp_fput($this->_handle, $remote, $tmpFile, FTP_BINARY); @fclose($tmpFile); return $result; } /** * Automatically find the Joomla! root directory. You must have already logged * in, ignoring the initial directory setting. * @return string|bool The root path, or false if we couldn't find it. */ function findRoot() { $ftpPaths = array(); // Get the FTP CWD, in case it is not the FTP root $cwd = $this->getPwd(); if ($cwd === false) { return false; } $cwd = rtrim($cwd, '/'); // Get list of folders in the CWD $ftpFolders = $this->listDetails(null, 'folders'); if ($ftpFolders === false || count($ftpFolders) == 0) { return false; } for ($i=0, $n=count($ftpFolders); $i<$n; $i++) { $ftpFolders[$i] = $ftpFolders[$i]['name']; } // Check if Joomla! is installed at the FTP CWD $dirList = array('administrator', 'components', 'installation', 'language', 'libraries', 'plugins'); if (count(array_diff($dirList, $ftpFolders)) == 0) { $ftpPaths[] = $cwd.'/'; } // Process the list: cycle through all parts of JPATH_SITE, beginning from the end $parts = explode(DS, JPATH_SITE); $tmpPath = ''; for ($i=count($parts)-1; $i>=0; $i--) { $tmpPath = '/'.$parts[$i].$tmpPath; if (in_array($parts[$i], $ftpFolders)) { $ftpPaths[] = $cwd.$tmpPath; } } // Check all possible paths for the real Joomla! installation $checkValue = @file_get_contents(JPATH_SITE.DS.'includes'.DS.'joomla'.DS.'version.php'); foreach ($ftpPaths as $tmpPath) { $filePath = rtrim($tmpPath, '/').'/libraries/joomla/version.php'; $buffer = null; @$this->read($filePath, $buffer); if ($buffer == $checkValue) { $ftpPath = $tmpPath; break; } } // Return the FTP root path if (isset($ftpPath)) { return $ftpPath; } else { return false; } } function recursiveDelete($directory) { # here we attempt to delete the file/directory @ftp_chdir($this->_handle, $this->ftpdir.'/'.$directory); if( !(@ftp_rmdir($this->_handle, $directory) || @ftp_delete($this->_handle, $directory)) ) { # if the attempt to delete fails, get the file listing $filelist = @ftp_rawlist($this->_handle, $this->ftpdir.'/'.$directory); # loop through the file list and recursively delete the FILE in the list foreach($filelist as $current) { if(empty($current)) continue; $split = preg_split('[ ]', $current, 9, PREG_SPLIT_NO_EMPTY); $file = $this->ftpdir.'/'.$directory.'/'.$split[8]; $isdir = ($split[0]{0} === 'd') ? true : false; if($isdir) { $this->recursiveDelete($file); } else { @ftp_chdir($this->_handle, $this->ftpdir.'/'.$directory); @ftp_delete($this->_handle, $file); } } #if the file list is empty, delete the DIRECTORY we passed @ftp_chdir($this->_handle, $this->ftpdir.'/'.$directory); if(!(@ftp_rmdir($this->_handle, $directory))) @ftp_delete($this->_handle, $directory); } } } ?>