From d235aa33f9b53986428dd6fc35fd98fc2a3866d6 Mon Sep 17 00:00:00 2001 From: obi11235 Date: Sat, 26 Apr 2014 03:03:17 -0400 Subject: [PATCH 1/5] Fix Bug with missing directories in plugins --- system/class/FileDispatcher.class.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/system/class/FileDispatcher.class.php b/system/class/FileDispatcher.class.php index a89437f..27dc5c3 100644 --- a/system/class/FileDispatcher.class.php +++ b/system/class/FileDispatcher.class.php @@ -371,7 +371,8 @@ private static function scandirRecursive($path) return $tree; } else - throw new exception('Not a dir'); + //throw new exception('Not a dir'); + return array(); } /** From d2e0deaebe6fa97a732b3901776d3f9cccf099e8 Mon Sep 17 00:00:00 2001 From: Paul Date: Sat, 26 Apr 2014 03:13:21 -0400 Subject: [PATCH 2/5] Adding Request Class --- system/class/Debug.class.php | 2 + system/class/Request.class.php | 480 +++++++++++++++++++++++++++++++++ system/include/common.inc.php | 2 +- 3 files changed, 483 insertions(+), 1 deletion(-) create mode 100644 system/class/Request.class.php diff --git a/system/class/Debug.class.php b/system/class/Debug.class.php index b7bfa38..1eac1b0 100644 --- a/system/class/Debug.class.php +++ b/system/class/Debug.class.php @@ -60,6 +60,7 @@ class Debug implements iSession const LOG_GLOBALS = 'LOG_GLOBALS'; const LOG_PAGELOAD_TIME = 'LOG_PAGE_LOAD_TIME'; const LOG_CODEBASE = 'LOG_CODEBASE'; + const LOG_REQUEST = 'LOG_REQUEST'; /** * Used by validate options * @var array of avalable options @@ -79,6 +80,7 @@ class Debug implements iSession self::LOG_PERMISSION, self::LOG_SMARTY, self::LOG_FILEDISPATCHER, + self::LOG_REQUEST, ); //Display modes diff --git a/system/class/Request.class.php b/system/class/Request.class.php new file mode 100644 index 0000000..6b178f7 --- /dev/null +++ b/system/class/Request.class.php @@ -0,0 +1,480 @@ + $var_name) + { + list($src_name, $dest_name) = explode(':', $var_name.':'); + if (!$dest_name) $dest_name = $src_name; + + $var_list[$key] = $dest_name; + + if (!isset(self::$_REQUEST[$src_name])) + { + $values[$dest_name] = $default; + } + else if (!is_array(self::$_REQUEST[$src_name])) + { + if(sizeof($argv)) + $val = call_user_func($func, self::$_REQUEST[$src_name], $argv); + else + $val = call_user_func($func, self::$_REQUEST[$src_name]); + + $values[$dest_name] = $val; + } + else + { + $values[$dest_name] = self::parseArray(self::$_REQUEST[$src_name], $default, $func, $argv); + } + } + + if( count($var_list) == 1 ) + return $values[$var_list[0]]; + else + return $values; + } + + /** + * Private function used by parseList + * @param $var_list + * @param $default + * @param $func + * @param $argv + * @return + */ + private static function parseArray($var_list, $default, $func, $argv) + { + $values = array(); + foreach ($var_list as $key=>$val) + { + $values[$key] = !is_array($val) ? call_user_func($func, $val, $argv) : self::parseArray($val, $default, $func, $argv); + } + + return $values; + } + + /** + * Private function used to cast a value to a date + * @param $date + * @param $argv + * @return + */ + private static function castDate($date, $argv) + { + $ts = strtotime($date); + return $ts !== FALSE ? date($argv[0], $ts) : NULL; + } + + /** + * private function used to cast a value as an enum + * @param $value + * @param $argv + * @return + */ + private static function castEnum($value, $argv) + { + return in_array($value, $argv[0]) ? $value : $argv[1]; + } + + /** + * Private function used to cast a value as a boolean + * @param $value + * @return + */ + private static function castBool($value) + { + return ($value == 'false' || !$value) ? FALSE : TRUE; + } + +// public: + /** + * Called to setup the Request class + */ + public static function initialize() + { + + self::$_REQUEST = $_REQUEST; + Debug::log(self::$_REQUEST, Debug::LOG_REQUEST); + } + + public static function initPathInfo( $vars = FALSE ) + { + $path_info = FileDispatcher::getPathInfo(); + if($path_info === FALSE) + $path_info = $_SERVER['PATH_INFO']; + + $pi_parts = explode('/', $path_info); + if(array_shift($pi_parts) != '') throw new Exception( "URI error" ); + + if($vars != FALSE) + { + $names = explode('/', $vars); + array_shift($names); + foreach($names as $key=>$n) + if(isset($pi_parts[$key])) + $url_vars[$n] = $pi_parts[$key]; + $pi_parts = $url_vars; + } + + self::$_REQUEST = array_merge(self::$_REQUEST, $pi_parts); + } + + /** + * Used to get a Date string from a request or get submission + * + * If you are requesting a path info variable use the syntax: + * + * 0:username + * + * you are requesting the first path info variable and naming it username + * + * @param string $var_list comma seperated list of values to get from request + * @param string $format date format string + * @param boolean $default default value to return if variable is not found + * @return mixed string if one item is requested, an array if multiple are requested + */ + public static function getDateString($var_list, $format='m/d/Y', $default = NULL) + { + return self::parseList($var_list, $default, array('Request', 'castDate'), $format); + } + + /** + * Used to get a string from the request object validating it with a list of + * possible options for the enum + * + * If you are requesting a path info variable use the syntax: + * + * 0:username + * + * you are requesting the first path info variable and naming it username + * @param string $var_list comma seperated list of values to get from request + * @param array $options posible values for the enum + * @param boolean $default default value to return if variable is not found + * @return mixed string if one item is requested, an array if multiple are requested + */ + public static function getEnum($var_list, $options, $default = NULL) + { + return self::parseList($var_list, $default, array('Request', 'castEnum'), $options, $default); + } + + /** + * Used to get a float from the request object validating it as a float + * + * If you are requesting a path info variable use the syntax: + * + * 0:username + * + * you are requesting the first path info variable and naming it username + * + * @param string $var_list comma seperated list of values to get from request + * @param boolean $default default value to return if variable is not found + * @return mixed string if one item is requested, an array if multiple are requested + */ + public static function getFloat($var_list, $default = 0.0) + { + return self::parseList($var_list, $default, 'floatval'); + } + + /** + * Used to get a integer from the request object validating it as a integer + * + * If you are requesting a path info variable use the syntax: + * + * 0:username + * + * you are requesting the first path info variable and naming it username + * + * @param string $var_list comma seperated list of values to get from request + * @param boolean $default default value to return if variable is not found + * @return mixed string if one item is requested, an array if multiple are requested + */ + public static function getInteger($var_list, $default = 0) + { + return self::parseList($var_list, $default, 'intval'); + } + + /** + * Used to get a boolean from the request object validating it as a boolean value + * + * If you are requesting a path info variable use the syntax: + * + * 0:username + * + * you are requesting the first path info variable and naming it username + * + * @param string $var_list comma seperated list of values to get from request + * @param boolean $default default value to return if variable is not found + * @return mixed string if one item is requested, an array if multiple are requested + */ + public static function getBoolean($var_list, $default = FALSE) + { + return self::parseList($var_list, $default, array('Request', 'castBool')); + } + + /** + * Used to get a string from the request object + * + * If you are requesting a path info variable use the syntax: + * + * 0:username + * + * you are requesting the first path info variable and naming it username + * + * @param string $var_list comma seperated list of values to get from request + * @param boolean $default default value to return if variable is not found + * @return mixed string if one item is requested, an array if multiple are requested + */ + public static function getString($var_list, $default = '') + { + return self::parseList($var_list, $default, 'strval'); + } + + /** + * returns the name of the domain (www.domain.com) + * @return string + */ + public static function getDomain() + { + return $_SERVER['HTTP_HOST']; + } + + /** + * returns the path requested by the client ($_SERVER['uri']) + * @return string + */ + public static function getURI() + { + return $_SERVER['REQUEST_URI']; + } + + /** + * Returns the relative URL of the current page + * @return String + */ + public static function getRelativeURL() + { + $uri = Request::getURI(); + if( strpos($uri, '?') ) + { + $uri_bits = explode('?',$uri); + $uri = $uri_bits[0]; + } + if( !$uri ) + $uri = '/'; + + return $uri; + } + + /** + * Returns the absolute url of the current page (including http protocol) + * @return String + */ + public static function getAbsoluteURL() + { + $relative_url = Request::getRelativeURL(); + $protocol = self::getProtocol(); + $host = $_SERVER['HTTP_HOST']; + if( !$protocol || !$host || !$relative_url ) + throw new Exception( Request::ERR_INTERNAL ); + return $protocol . '://' . $host . $relative_url; + } + + /** + * Returns the http protocol for the current page + * @return String + */ + public static function getProtocol() + { + $protocol = array_key_exists( 'HTTPS', $_SERVER ) ? 'https' : 'http'; + return $protocol; + } + + /** + * Returns the document root + * @return string + */ + public static function getDocumentRoot() + { + return DOCUMENT_ROOT; + } + + /** + * + * @return String Fieldname of CSRF key + */ + public static function get_csrf_key_field() + { + return CSRF_FIELD; + } + + /** + * + * @return String CSRF key + */ + public static function get_csrf_key() + { + return $_SESSION[CSRF_FIELD]; + } + + /* + * check_csrf_key() + * $key: optional paramater to specify a key to be checked + * instead of the standard key in the request values + * + * Checks and cache's the results of the default key, checks the + * otional key live, take no action other than returning true or false + * + * @return: true if key is valid, false otherwise + */ + private static function check_csrf_key( $key = '' ) + { + if(!isset($_SESSION[CSRF_FIELD]) || $_SESSION[CSRF_FIELD] == '' ) + { + self::$valid_csrf = false; + return false; + } + + if(isset($key) && $key != '') return ($key == $_SESSION[CSRF_FIELD]); + + if(isset(self::$valid_csrf)) return self::$valid_csrf; + + if (isset(self::$request_csrf_key) && self::$request_csrf_key != '') $key = self::$request_csrf_key; + else if (isset(self::$_REQUEST[CSRF_FIELD])) + { + self::$request_csrf_key = self::$_REQUEST[CSRF_FIELD]; + $key = self::$request_csrf_key; + } + else + { + self::$valid_csrf = false; + return false; + } + + self::$valid_csrf = ($key == $_SESSION[CSRF_FIELD]); + + return self::$valid_csrf; + } + + /* + * verify_csrf_key() + * $key: optional paramater to specify a key to be checked + * instead of the standard key in the request values + * + * logs all verification failures, in authoritative mode + * will redirect to the index page. + * + * @return: true if key is valid, false otherwise + */ + public static function verify_csrf_key() + { + $key = ''; + $fatal = false; + + $param_count = func_num_args(); + + if($param_count == 0) + { + $key = ''; + $fatal = true; + } + else if ($param_count == 1) + { + $arg = func_get_arg(0); + if(is_bool($arg)) + { + $key = ''; + $fatal = $arg; + } + else if(is_string($arg)) + { + $key = $arg; + $fatal = true; + } + else if( is_null($arg) ) + { + $key = ''; + $fatal = true; + } + else + throw new Exception("Wrong argument type given"); + } + else if ($param_count == 2) + { + unset($key); + unset($fatal); + + $arg = func_get_args(); + + foreach($arg as $a) + { + if(is_bool($a) && !isset($fatal)) $fatal = $a; + else if(is_string($a) && !isset($key)) $key = $a; + else throw new Exception("Wrong argument type given"); + } + + if(!isset($key) || !isset($fatal)) throw new Exception("Wrong argument type given"); + } + else throw new Exception("Wrong number of arguments given, got {$param_count} expected 0 - 2"); + + if( self::check_csrf_key($key) ) return true; + else self::log_csrf_failure($fatal); + //TODO: when fatal is true ths should redirect rather than return + if($fatal) die('Fatal CSRF failure'); + else return false; + } + + /** + * log_csrf_failure() + * logs the site information + * @param boolean indicates if the error was fatal or not + */ + private static function log_csrf_failure($fatal) + { + $error_message = "Start CSRF Failure\n".$_SERVER['SCRIPT_FILENAME'].PHP_EOL. + 'Fatal: '.($fatal?'TRUE':'FALSE').PHP_EOL. + $_SERVER['REMOTE_ADDR'].PHP_EOL. + '$_SERVER[SERVER_NAME]: '.$_SERVER['SERVER_NAME'].PHP_EOL. + '$_SERVER[REQUEST_URI]: '.$_SERVER['REQUEST_URI'].PHP_EOL. + '_REQUEST: '.var_export($_REQUEST, TRUE).PHP_EOL. + '$_SESSION[CSRF_FIELD]: '.$_SESSION[CSRF_FIELD].PHP_EOL. + '$_COOKIE[CSRF_FIELD]: '.$_COOKIE[CSRF_FIELD].PHP_EOL. + "End CSRF Failure\n"; + try{ + $error_log = @fopen(CSRF_LOG_FILE, 'a'); + if( !@fwrite($error_log, $error_message) ) + throw new Exception( 'Failed writing file.' ); + @fclose($error_log); + } + catch (Exception $e) + { + error_log($error_message); + } + } + + } + +// no php end tag (not required- causes problems with unwanted whitespace) \ No newline at end of file diff --git a/system/include/common.inc.php b/system/include/common.inc.php index 70199d2..59900ad 100644 --- a/system/include/common.inc.php +++ b/system/include/common.inc.php @@ -103,7 +103,7 @@ function __autoload($class) { $class_parts = explode('_', $class, 2); - $file = EMBER_PLUGIN_DIR.$class_parts[0].DS.'class'.DS.$class_parts[0].'_'.str_replace("_", "/", $class_parts[1]).'.class.php'; + $file = EMBER_PLUGIN_DIR.$class_parts[0].DS.'class'.DS.$class_parts[0].'/'.str_replace("_", "/", $class_parts[1]).'.class.php'; if(is_file($file)) require $file; else From 6fa60e900b425049ccb999036cb2ff32e4384006 Mon Sep 17 00:00:00 2001 From: obi11235 Date: Sat, 26 Apr 2014 03:23:38 -0400 Subject: [PATCH 3/5] FileDispatcher bug --- system/class/FileDispatcher.class.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/system/class/FileDispatcher.class.php b/system/class/FileDispatcher.class.php index a89437f..911a07e 100644 --- a/system/class/FileDispatcher.class.php +++ b/system/class/FileDispatcher.class.php @@ -371,7 +371,8 @@ private static function scandirRecursive($path) return $tree; } else - throw new exception('Not a dir'); + //throw new exception('Not a dir'); + return array(); } /** @@ -392,4 +393,4 @@ public static function http404($die = TRUE) if($die) die; } -} \ No newline at end of file +} From dcdff555a794c7522a6c669090d33e78efc67019 Mon Sep 17 00:00:00 2001 From: obi11235 Date: Sat, 26 Apr 2014 03:27:39 -0400 Subject: [PATCH 4/5] Adding support to specify a site from CLI scripts --- bin/test_cli.php | 2 ++ system/class/Site.class.php | 5 ++++- system/include/common.inc.php | 2 ++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/bin/test_cli.php b/bin/test_cli.php index 4a3ade9..e8988b7 100644 --- a/bin/test_cli.php +++ b/bin/test_cli.php @@ -1,6 +1,8 @@ Date: Sat, 26 Apr 2014 03:44:20 -0400 Subject: [PATCH 5/5] Bug fix with supporting Site config in cli mode --- system/include/common.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/include/common.inc.php b/system/include/common.inc.php index 599be7a..3ccad76 100644 --- a/system/include/common.inc.php +++ b/system/include/common.inc.php @@ -33,7 +33,7 @@ function getPageLoadTime() $inital_path = ini_get('include_path'); ini_set('include_path', '/var/www/ember/system/include:/var/www/ember/system/lib/php:'.$inital_path); define('SESSION_TYPE', 'cli'); - $_SERVER = array(); + if(!is_array($_SERVER)) $_SERVER = array(); //TODO: make this generic $_SERVER['DOCUMENT_ROOT'] = '/var/www/ember/webroot'; $_SERVER['HTTP_USER_AGENT'] = 'cli';