584799d026024e108d87aeceb51804d3

Any thoughts on this?
Missing some functionallities?

Could some parts written shorter?

Thanxs in advance :D

BTW: Before questions, this class is written because of I'm currently using a server without FTP-support for PHP :(

<?php
class FTPSocket {
	var $connection;
	var $port = 21;

	function connect($host, $user=false, $pass=false){
		if($this->connection) @fclose($this->connection);
		if(($this->connection = @fsockopen($host, (is_int($this->port)? $this->port : 21), $error, $errorstr, 5)) && function_exists('set_socket_blocking')){
			@set_socket_blocking($this->connection, 0);
			if((intval($this->reply()) == 220) && is_string($user) && ($replycode = intval($this->command('USER '.$user)))){
				if($replycode == 331) $replycode = intval($this->command('PASS '.(is_string($pass)? $pass : 'anonymous')));
				elseif(is_string($pass)) $replycode = intval($this->command('ACCT '.$pass));
				$this->features(true);
				return(($replycode == 230) || ($replycode == 202));
			}
		}
		return false;
	}
	
	function reply($retry=true){
		if($this->connection){
			$reply = '';
			while(true){
				while(is_string($replypart = @fgets($this->connection, 512)) && (strlen($replypart) > 0)){
					$reply .= $replypart;
					if(is_string($replypart) && is_numeric(substr($replypart, 0, 3)) && (ord(substr($replypart, 3, 1)) == 32)) return $reply;
				}
				if(!$retry) break;
			}
		}
		return false;
	}
	
	function umask($umask){
		return(is_numeric($umask) && (intval($this->command('UMASK 0'.decoct(intval($umask))))));
	}
	
	function command($commandstring){
		$this->reply(false);
		if(is_string($commandstring) && $this->connection && fwrite($this->connection, $commandstring."\r\n")) return $this->reply();		
		return false;
	}
	
	function cdup(){
		return(intval($this->command('CDUP')) == 200);
	}
	
	function cwdir($path){
		return(is_string($path) && (intval($this->command('CWD '.$path)) == 250));
	}

	function rmdir($path){
		return(is_string($path) && (intval($this->command('RMD '.$path)) == 250));
	}
	
	function mkdir($path, $umask=false){
		return(is_string($path) && (!is_numeric($umask) || $this->umask($umask)) && (intval($this->command('MKD '.$path)) == 257));
	}
	
	function delete($path){
		return(is_string($path) && (intval($this->command('DELE '.$path)) == 250));
	}
	
	function chmod($path, $chmod){
		return(is_numeric($chmod) && (intval($this->command('SITE CHMOD 0'.decoct(intval($chmod)).' '.$path)) == 200));
	}
	
	function rename($path, $newpath){
		return(is_string($path) && is_string($newpath) && (intval($this->command('RNFR '.$path)) == 350) && (intval($this->command('RNTO '.$newpath)) == 250));
	}
	
	function file_exists($path){
		return(intval($this->command('RNFR '.$path)) == 350);
	}
	
	function pwdir(){
		if((intval($reply = $this->command('PWD')) == 257) && is_int($spos = strpos($reply, '"')) && is_int($epos = strpos($reply, '"', ($spos + 1)))) return str_replace('""', '"', substr($reply, ($spos + 1), ($epos - $spos - 1)));
	}
	
	function mtime($path){
		if(is_string($path) && (intval($reply = $this->command('MDTM '.$path)) == 213) && is_numeric($time = substr($reply, 4, 14)) && is_int($time = mktime(substr($time, 8, 2), substr($time, 10, 2), substr($time, 12, 2), substr($time, 4, 2), substr($time, 6, 2), substr($time, 0, 4)))) return $time;
		return false;
	}

	function features($reget=false){
		static $feats = Array();
		if(!$reget) return $feats;
		if(intval($reply = $this->command('FEAT')) == 211){
			$feats = Array(); $feat = preg_split("#\s*([\r\n]+)\s*#", trim($reply)); $i = 0;
			while(($i += 1) < (count($feat) - 1)) $feats[(is_int($pos = strpos($feat[$i], chr(32)))? substr($feat[$i], 0, $pos) : $feat[$i])] = (is_int($pos)? substr($feat[$i], ($pos + 1)) : '');
			return $feats;
		}
		return false;
	}

	function abort(){
		if(isset($this->dataconnection) && in_array(($reply = intval($this->command('ABOR'))), Array(225, 226))){
			if(($reply == 226) && @fclose($this->dataconnection)) unset($this->dataconnection);
			return false;
		}
	}
	
	function systype(){
		if(intval($reply = $this->command('SYST')) == 215) return(trim(substr($reply, 4)));
		return false;
	}
	
