<?php

	/*
	*	Gekko - Open Source Web Development Framework
	*	------------------------------------------------------------------------
	*	Copyright (C) 2004-2005, J. Carlos Nieto <xiam@users.sourceforge.net>
	*	This program is Free Software.
	*
	*	@package	Gekko
	*	@license	http://www.gnu.org/copyleft/gpl.html GNU/GPL License 2.0
	*	@author		J. Carlos Nieto <xiam@users.sf.net>
	*	@version	CVS: $Id:$
	*	@link		http://www.gekkoware.org
	*/

	if (!defined("IN-GEKKO")) die("Get a life!");

	/*
		FTP Support class for Gekko
	*/

	//if (!defined("IN-GEKKO")) die("Get a life!");

	define("REMOTECONN_DEBUG", 0);

	Class remoteConnection {

		var $socket;
		var $errno;
		var $errstr;
		var $timeout = 3;
		var $last_svr_response;

		function remoteConnection($host, $port) {
			return $this->open($host, $port);
		}

		// opens a new connection
		function open($host, $port) {
			return $this->socket = fsockopen($host, $port, $this->errno, $this->errstr);
		}

		// writes a response to server
		function write($data) {
			if (!$this->socket) return -1;
			$this->debug("C", $data);
			return fwrite($this->socket, $data);
		}

		// prints debug messages if enabled.
		function debug($id, $string) {
			if (REMOTECONN_DEBUG  == 1) {
				echo "$id: ".trim($string)."\n";
			}
		}

		// returns|sets last server response.
		function last($svr_response = null) {
			if ($svr_response) $this->last_svr_response = $svr_response;
			return $this->last_svr_response;
		}

		// reads data from server
		function read() {
			do {
				stream_set_timeout($this->socket, $this->timeout);
				if (!strlen($buff = fread($this->socket, 4092))) break;
				$data .= $buff;
			} while (1);
			$this->debug("S", $this->last($data));
			return $data;
		}

		// closes remote connection
		function close() {
			fclose($this->socket);
		}
	}


	/*
		*** ftpSession basic usage example ***
		$ftp = new ftpSession("localhost", 21, "user", "pass");
		if ($ftp) {

			$ftp->cd("public_html");
			$ftp->chmod("conf.php", 0777);

			header("content-type: image/png");
			echo $ftp->get("me.png");

			$ftp->bye();
		}
	*/


	class ftpSession {

		var $info = array();
		var $conn;

		function ftpSession($host, $port = 21, $user = "anonymous", $pass = "anonymous@example.com") {
			$this->info["host"] = $host;
			$this->info["port"] = $port ? $port : 21;
			$this->info["user"] = $user ? $user : "anonymous";
			$this->info["pass"] = $pass ? $pass : "anonymous@example.com";
			$this->login();
		}

		// talks with server, expects responses, etc...
		function chat($expects, $answers = null, $avoid_errors = true) {
			$data = $this->conn->read();
			if (substr(trim($data), 0, 3) == $expects) {
				if ($answers) {
					$this->conn->write($answers);
				}
				return true;
			} else {
				if ($avoid_errors) return false;
				trigger_error("S: \"".trim($data)."\", expecting: \"$expects\"", E_USER_ERROR);
			}
		}

		function login() {
			if (!$this->info["host"]) trigger_error("Please set FTP Account info first!", E_USER_ERROR);
			if (($this->conn = new remoteConnection($this->info["host"], $this->info["port"])) !== false) {
				$this->chat("220", "USER ".$this->info["user"]."\r\n");
				$this->chat("331", "PASS ".$this->info["pass"]."\r\n");
				$this->chat("230") or $this->error('FTP_WRONG_PASSWORD');
				return true;
			}
		}
		function mkdir($dirname, $mod) {
			$this->conn->write("MKD $dirname\r\n");
			return $this->chat("257");
		}
		function chmod($filename, $mod) {
			$this->conn->write("SITE CHMOD $mod $filename\r\n");
			return $this->chat("200");
		}
		function cd($dirname) {
			$this->conn->write("CWD $dirname/\r\n");
			return $this->chat("250");
		}
		function delete($filename) {
			$this->conn->write("DELE $filename\r\n");
			return $this->chat("250");
		}
		function rmdir($dirname) {
			$this->conn->write("RMD $dirname/\r\n");
			return $this->chat("250");
		}
		function rename($oldfile, $newfile) {
			$this->write("RNFR $oldfile\r\n");
			if ($this->chat("350")) {
				$this->write("RNTO $newfile\r\n");
				return $this->chat("250");
			}
		}
		function get($filename) {

			$this->conn->write("TYPE I\r\n");
			$this->chat("200");

			// switching to passive mode
			$this->conn->write("PASV\r\n");
			$this->chat("227");

			// getting data connection host and port
			preg_match("/\((.*)\)/", $this->conn->last(), $m);
			$m = explode(",", $m[1]);

			$host = $m[0].".".$m[1].".".$m[2].".".$m[3];
			$port = ($m[4]*256)+$m[5];

			// opening connection and downloading data
			if ($dataConn = new remoteConnection($host, $port)) {
				$this->conn->write("RETR $filename\r\n");
				$this->chat("150");
				$data = $dataConn->read();
				$dataConn->close();
			} else {
				$this->error('FTP_DATA_CONNECTION_ERROR');
			}

			if (!$this->chat("226")) {
				$this->error('FTP_NO_FILE');
				return false;
			}

			return $data;
		}
		function error($err) {
			echo "FTP Error: ";
			switch ($err) {
				case 'FTP_WRONG_PASSWORD':
					echo "Wrong username or password.";
				break;
				case 'FTP_DATA_CONNECTION_ERROR':
					echo "Data connection error.";
				break;
				case 'FTP_NO_FILE':
					echo "No such file or directory.";
				break;
				default: echo "Unknown error";
			}
			echo "\n";
			die;
		}
		function bye() {
			$this->conn->write("QUIT\r\n");
			$this->conn->close();
		}
	}

	/*
		*** httpSession basic usage example ***

		if (($http = new httpSession("example.com", "80")) !== false) {
			header("content-type: image/png");
			echo $http->get("/somedir/somefile.png");
			$http->close();
		}
	*/
	class httpSession {

		var $userAgent = "Gekko/0.5";
		var $conn, $info, $head, $body;

		function httpSession($host, $port = 80, $user = null, $pass = null) {
			$this->info["host"] = $host;
			$this->info["port"] = $port ? $port : 80;
			$this->info["user"] = $user;
			$this->info["pass"] = $pass;
			return $this->open($this->info["host"], $this->info["port"], $this->info["user"], $this->info["pass"]);
		}
		function open($host, $port, $user, $pass) {
			if (($this->conn = new remoteConnection($host, $port)) !== false) {
				return true;
			}
			return false;
		}
		function get($what) {

			$this->conn->write("GET ".($what ? $what : "/")." HTTP/1.0\r\n");
			$this->conn->write("Host: ".$this->info["host"].":".$this->info["port"]."\r\n");
			$this->conn->write("User-Agent: ".$this->userAgent."\r\n");
			if ($this->info["user"]) $this->conn->write("Authorization: Basic ".base64_encode($this->info["user"].":".$this->info["pass"])."\r\n");
			$this->conn->write("Accept: */*\r\n");
			$this->conn->write("Accept-Encoding: gzip,deflate\r\n");
			$this->conn->write("\r\n");

			$buff = $this->conn->read();

			$dlmt = strpos($buff, "\r\n\r\n");

			$this->head = substr($buff, 0, $dlmt);
			$this->body = substr($buff, $dlmt+4);

			$answ = false;
			$headlines = explode("\n", $this->head);
			foreach ($headlines as $header) {
				if (!$anws) {
					$anws = $header;
					// expecting HTTP/1.1 200 OK
					if (!strpos($anws, "200")) return false;
				}
				$del = strpos($header, ":");
				$hdr = strtolower(substr($header, 0, $del));
				$val = trim(substr($header, $del+1));

				switch ($hdr) {
					case "content-encoding":
						// Read http://www.php.net/manual/en/function.gzinflate.php
						if ($val == "gzip") $this->body = gzinflate(substr($this->body, 10));
					break;
				}
			}

			return $this->body;
		}
		function close() {
			$this->conn->close();
		}
	}

	function parseURI($uri) {
		$r = array();
		preg_match("/^([a-zA-Z0-9]*)?\:\/\/([^\/]+)(.*)/i", $uri, $m);

		$r["proto"] = $m[1];
		$r["host"] = $m[2];
		$r["file"] = $m[3];

		if (($d = strpos($r["host"], "@")) !== false) {
			$r["user"] = substr($r["host"], 0, $d);
			$r["host"] = substr($r["host"], $d+1);
		}
		if (($d = strpos($r["user"], ":")) !== false) {
			$r["pass"] = substr($r["user"], $d+1);
			$r["user"] = substr($r["user"], 0, $d);
		}
		if (($d = strpos($r["host"], ":")) !== false) {
			$r["port"] = substr($r["host"], $d+1);
			$r["host"] = substr($r["host"], 0, $d);
		}
		return $r;
	}

	function getfile($location, $try = 0) {

		$uri = parseURI($location);

		$try++;

		switch ($uri["proto"]) {
			// http get
			case "http":
				$rc = new httpSession($uri["host"], $uri["port"], $uri["user"], $uri["pass"]);
				if (($buff = $rc->get($uri["file"])) !== false) {
					$rc->close();
				} else {
					// checking headers
					$headers = explode("\n", $rc->head);
					foreach ($headers as $header) {
						$del = strpos($header, ":");
						$hdr = strtolower(substr($header, 0, $del));
						$val = trim(substr($header, $del+1));
						switch ($hdr) {
							case "location":
								// preventing loop
								if ($try > 1) return false;
								$rc->close();

								// making new url
								$new_url = "http://";
								$uri2 = parseURI($val);
								if ($uri["user"]) {
									$new_url .= "".$uri["user"].":".$uri["pass"]."@";
								}
								$new_url .= $uri["host"].($uri["port"] ? ":".$uri["port"]: "");
								$new_url .= $uri2["file"];

								$buff = getfile($new_url, $try);
							break;
						}
					}
				}
			break;
			case "ftp":
				$rc = new ftpSession($uri["host"], $uri["port"], $uri["user"], $uri["pass"]);
				$buff = $rc->get(substr($uri["file"], 1));
				$rc->bye();
			break;
			default:
				if (!file_exists($location)) ;
				if (($h = fopen($location, "r") != false) {
					$buff = fread($h, filesize($location));
					fclose($h);
				}
			break;
		}
		return $buff ? $buff : false;
	}

	echo getfile("/etc/passwd");

?>