<?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
	*	@subpackage	/lib
	*	@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
	*/

	/*
		Those are core functions supposed for being used in every
		script
	*/

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

	set_magic_quotes_runtime(0);

	require_once(GEKKO_ROOT."dbconf.php");
	require_once(GEKKO_ROOT."lib/database.lib.php");
	require_once(GEKKO_ROOT."modules/conf/core.lib.php");

	# Core Group Database (read HACKING file)
	require_once(GEKKO_ROOT."cgdb.php");

	require_once(GEKKO_ROOT."lib/cache.lib.php");
	require_once(GEKKO_ROOT."lib/lang.lib.php");
	require_once(GEKKO_ROOT."lib/accesscontrol.lib.php");

	Class ModCore {
		var $buff;
		var $main;
		function root($module) {
			return GEKKO_ROOT."modules/$module/";
		}
		function check($module, $main = true) {
			if ($module) {
				$module = preg_replace("/[^a-z0-9\.\-\_]/i", "", $module);
				return ereg("\.\.", $module) ? false : file_exists(ModCore::root($module).($main ? "main.inc.php" : ""));
			}
		}
		function is_installed($module) {
			$q = $GLOBALS["db"]->query("SELECT ID FROM ".db_table("module")." WHERE Module = '{$module}'", __FILE__, __LINE__, true);
			return ($GLOBALS["db"]->num_rows($q));
		}
		function getModClass($module) {
			return "GekkoModule_".preg_replace("/[^a-z0-9]/i", "_", $module);
		}
		function modInstall($module, $type = "I") {

			/*
				Types:
					U = Uninstall
					R = Reinstall
					I = Install
					P = Upgrade
			*/

			require_once GEKKO_ROOT."modules/packages/main.lib.php";

			require_once GEKKO_ROOT."modules/$module/module.inc.php";

			$modclass = modCore::getModClass($module);
			$modclass = new $modclass;

			/* reading package.xml */
			$modxml = pkg_get_xml($module);

			if ($type == "P") {
				if (($inform = pkg_checkInstall($modxml)) == false) {
					// getting installed version
					$installed_version = conf::getKey($module, "_version");

					// upgrading
					$modclass->upgrade($installed_version);

					// new configuration variables, keeping user settings
					$modclass->configure();

					// seting new version
					conf::setKey($module, "_version", $modxml["release"]["version"], "s");
				}
			}

			if ($type == "U" || $type == "R") {

				/* dropping from modules */
				$GLOBALS["db"]->query("DELETE FROM ".db_table("module")." WHERE Module = '{$module}'", __FILE__, __LINE__, true);

				/* cleaning conf */
				Conf::delKey($module, "*");

				/* uninstalling */
				$modclass->uninstall();

				/* deep cleaning */
				if (isset($modxml["requires"]["module"]))
					foreach ($modxml["requires"]["module"] as $required) {
						require_once GEKKO_ROOT."modules/$required/module.inc.php";

						$reqclass = modCore::getModClass($required);
						$reqclass = new $reqclass;

						$reqclass->ext_uninstall($module);

						unset($reqclass);
					}
			}

			if ($type == "I" || $type == "R") {

				/* checking package dependencies and requeriments */

				if (($inform = pkg_checkInstall($modxml)) == false) {

					$modclass->install();

					$modclass->configure();

					/*
					if (!modCore::is_installed($module)) {
						// super user access only for unknown modules
						$group = isset($GLOBALS["cgdb"][$module]) ? $GLOBALS["cgdb"][$module] : "1";
						modCore::registerModule($group, $module, "#", $group);
					}
					*/

					/* module version */
					conf::setKey($module, "_version", $modxml["release"]["version"], "s");

				} else {
					/* missing dependency */
					header("content-type: text/plain");
					echo $inform;
					abort();
				}

			}

			unset ($modclass);

			return false;
		}
		function save($data) {
			$this->buff .= $data;
		}
		function data() {
			return $this->buff;
		}
		function getModules($packages = true) {
			if (!isset($GLOBALS["_cache"]["Modules"])) {
				$r = array();
				$o = opendir(GEKKO_ROOT."modules/");
				while (($f = readdir($o)) !== false) {
					if ($f == "." || $f == ".." || !is_dir(GEKKO_ROOT."modules/".$f)) continue;
					$r[] = $f;
				}
				closedir($o);
				$GLOBALS["_cache"]["Modules"] = $r;
			}
			return $GLOBALS["_cache"]["Modules"];
		}
		function registerModule($id, $module, $access, $admin) {
			/*
				Assigned ID for new modules are reserved from 1 up to 64
				for Gekko official modules. Custom modules for your
				application must be registered with and ID major than
				64
				* read HACKING file
			*/

			// checking if module or id is already registered
			$q = $GLOBALS["db"]->query("SELECT ID FROM ".db_table("module")." WHERE ID = '{$id}' OR Module = '{$module}'",__FILE__, __LINE__, true);

			if ($GLOBALS["db"]->num_rows($q)) {
				// refusing to duplicate module name or id
				trigger_error("Couldn't register module '$module' with id '$id': Duplicated ID or NAME. Please read HACKING file.", E_USER_ERROR);
			}

			// registering module
			$q = $GLOBALS["db"]->query("
			INSERT INTO ".db_table("module")."
				(ID, Module, auth_Exec, auth_Manage, Modified)
			VALUES
				('$id', '".strtolower($module)."', '$access', '$admin', '".time()."')
			", __FILE__, __LINE__, true);

			// registering group if not exists
			$q = $GLOBALS["db"]->query(
				"SELECT ID FROM ".db_table("group")." WHERE ID = '$id'",
				__FILE__, __LINE__, true
			);
			if (!$GLOBALS["db"]->num_rows($q)) {
				$q = $GLOBALS["db"]->query("INSERT INTO ".db_table("group")." (ID, Groupname, Description) VALUES ('$id', '$module', '".ucfirst($module)."')");
			}
		}
	}

	/*
		gauth(String auth, String levels);

		Returns true when $level is contained within $auth string.
		When $level is not set, this function takes users groups
		as $level and checks if one of the $levels (separated by
		commas) matchs with one of the auth levels (separated by
		commas too).

		For example:
			gauth("1,2,3", "4,5");
		Returns false, since both 4 and 5 are out of $auth
		variable
			gauth("4,2", "2");
		Returns true, "2" is contained into "4,2"

		Remember that both $auth and $levels must be strings
		containing comma-separated numeric values. But you can
		pass (at least for $auth) a module name, this will be
		automatically replaced by its corresponding id.
	*/

	function gauth($auth, $level = "") {
		// when no level is speficied, takes user groups
		if (!$level) $level = $GLOBALS["User"]["Groups"];

		// both $auth & $level are separated by commas
		$auth = explode(",", $auth);
		$level = explode(",", $level);

		// when $auth argument is not an integer it should
		// be a module name
		while (list($key) = each($auth)) {
			if ((strlen($auth[$key]) > 1) && (!is_integer($auth[$key]))) {
				$auth[$key] = isset($GLOBALS["cgdb"][$auth[$key]]) ? $GLOBALS["cgdb"][$auth[$key]] : $auth[$key];
			}
		}

		// checking level codes
		/*
			Level ranges
			code -  returns true for
			  1  -  super user (el mero mero)
			  *  -  any level
			  @  -  reserved gekko core modules (1 - 200)
			  #  -  reserved module levels (1 - 400)
			  $  -  user level (1 - 500)
			  ?  -  unprivileged level (501 or no groups)
		*/

		if (in_array("*", $auth)) return true;

		foreach ($level as $check) {
			// note that I'm using (x > 0)
			if (($check = intval(trim($check))) > 0) {
				// access granted using level codes
				if ($check <= 200 && in_array("@", $auth)) return true;
				if ($check <= 400 && in_array("#", $auth)) return true;
				if ($check <= 500 && in_array("$", $auth)) return true;
				if ($check == 501 && in_array("?", $auth)) return true;
				// superadmin has total access to any level because we love him/her :)
				# if (($check === $GLOBALS["cgdb"]["admin"]) && !in_array("?", $auth)) return true;
				if ($check === $GLOBALS["cgdb"]["admin"]) return true;
				// access granted using specific levels
				if (in_array($check, $auth)) return true;
			} else {
				// no groups means no access
				if (in_array("?", $auth)) return true;
			}
		}
		return false;
	}
	// authentication hash
	function mkauth($hash, $key) {
		return $key.":".md5($hash.IP_ADDR);
	}
	// random string
	function genkey($len, $charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") {
		$charlen = strlen($charset);
		$return = "";
		for ($i = 0; $i < $len; $i++) {
			$return .= $charset[rand(0, $charlen-1)];
		}
		return $return;
	}
	// set cookie
	function gcookie($name, $value = null, $life = null) {
		setCookie (
			conf::getkey("core", "site.cookie.prefix").$name,
			$value,
			time() + (($life > 0) ? $life : conf::getkey("core", "site.cookie.life")),
			conf::getkey("core", "site.cookie.path")
		);
	}
	// read cookie
	function rcookie($name) {
		return isset($_COOKIE[conf::getkey("core", "site.cookie.prefix").$name]) ? $_COOKIE[conf::getkey("core", "site.cookie.prefix").$name] : null;
	}

	/*
		_ext(variable name, position);
		Extracts a variable identified by $var from
		$_SERVER["PATH_INFO"] (when $pos is specified)
		or $_GET (when $var is psecified)
	*/
	function _ext($index, $pos = 0) {
		if ($pos && isset($_SERVER["PATH_INFO"])) {
			// $pos: index.php/0/1/2/3/n
			$inf = explode("/", trim($_SERVER["PATH_INFO"], "/"));
			sanitize($inf[$pos]);
			if (isset($inf[$pos])) return $inf[$pos];
		}
		// if you specify $var as a list separated by commas, then
		// this function will return only the first match
		$index = explode(",", $index);
		foreach ($index as $i) {
			if (isset($_GET[$i = trim($i)])) return $_GET[$i];
		}
		// when position or index doesn't exists
		return false;
	}


	/*
	*	slog(System message, file to save, importance level);
	*	Logs
	*/
	function slog($string, $file, $level = 5) {
		/*
			Level ranges from 1 up to 5
			level 5: lesser importart
			level 1: really important
		*/
		if ($level < 1 || $level > 5) return true;

		/*
			normal users can ignore major part of slog() messages
		*/
		if ($level > 2 && !GEKKO_ENABLE_DEBUG) {
			return true;
		}

		$logdir = GEKKO_ROOT."temp/logs/";

		if (!file_exists($logdir)) { mkdir($logdir); fixfile($logdir); }

		if (($h = @fopen($logdir.$file.".log", "a")) !== false) {
			if (!defined("SLOG_LOGGED_".strtoupper($file))) {
				$log = "\n[".date("d/m/Y H:i:s")."] ".((isset($GLOBALS["User"]) ? "(uid={$GLOBALS["User"]["ID"]}) {$GLOBALS["User"]["Username"]}@": ""))."".getIP()." [{$_SERVER["HTTP_USER_AGENT"]}]\n{$_SERVER["REQUEST_URI"]}";
				$log = $string ? "$log\n-- $string\n" : "$log\n";
				define("SLOG_LOGGED_".strtoupper($file), true);
			}
			fwrite($h, isset($log) ? $log : "-- $string\n");
			fclose($h);
		}
	}

	/*
	*	abort();
	*	Aborts Gekko execution, closes SQL connections.
	*/
	function abort($msg = null, $output_buffer = true) {

		if (isset($GLOBALS["db"])) $GLOBALS["db"]->close();

		slog("Aborted: ".($msg ? $msg : "No error message")."", "error", 1);

		if ($msg)  echo $msg;

		if ($output_buffer && function_exists("gzoutput")) {
			gzoutput();
		}

		die;
	}

	/*
	*	fixfile(String path);
	*	An attempt to fix file permissions problems between user and
	*	webserver privileges.
	*/
	function fixfile($file) {
		if (!is_writable($file))
			@chmod ($file, 0775);
	}

	/*
		Reads and entire file
	*/
	function fileread($fname) {
		if (($h = @fopen($fname, "r")) !== false) {
			$c = fread($h, filesize($fname));
			fclose($h);
			return $c;
		} else {
			trigger_error("Couldn't read \"$fname\".", E_USER_NOTICE);
		}
	}
	function listdir($dir, $recursive = false, $only_files = false) {

		if (substr($dir, -1) != "/") $dir .= "/";

		$dp = @opendir($dir);
		$dc = Array();
		while (($file = @readdir($dp)) !== false) {
			if ($file != "." && $file != "..") {
				if ($recursive && is_dir($dir.$file)) {
					$tmp = listdir($dir.$file, true);
					$dfs = Array();
					foreach ($tmp as $f) {
						$dfs[] = $file."/".$f;
					}
					$dc = array_merge($dc, $dfs);
					if ($only_files) continue;

				}
				$dc[] = $file;
			}
		}
		@closedir($dp);
		return $dc;
	}

	// sends and http request to redirect our browser
	function redirect($where) {
		header("Location: $where");
	}

	// Sanitinizing variables for avoiding SQL injections
	function sanitize(&$var) {
		if (is_array($var)) {
			foreach ($var as $key => $tmp) {
				sanitize($var[$key]);
			}
		} else {
			if (!get_magic_quotes_gpc()) {
				$var = str_replace("'", "\'", $var);
			}
		}
	}

	function unsanitize() {
		if (is_array($var)) {
			foreach ($var as $key => $tmp) {
				unsanitize($var[$key]);
			}
		} else {
			if (!get_magic_quotes_gpc()) {
				$var = str_replace("\'", "'", $var);
			}
		}
	}

	/*
		TODO: Grants or denies access for modules.
	*/
	function gateKeeper($modules, $authStr, $abort = true) {
		if (!gauth($modules) || $authStr != _l("C_AUTH_STR")) {
			if ($abort) { abort(accessDenied(1)); }
			return false;
		}
		return true;
	}

	function checkAuthStr($auth) {
		return ($auth == _l("C_AUTH_STR"));
	}

	/*
		Renames an Array key
			keyren(array, old name, new name);
	*/
	function keyren(&$array, $old, $new) {
		$array[$new] = $array[$old];
		unset($array[$old]);
	}

	function execWithEach(&$var, $exec) {
		if (is_array($var)) {
			foreach ($var as $key => $tmp) {
				execWithEach($var[$key], $exec);
			}
		} else {
			eval("$exec(\$var);");
		}
	}
	function accessDenied($print = false, $file = false, $line = false) {
		if (GEKKO_ENABLE_DEBUG && $file && $line) {
			echo "$file:$line\n";
		}
		if ($print) {
			echo _l("E_ACCESS_DENIED");
		} else {
			return _l("E_ACCESS_DENIED");
		}
	}

	function gdebug($text, $exit = 1) {
		header("content-type: text/plain");
		print_r($text);
		if ($exit) die;
	}

	function fill($string, $size, $char = "0") {
		while (strlen($string) < $size) $string = $char.$string;
		return $string;
	}
	function mkdate($unixtime = null) {
		return date("d-m-Y H:i:s A", $unixtime ? $unixtime : time());
	}
	function date2mysqltime($date) {
		return $date["y"].fill($date["m"], 2).fill($date["d"], 2)."000000";
	}
	function timestamp($time = null) {
		return date("YmdHis", $time ? $time : time());
	}
	function timestampdate($sqltime) {
		return mktime(substr($sqltime,8, 2), substr($sqltime, 10, 2), substr($sqltime, 12, 2), substr($sqltime, 4, 2), substr($sqltime, 6, 2), substr($sqltime, 0, 4));
	}

	function check_value($check, $allowed, $default = false) {
		return in_array($check, explode(",", $allowed)) ? $check : $default;
	}
	function file_extension($file) {
		return strtolower(substr($file = basename($file), (strpos(strrev($file), ".")*-1)));
	}
	function db_get_field($table, $id, $field = null, $use_cache = true) {
		$return = false;
		$cache = "query_field($id,$table,$field)";
		if (!$use_cache || cache::get($cache) === false) {

			$q = $GLOBALS["db"]->query("SELECT ".($field ? $field : "*")." FROM ".db_table($table)." WHERE ID = '{$id}'", __FILE__, __LINE__, true);
			if ($GLOBALS["db"]->num_rows($q)) {
				$return = Array();
				$row = $GLOBALS["db"]->fetch_row($q);
				if (!is_array($row)) break;
				foreach ($row as $key => $val) {
					$return[$key] = $val;
				}
			}

			$return = $return ? ($field ? $return[$field] : $return) : false;

			if ($use_cache) {
				cache::set($cache, $return);
			} else {
				return $return;
			}

		}
		return cache::get($cache);
	}

	function local_referer() {
		if (isset($_SERVER["HTTP_REFERER"])) {
			preg_match("/http:\/\/.*?\/(.*)/", $_SERVER["HTTP_REFERER"], $m);
			return "/".$m[1];
		} else {
			return "";
		}
	}

	/*
		timeMark(yyyy.mm.dd)
		@returns: unix timestamp range
	*/
	function timeMark($time) {
		$return = false;
		$time = explode(".", preg_replace("[^0-9.]", "", $time));

		if (count($time)) {
			$return = Array();

			if ($time[0] < 1901 && count($time) > 1)
				$time[0] = date("Y");

			if (isset($time[1]) && ($time[1] < 1 || $time[1] > 12)) $time[1] = 1;
			if (isset($time[2]) && ($time[2] < 1 || $time[2] > 31)) $time[2] = 1;

			if (isset($time[1]) && isset($time[2])) {
				/* yyyy.mm.dd */
				$lo = mktime(0, 0, 0, $time[1], $time[2], $time[0]);
				$hi = mktime(23, 59, 59, $time[1], $time[2], $time[0]);
			} elseif (isset($time[1])) {
				/* yyyy.mm */
				$lo = mktime(0, 0, 0, $time[1], 1, $time[0]);
				$hi = mktime(23, 59, 59, $time[1], date("t", $lo), $time[0]);
			} else {
				/* yyyy */
				$lo = $time[0] ? mktime(0, 0, 0, 1, 1, $time[0]) : 0;
				$hi = $time[0] ? mktime(23, 59, 59, 12, 31, $time[0]) : time();
			}
			$return = Array($lo, $hi);
		}
		return $return;
	}

	function get_last_page($items, $per_page) {
		return intval($items/$per_page) + (($items%$per_page) ? 1 : 0);
	}

	function use_ssl() {
		if (!defined("GEKKO_NO_SSL") && !isset($_GET["no_ssl"]) && !isset($_SERVER["HTTPS"])) {
			// trying to determine if this server supports ssl
			if (function_exists("apache_get_modules")) {
				$ap_mods = apache_get_modules();
				// if it does, redirecting user to SSL mode.
				if (in_array("mod_ssl", $ap_mods)) {
					if (!defined("IN-INSTALL"))
						$GLOBALS["AccessTable"]->dropEntry("core-exec-preban");
					redirect("https://".$_SERVER["HTTP_HOST"].$_SERVER["REQUEST_URI"]);
					abort(null, false);
				}
			}
		}
	}
	function ssl_normal_redirect(&$return) {
		// using ssl only for specifical tasks
		if (isset($_SERVER["HTTPS"])) {
			if ($return) {
				$return = "http://".$_SERVER["HTTP_HOST"].dirname($_SERVER["SCRIPT_URL"])."/".$return;
			} else {
				$return = "http".substr($_SERVER["HTTP_REFERER"], 5);
			}
		}
	}

	// converts text strings into a url-friendly form
	function title_encode($title) {
		$title = preg_replace("/[^a-zA-Z0-9]/e", "sprintf('%%%x',ord('\\0'))", $title);
		$title = str_replace("%20", "+", $title);
		$title = str_replace("%2d", "-", $title);
		return $title;
	}

	// sets or changes variables passed by url (such as index.php?foo=bar)
	function url_set_var($var, $val, $url = "") {

		if (!$url)
			$url = $_SERVER["REQUEST_URI"];

		// your must urlencode it manually before passing it as an argument
		//$val = urlencode($val);

		// searching variable in the current url
		if (preg_match("/(\?|&)$var=.*(&|$)/", $url)) {
			$url = preg_replace("/(\?|&)($var\=.*?)(&|$)/", "\\1$var=$val\\3", $url);
		} else {
			// not found, appending it
			$url .= (preg_match("/\?.*\=.*/", $url) ? "&" : "?")."$var=$val";
		}

		return $url;
	}

	define("IP_ADDR", getIP());
	define("INIT_TIME", getmicrotime());

	# common processes
	sanitize($_GET);
	sanitize($_POST);
	sanitize($_COOKIE);
	sanitize($_SERVER);

	if (!defined("IN-INSTALL"))
		cache_init();

	if (GEKKO_DEMO_MODE) {
		// deleting temporary files older than 30 minutes
		$c_list = Array("temp/cache", "data/uploads");
		foreach ($c_list as $c_item) {
			$items = listdir(GEKKO_ROOT.$c_item, true, true);
			foreach ($items as $item) {
				$item = GEKKO_ROOT.$c_item."/".$item;
				if ((time() - filemtime($item)) > 1800) {
					@unlink($item);
				}
			}
		}
	}

?>