	function storeunique($fileordata, $path=false){
		if(is_string($path) && !$this->cwdir($path)) return false;
		if(is_string($fileordata)){
			$replycode = 425;
			if(isset($this->dataconnection) && $this->type('I') && (intval($this->command('ALLO '.(is_file($fileordata)? filesize($fileordata) : strlen($fileordata))))) && in_array(($replycode = intval($this->command('STOU'))), Array(125, 150))){
				if(!is_file($fileordata)) fwrite($this->dataconnection, $fileordata);
				elseif($fp = @fopen($fileordata, 'rb')) while(is_string($filepart = @fgets($fp))) fwrite($this->dataconnection, $filepart);
				elseif($this->abort()) return false;
				if(@fclose($this->dataconnection)) unset($this->dataconnection);
				return(intval($this->reply()) == 226);
			}
			elseif(in_array($replycode, Array(425, 426)) && $this->passive()) return $this->storeunique($fileordata, $path);
			$this->abort();
		}
		return false;
	}
	
	function retrieve($path, $file=false, $restore=false){
		$replycode = 425;
		if(!is_numeric($restore) || ($this->file_exists($path) && (!is_numeric($restore) || (intval($this->command('REST '.intval($restore))) == 350)))){
			if(isset($this->dataconnection) && $this->type('I') && is_string($path) && in_array(($replycode = intval($this->command('RETR '.$path))), Array(150, 125))){
				if(is_string($file)) $fp = fopen($file, 'wb');
				$reply = '';
				while(true){
					if(is_string($replypart = fgets($this->dataconnection, 256))){
						if(isset($fp) && ($reply = true)) fwrite($fp, $replypart);
						else $reply .= $replypart;
					}
					if(!is_string($replypart)){
						@fclose($this->dataconnection);
						unset($this->dataconnection);
						if(intval($this->reply()) == 226){
							if(is_string($reply)) return $reply;
							else return((!isset($fp) || @fclose($fp)) && !!$reply);
						}
					}
				}
			}
			elseif(in_array($replycode, Array(425, 426)) && $this->passive()) return $this->retrieve($path, $file);
			$this->abort();
		}
		return false;
	}
	
	function store($remotefile, $fileordata, $restore=false){
		$replycode = 425;
		if(is_string($remotefile) && is_string($fileordata)){
			if(isset($this->dataconnection) && $this->type('I') && (!is_numeric($restore) || (intval($this->command('REST '.($restore = intval($restore)))) == 350)) && in_array(intval($this->command('ALLO '.(is_file($fileordata)? (filesize($fileordata) - (is_int($restore)? $restore : 0)) : strlen($fileordata)))), Array(200, 202)) && in_array(($replycode = intval($this->command('STOR '.$remotefile))), Array(150, 125))){
				if(!is_file($fileordata)) fwrite($this->dataconnection, $fileordata);
				elseif(is_file($fileordata) && ($fp = fopen($fileordata, 'rb')) && (!is_int($restore) || is_int(@fseek($fp, $restore)))) while(is_string($filepart = @fgets($fp))) fwrite($this->dataconnection, $filepart);
				elseif($this->abort()) return false;
				if(@fclose($this->dataconnection)) unset($this->dataconnection);
				return(intval($this->reply()) == 226);
			}
			elseif(in_array($replycode, Array(425, 426)) && $this->passive()) return $this->store($remotefile, $fileordata, $restore);
			$this->abort();
		}
		return false;
	}
	
	function append($file, $fileordata){
		$replycode = 425;
		if(is_string($file) && is_string($fileordata)){
			$replycode = 425;
			if(isset($this->dataconnection) && $this->type('I') && (intval($this->command('ALLO '.(is_file($fileordata)? filesize($fileordata) : strlen($fileordata))))) && in_array(($replycode = intval($this->command('APPE '.$file))), Array(125, 150))){
				if(!is_file($fileordata)) fwrite($this->dataconnection, $fileordata);
				elseif($fp = @fopen($fileordata, 'rb')) while(is_string($filepart = @fgets($fp))) fwrite($this->dataconnection, $filepart);
				elseif($this->abort()) return false;
				if(@fclose($this->dataconnection)) unset($this->dataconnection);
				return(intval($this->reply()) == 226);
			}
			elseif(in_array($replycode, Array(425, 426)) && $this->passive()) return $this->append($file, $fileordata);
			$this->abort();
		}
		return false;
	}
	
	function passive(){
		if(isset($this->dataconnection)) $this->abort();
		if((intval($reply = $this->command('PASV')) == 227) && is_int($spos = strpos($reply, '(')) && is_int($epos = strpos($reply, ')', $spos))){
			$ipparts = explode(',', substr($reply, ($spos + 1), ($epos - $spos - 1)));
			if(count($ipparts) == 6){
				$host = ''; $count = -1;
				while(($count += 1) < 4){
					if(is_numeric($ipparts[$count])) $host .= (($host == '')? '' : '.').intval($ipparts[$count]);
					else return false;
				}
				$port = ((intval($ipparts[4]) << 8) | intval($ipparts[5]));
				if($this->dataconnection = @fsockopen($host, $port, $errno, $errstr, 30)) return true;
			}
		}
		return false;
	}
	
