Thought some of you might find this helpful. Pretty self explanatory for the most part. Also included my own logging classes. It's all kind of messy/undocumented because it's a work in progress, but it is totally functional. I would post in the treasure chest thread but nobody actually checks that.
Code:
<?php
$cfg['hostname'] = 'yourdomain.com';
$cfg['username'] = 'chatmasta';
$cfg['username'] = 'pass';
echo '<pre>';
try {
$ftp = new Ftp($cfg['hostname'], $cfg['username'], $cfg['password']);
$ftp->cd('public_html');
$ftp->cd('fortesting');
/*
.... do FTP stuff here. If any of it throws an exception, it goes to the catch block */
*/
} catch (Exception $e) {
echo $e->getMessage();
}
echo "\n";
print_r($ftp->log->getAllItems());
echo '<hr>Done.';
class Log {
private $stack = array();
public function __construct(Log $base_log = null) {
if(!is_null($base_log))
$this->stack = $base_log->getAllItems();
}
public function message($item) {
$this->add($item, 'message');
}
public function error($item, $throw_exception = false) {
$this->add($item, 'error');
if($throw_exception)
throw new Exception($this->getLastItem()->message);
}
private function add($item, $type = null) {
if(!is_a($item, 'LogItem') && $type == null)
throw new Exception('$item passed to Log::add() must be LogItem or $type must be defined');
if(!is_a($item, 'LogItem')) $item = new LogItem($item, $type);
$this->stack[] = $item;
}
public function getLastItem() {
return end($this->stack);
}
public function getAllItems() {
return $this->stack;
}
}
class LogItem {
public $message, $type;
public function __construct($message, $type = 'error') {
$this->message = $message;
$this->type = $type;
}
public function isType($type) {
return ($this->type == $type);
}
}
class Util {
public static function parseConstant($constant) {
// If $constant is not defined, we assume $constant is a string value to be parsed
// otherwise, we parse the value of the constant with the name $constant
if(!defined($constant))
$constant_value = $constant;
else
$constant_value = constant($constant);
if(preg_match_all("/\{([A-za-z0-9]+)\}/i", $constant_value, $matches)) {
foreach($matches[1] as $needle) {
global ${$needle};
$constant_value = str_replace('{' . $needle . '}', ${$needle}, $constant_value);
}
}
return $constant_value;
}
}
class Ftp {
private $conn, $current_dir;
public $log;
public function __construct($host, $username, $password, $passive = false) {
$this->log = new Log;
$this->connect($host, $username, $password, $passive);
}
private function connect($host, $username, $password, $passive = false) {
$this->conn = ftp_connect($host);
$login = ftp_login($this->conn, $username, $password);
ftp_pasv($this->conn, $passive);
if(!$this->conn || !$login)
$this->log->error('There was a login problem.', true);
$this->log->message('Sucessfully connected.');
}
public function ls($dir = '.', $raw = false) {
$ls = ($raw) ? ftp_rawlist($this->conn, $dir) : ftp_nlist($this->conn, $dir);
if(!$ls)
$this->log->error("Could not list contents of $dir", true);
return $ls;
}
public function isDir($dir) {
$original_dir = ftp_pwd($this->conn);
$result = @ftp_chdir($this->conn, $dir);
if($result) {
ftp_chdir($this->conn, $original_dir);
return true;
}
return false;
}
public function isFile($file) {
return in_array($file, $this->ls());
}
public function chmod($path, $mode_dec) {
$mode_oct = octdec(str_pad($mode_dec, 4, '0' ,STR_PAD_LEFT));
$result = ftp_chmod($this->conn, $mode_oct, $path);
if(!$result)
$this->log->error("Error changing permissions for $path to $mode_dec", true);
$this->log->message("Permissions for $path are now $mode_dec");
}
public function cd($dir) {
$result = ftp_chdir($this->conn, $dir);
if(!$result)
$this->log->error("Could not change directory to $dir", true);
$this->log->message('Current directory is now' . ftp_pwd($this->conn));
}
public function mkdir($dir, $mode_dec = null) {
$current_dir = ftp_pwd($this->conn);
$result = ftp_mkdir($this->conn, $dir);
if(!$result)
$this->log->error("Could not make directory $dir in " . ftp_pwd($this->conn), true);
$this->log->message("Made directory $dir in " . ftp_pwd($this->conn));
if(!is_null($mode_dec))
$this->chmod($dir, $mode_dec);
}
public function rmdir($dir) {
if($dir == '.' || $dir == '..')
return false; // quietly return
$result = ftp_rmdir($this->conn, $dir);
if(!$result)
$this->log->error("Could not remove directory $dir - you should ensure that it is empty.", true);
$this->log->message("Removed directory $dir");
}
public function delete($path) {
$result = ftp_delete($this->conn, $path);
if(!$result)
$this->log->error("Could not delete file $path", true);
$this->log->message("Deleted file $path");
}
public function upload($from_path, $to_path, $mode = null) {
if($mode != 'ascii' || $mode != 'binary')
$mode = self::determineUploadMode($from_path);
$mode = ($mode == 'ascii' || $mode == FTP_ASCII) ? FTP_ASCII : FTP_BINARY;
$result = ftp_put($this->conn, $from_path, $to_path, $mode);
if(!$result)
$this->log->error("Error uploading $from_path to $to_path", true);
$this->log->message("Successfully uploaded $from_path to $to_path");
}
public function download($from_path, $to_path) {
$mode = self::determineUploadMode($to_path);
$result = ftp_get($this->conn, $to_path, $from_path, $mode, 0);
if(!$result)
$this->log->error('Error downloading $from_path to $to_path');
$this->log->message('Successfully downloaded $from_path to $to_path');
}
public static function determineUploadMode($path) {
$ascii_always = array('.htm', '.html', '.shtml', '.php', '.pl', '.cgi', '.js', '.py', '.cnf', '.css', '.forward', '.htaccess', '.map', '.pwd', '.txt', '.grp', '.ctl');
$extension = array_pop(explode('.', $from_path));
if(in_array($extension, $ascii_always))
return FTP_ASCII;
return FTP_BINARY;
}
public function __destruct() {
if($this->conn) ftp_close($this->conn);
}
}
?>
PHP:
<?php echo 'Why does this code highlighting suck so much dick?'; ?>