hd_keeper ([info]hd_keeper) wrote,
@ 2009-07-06 10:30:00
Previous Entry  Add to memories!  Tell a Friend  Next Entry
SolidFTP extends Net_FTP
Provides more reliable file download than Net_FTP from PEAR


<?php
require_once 'Net/FTP.php';

// Invalid value for retry count
define( 'NET_FTP_ERR_RETRYCOUNTLESSZERO', -51);

// Remote file does not exist
define('NET_FTP_ERR_NOREMOTEFILE', -52);

// Number of retries exceeded, giving up
define('NET_FTP_ERR_RETRYCOUNTEXCEEDED', -53);

/**
 * Provides more reliable file download than Net_FTP from PEAR
 *
 * @see http://pear.php.net/package/Net_FTP
 * @author Keeper <hd_keeper@mail.ru>
 */
class SolidFTP extends Net_FTP
{
	/**
	 * Maximum number of retries for file download
	 * @var integer
	 */
	var $_retry_count = 20;
	
	/**
	 * Last working directory on the remote server
	 * @var string
	 */
	var $_last_dir = null;
	
	/**
	 * More reliable file download from the FTP-server
	 * @see Net_FTP::get()
	 *
	 * @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 - Whether to overwrite existing file (optional)
	 * @param int    $mode - Either FTP_ASCII or FTP_BINARY (optional)
	 * @return mixed - true on success, otherwise PEAR::Error
	 */
	function get( $remote_file, $local_file, $overwrite = false, $mode = null)
	{
		if (!isset($mode)) {
			$mode = $this->checkFileExtension( $remote_file);
		}

		$remote_file = $this->_constructPath($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);
		}

		// Remember a working directory
		$this->_last_dir = $this->pwd();
		if ($this->isError( $this->_last_dir)) {
			$this->_last_dir = null;
		}
		
		$resume_pos = 0;
		$get_result = $reconn_result = false;
		for ($current_try = 0; $current_try <= $this->_retry_count; $current_try++)
		{
			if ($current_try > 0) {
				// Try to reconnect
				$reconn_result = $this->reconnect();
				if ($this->isError( $reconn_result, NET_FTP_ERR_DIRCHANGE_FAILED)) {
					// Working directory does not exist anymore
					return $reconn_result;
				} elseif ($this->isError( $reconn_result)) {
					// Other connection error may be temporary
					continue;
				}
				clearstatcache();
				$resume_pos = filesize( $local_file);
			}

			// Check if remote file still exists
			if (@ftp_size( $this->_handle, $remote_file) == -1) {
				return $this->raiseError( "Remote file '$remote_file' does not exist.",
					NET_FTP_ERR_NOREMOTEFILE);
			}
	        
			// Transfer a chunk of file
			// ftp_get() deletes local file on failure and thus cannot be used
			$get_result = @ftp_nb_get( $this->_handle, $local_file, $remote_file, $mode, $resume_pos);
			while ($get_result == FTP_MOREDATA) {
				$this->_announce('nb_get');
				$get_result = @ftp_nb_continue( $this->_handle);
			}
			
			// Transfer successful
			if ($get_result) break;
		}
        
		if (!$get_result || $this->isError( $reconn_result)) {
			return $this->raiseError( "Retry count exceeded while downloading '$remote_file' - giving up.",
				NET_FTP_ERR_RETRYCOUNTEXCEEDED);
		} else {
			return true;
		}
	}
	
	/**
	 * Reconnect to the remote FTP-server, using last hostname,
	 * username, password and working directory
	 * @return mixed - true on success, otherwise PEAR::Error
	 */
	function reconnect() {
		$this->_announce('reconnect');
		$res = $this->connect();
		if ($this->isError( $res)) return $res;
		$res = $this->login();
		if ($this->isError( $res)) return $res;
		if (!is_null( $this->_last_dir)) {
			$res = $this->cd( $this->_last_dir);
			if ($this->isError( $res)) return $res;
		}
		return true;
	}
	
	/**
	 * Set maximum number of retries
	 * @param integer $retry_count
	 * @return mixed - true on success, otherwise PEAR::Error
	 */
	function setRetryCount( $retry_count) {
		if (!is_int( $retry_count) || ($retry_count < 0)) {
			return $this->raiseError( 'Retry count '.$timeout.' is invalid, has to be an integer >= 0',
				NET_FTP_ERR_RETRYCOUNTLESSZERO);
		}
		$this->_retry_count = $retry_count;
		return true;
	}
	
	/**
	 * Return maximum number of retries
	 * @return integer
	 */
	function getRetryCount() {
		return $this->_retry_count;
	}
	
} // class SolidFTP
?>




Create an Account
Forgot your login or password?
Login w/ OpenID
English • Español • Deutsch • Русский…