	function type($type=false){
		return(is_string($type) && (intval($this->command('TYPE '.$type)) == 200));
	}
	
	function fileList($path=false, $raw=false){
		$replycode = 425;
		if(!is_string($path)) $raw = $path;
		if(isset($this->dataconnection) && $this->type('A') && (($mlsd = in_array(intval($this->command('MLSD '.(is_string($path)? ' '.$path : ''))), Array(150, 125))) || in_array(intval($this->command('LIST -a'.(is_string($path)? ' '.$path : ''))), Array(150, 125)))){
			$reply = '';
			while(true){
				if(is_string($replypart = fgets($this->dataconnection, 128))) $reply .= $replypart;
				if(!is_string($replypart)){
					@fclose($this->dataconnection);
					unset($this->dataconnection);
					if(intval($this->reply()) == 226){
						if($raw) return($reply);
						$files = Array();
						$records = split("[\r\n]+", trim($reply));
						if($mlsd){
							# TODO: implement MLSD
						}
						else{
							$systype = $this->systype();
							if(preg_match('/(LI|U)NIX/i', $systype)){
								while(is_string($record = current($records))){
									next($records);
									$fields = preg_split("/\s+/", $record);
									if(count($fields) > 8){
										$files[($index = count($files))] = Array('type' => ((($type = substr($fields[0], 0, 1)) == '-')? 'F' : strtoupper($type)), 'inode' => intval($fields[1]), 'perms' => 0, 'owner' => $fields[2], 'group' => $fields[3], 'size' => intval($fields[4]), 'name' => $fields[8]);
										$perms = substr($fields[0], 1);
										if(isset($fields[10])) $files[$index]['link'] = $fields[10];
										$count = -1;
										while(strlen($perms) > ($count += 1)) $files[$index]['perms'] = ((($files[$index]['perms'] << 1) | ((int) (substr($perms, $count, 1) != '-'))));
									}
								}
							}
							else if(preg_match('/WIN/i', $systype)){
								while(is_string($record = current($records))){
									next($records);
									if(strlen($record) > 40){
										$date = trim(substr($record, 0, 9));
										$time = trim(substr($record, 10, 7));
										$mtime = mktime((intval(substr($time, 0, 2)) + ((strtoupper(substr($time, 5, 2)) == 'PM')? 12 : 0)), intval(substr($time, 3, 2)), 0, intval(is_int($slashpos = strpos($date, '/'))? substr($date, 3, 2) : substr($date, 0, 2)), intval(is_int($slashpos)? substr($date, 0, 2) : substr($date, 3, 2)), ((($year = (2000 + intval(substr($date, 6, 2)))) > intval(date('Y')))? ($year - 100) : $year));
										$size = trim(substr($record, 18, 20));
										$files[($index = count($files))] = Array('type' => (!is_numeric($size)? 'D' : 'F'), 'size' => (is_numeric($size)? intval($size) : 0), 'name' => substr($record, 39), 'modify' => $mtime);
									}
								}
							}
						}
						return $files;
					}
					break;
				}
			}
		}
		elseif(in_array($replycode, Array(425, 426)) && $this->passive()) return $this->fileList($path, $raw);
		$this->abort();
		return false;
	}
	
	function namelist($path=false){
		$replycode = 425;
		if(isset($this->dataconnection) && $this->type('A') && in_array(($replycode = intval($this->command('NLST'.(is_string($path)? ' '.$path : '')))), Array(150, 125))){
			$reply = '';
			while(true){
				if(is_string($replypart = fgets($this->dataconnection, 128))) $reply .= $replypart;
				if(!is_string($replypart)){
					@fclose($this->dataconnection);
					unset($this->dataconnection);
					if(intval($this->reply()) == 226) return(split("[\r\n\s]+", trim($reply)));
				}
			}
		}
		else if(in_array($replycode, Array(425, 426)) && $this->passive()) return $this->namelist($path);
		$this->abort();
		return false;
	}
	
	function quit(){
		if(isset($this->dataconnection) && @fclose($this->dataconnection)) $this->reply(false);
		return($this->command('REIN') && (intval($this->command('QUIT')) == 221) && @fclose($this->connection));
	}
}
?>

Refactorings

No refactoring yet !

441c4f02db55ef2cbe96027af7012e01

techietim

October 20, 2007, October 20, 2007 14:10, permalink

No rating. Login to rate!

That's pretty good. You should post that up on:
http://php.net/ftp

584799d026024e108d87aeceb51804d3

JWvdV

October 20, 2007, October 20, 2007 14:19, permalink

No rating. Login to rate!

@techietim:
PHP.NET doesn't like such a long note, so this class can't be posted on PHP.NET.

Your refactoring





Format Copy from initial code

or Cancel