Code Coverage |
||||||||||
Classes and Traits |
Functions and Methods |
Lines |
||||||||
Total | |
100.00% |
1 / 1 |
|
100.00% |
18 / 18 |
CRAP | |
100.00% |
159 / 159 |
Hm_Router | |
100.00% |
1 / 1 |
|
100.00% |
20 / 20 |
61 | |
100.00% |
158 / 158 |
process_request($config, $debug_mode) | |
100.00% |
1 / 1 |
1 | |
100.00% |
14 / 14 |
|||
format_response_content($response_data, $allowed_output) | |
100.00% |
1 / 1 |
1 | |
100.00% |
2 / 2 |
|||
render_output($output, $response_data) | |
100.00% |
1 / 1 |
1 | |
100.00% |
3 / 3 |
|||
process_module_setup($config, $debug_mode) | |
100.00% |
1 / 1 |
2 | |
100.00% |
3 / 3 |
|||
get_debug_modules($config) | |
100.00% |
1 / 1 |
3 | |
100.00% |
12 / 12 |
|||
get_production_modules($config) | |
100.00% |
1 / 1 |
1 | |
100.00% |
4 / 4 |
|||
check_for_tls($config, $request) | |
100.00% |
1 / 1 |
5 | |
100.00% |
6 / 6 |
|||
setup_session($config) | |
100.00% |
1 / 1 |
4 | |
100.00% |
16 / 16 |
|||
get_active_mods($mod_list) | |
100.00% |
1 / 1 |
1 | ||||||
anonymous function($v) | |
100.00% |
1 / 1 |
1 | ||||||
load_modules($class, $module_sets) | |
100.00% |
1 / 1 |
4 | |
100.00% |
10 / 10 |
|||
load_module_sets($config, $handlers=array(), $output=array()) | |
100.00% |
1 / 1 |
1 | |
100.00% |
7 / 7 |
|||
load_module_set_files($mods, $active_mods) | |
100.00% |
1 / 1 |
4 | |
100.00% |
6 / 6 |
|||
check_for_redirected_msgs($session, $request) | |
100.00% |
1 / 1 |
4 | |
100.00% |
3 / 3 |
|||
check_for_redirect($request, $session, $result) | |
100.00% |
1 / 1 |
7 | |
100.00% |
13 / 13 |
|||
get_page($request, $filters) | |
100.00% |
1 / 1 |
11 | |
100.00% |
18 / 18 |
|||
process_page($request, $session, $config) | |
100.00% |
1 / 1 |
1 | |
100.00% |
5 / 5 |
|||
merge_response($response, $config, $request, $session) | |
100.00% |
1 / 1 |
1 | |
100.00% |
10 / 10 |
|||
merge_filters($existing, $new) | |
100.00% |
1 / 1 |
5 | |
100.00% |
9 / 9 |
|||
page_redirect($url, $status=false) | |
100.00% |
1 / 1 |
3 | |
100.00% |
13 / 13 |
<?php | |
if (!defined('DEBUG_MODE')) { die(); } | |
/** | |
* Page request router. This class ties together everything needed to process | |
* a request, initiate a session, run handler modules assigned to the request, | |
* and possibly do an HTTP redirect | |
*/ | |
class Hm_Router { | |
/* request id */ | |
public $page = 'home'; | |
/** | |
* Main entry point to the router. All the work of processing input and sending output to and from | |
* the browser happens here. | |
* | |
* @param $config object site configuration object | |
* @param $debug_mode bool true to use debug modules | |
* | |
* @return array list of the response array, the session object, and the allowed output filters | |
* for ajax responses | |
*/ | |
public function process_request($config, $debug_mode) { | |
/* get module assignments and input whitelists */ | |
list($filters, $handler_mods, $output_mods) = $this->process_module_setup($config, $debug_mode); | |
/* process inbound data */ | |
$request = new Hm_Request($filters); | |
/* check for HTTP TLS */ | |
$this->check_for_tls($config, $request); | |
/* initiate a session class */ | |
$session = $this->setup_session($config); | |
/* determine page or ajax request name */ | |
$this->get_page($request, $filters); | |
/* load processing modules for this page */ | |
$this->load_module_sets($config, $handler_mods, $output_mods); | |
/* run all the handler modules for a page and merge in some standard results */ | |
$response_data = $this->merge_response($this->process_page($request, $session, $config), $config, $request, $session); | |
/* check for POST redirect messages */ | |
$this->check_for_redirected_msgs($session, $request); | |
/* see if we should redirect this request */ | |
$this->check_for_redirect($request, $session, $response_data); | |
/* format and output the response data */ | |
$this->render_output($this->format_response_content($response_data, $request->allowed_output), $response_data); | |
/* save any cached stuff */ | |
Hm_Page_Cache::save($session); | |
/* save nonce set */ | |
hm_nonce::save($session); | |
/* close down the session */ | |
$session->end(); | |
} | |
/** | |
* Format result of output modules | |
* | |
* @param $response_data mixed data from output modules | |
* @param $allowed_output array filters applied to JSON formatted output | |
* | |
* @return mixed formatted content | |
*/ | |
private function format_response_content($response_data, $allowed_output) { | |
$formatter = new $response_data['router_format_name'](); | |
return $formatter->format_content($response_data, $allowed_output); | |
} | |
/** | |
* Send the formatted content to the user | |
* | |
* @param $output mixed data to send to the user | |
* @param $response_data mixed router details | |
* | |
* @return void | |
*/ | |
private function render_output($output, $response_data) { | |
$renderer = new Hm_Output_HTTP(); | |
$renderer->send_response($output, $response_data); | |
} | |
/** | |
* Build a list of module properties | |
* | |
* @param $config object site config object | |
* | |
* @return array list of filters, input, and output modules | |
*/ | |
private function process_module_setup($config, $debug_mode) { | |
if ($debug_mode) { | |
return $this->get_debug_modules($config); | |
} | |
else { | |
return $this->get_production_modules($config); | |
} | |
} | |
/** | |
* Get module data when in debug mode | |
* | |
* @param $config object site config object | |
* | |
* @return array list of filters, input, and output modules | |
*/ | |
private function get_debug_modules($config) { | |
$filters = array(); | |
$filters = array('allowed_output' => array(), 'allowed_get' => array(), 'allowed_cookie' => array(), | |
'allowed_post' => array(), 'allowed_server' => array(), 'allowed_pages' => array()); | |
$modules = explode(',', $config->get('modules', '')); | |
foreach ($modules as $name) { | |
if (is_readable(sprintf(APP_PATH."modules/%s/setup.php", $name))) { | |
$filters = Hm_Router::merge_filters($filters, require sprintf(APP_PATH."modules/%s/setup.php", $name)); | |
} | |
} | |
$handler_mods = array(); | |
$output_mods = array(); | |
return array($filters, $handler_mods, $output_mods); | |
} | |
/** | |
* Get module data when in production mode | |
* | |
* @param $config object site config object | |
* | |
* @return array list of filters, input, and output modules | |
*/ | |
public function get_production_modules($config) { | |
$filters = $config->get('input_filters', array()); | |
$handler_mods = $config->get('handler_modules', array()); | |
$output_mods = $config->get('output_modules', array()); | |
return array($filters, $handler_mods, $output_mods); | |
} | |
/** | |
* Force TLS connections unless the site config has it disabled | |
* | |
* @param $config object site config object | |
* @param $request object request object | |
* | |
* @return void | |
*/ | |
public function check_for_tls($config, $request) { | |
if (!$request->tls && !$config->get('disable_tls', false)) { | |
if (array_key_exists('SERVER_NAME', $request->server) && array_key_exists('REQUEST_URI', $request->server)) { | |
Hm_Router::page_redirect('https://'.$request->server['SERVER_NAME'].$request->server['REQUEST_URI']); | |
} | |
} | |
} | |
/** | |
* Start the correct session and auth objects. This only initiates the objects | |
* and does not process any session values yet | |
* | |
* @param $config object site config object | |
* | |
* @return object new session object | |
*/ | |
private function setup_session($config) { | |
$session_type = $config->get('session_type', false); | |
$auth_type = $config->get('auth_type', false); | |
if ($auth_type) { | |
if ($auth_type == 'DB') { | |
require_once APP_PATH.'third_party/pbkdf2.php'; | |
} | |
$auth_class = sprintf('Hm_Auth_%s', $auth_type); | |
} | |
else { | |
$auth_class = 'Hm_Auth_None'; | |
} | |
if ($session_type == 'DB') { | |
$session_class = 'Hm_DB_Session'; | |
} | |
else { | |
$session_class = 'Hm_PHP_Session'; | |
} | |
Hm_Debug::add(sprintf('Using %s with %s', $session_class, $auth_class)); | |
$session = new $session_class($config, $auth_class); | |
return $session; | |
} | |
/** | |
* Return the subset of active modules from a supplied list | |
* | |
* @param $mod_list array list of modules | |
* | |
* @return array filter list | |
*/ | |
public function get_active_mods($mod_list) { | |
return array_unique(array_values(array_map(function($v) { return $v[0]; }, $mod_list))); | |
} | |
/** | |
* Load modules into a module manager | |
* | |
* @param $class string name of the module manager to use | |
* @param $module_sets array list of modules by page | |
* | |
* @return void | |
*/ | |
public function load_modules($class, $module_sets) { | |
foreach ($module_sets as $page => $modlist) { | |
foreach ($modlist as $name => $vals) { | |
if ($this->page == $page) { | |
$class::add($page, $name, $vals[1], false, 'after', true, $vals[0]); | |
} | |
} | |
} | |
$class::try_queued_modules(); | |
$class::process_all_page_queue(); | |
} | |
/** | |
* Load all module sets and include required modules.php files | |
* | |
* @param $config object site config object | |
* @param $handlers array list of handler modules | |
* @param $output array list of output modules | |
* | |
* @return void | |
*/ | |
private function load_module_sets($config, $handlers=array(), $output=array()) { | |
$this->load_modules('Hm_Handler_Modules', $handlers); | |
$this->load_modules('Hm_Output_Modules', $output); | |
$active_mods = array_unique(array_merge($this->get_active_mods(Hm_Output_Modules::get_for_page($this->page)), | |
$this->get_active_mods(Hm_Handler_Modules::get_for_page($this->page)))); | |
$mods = explode(',', $config->get('modules', '')); | |
$this->load_module_set_files($mods, $active_mods); | |
} | |
/** | |
* Load module set definition files | |
* | |
* @param $mods array modules to load | |
* @param $active_mods array list of active modules | |
* | |
* @return void | |
*/ | |
public function load_module_set_files($mods, $active_mods) { | |
foreach ($mods as $name) { | |
if (in_array($name, $active_mods, true) && is_readable(sprintf(APP_PATH.'modules/%s/modules.php', $name))) { | |
require sprintf(APP_PATH.'modules/%s/modules.php', $name); | |
} | |
} | |
} | |
/** | |
* Collect pending user notices from a cookie after a redirect | |
* | |
* @param $session object session interface | |
* @param $request object request details | |
* | |
* @return void | |
*/ | |
public function check_for_redirected_msgs($session, $request) { | |
if (array_key_exists('hm_msgs', $request->cookie) && trim($request->cookie['hm_msgs'])) { | |
$msgs = @unserialize(base64_decode($request->cookie['hm_msgs'])); | |
if (is_array($msgs)) { | |
array_walk($msgs, function($v) { Hm_Msgs::add($v); }); | |
} | |
$session->secure_cookie($request, 'hm_msgs', '', 0); | |
} | |
} | |
/** | |
* Redirect the page after a POST form is submitted and forward any user notices | |
* | |
* @param $request object request details | |
* @param $session object session interface | |
* | |
* @return void | |
*/ | |
public function check_for_redirect($request, $session, $result) { | |
if (array_key_exists('no_redirect', $result) && $result['no_redirect']) { | |
return; | |
} | |
if (!empty($request->post) && $request->type == 'HTTP') { | |
$msgs = Hm_Msgs::get(); | |
if (!empty($msgs)) { | |
$session->secure_cookie($request, 'hm_msgs', base64_encode(serialize($msgs)), 0); | |
} | |
$session->end(); | |
if (array_key_exists('REQUEST_URI', $request->server)) { | |
Hm_Router::page_redirect($request->server['REQUEST_URI']); | |
} | |
} | |
} | |
/** | |
* Determine the page id | |
* | |
* @param $request object request details | |
* @param $filters array list of filters | |
* | |
* @return void | |
*/ | |
public function get_page($request, $filters) { | |
if (array_key_exists('allowed_pages', $filters)) { | |
$pages = $filters['allowed_pages']; | |
} | |
else { | |
$pages = array(); | |
} | |
if ($request->type == 'AJAX' && array_key_exists('hm_ajax_hook', $request->post) && in_array($request->post['hm_ajax_hook'], $pages, true)) { | |
$this->page = $request->post['hm_ajax_hook']; | |
} | |
elseif ($request->type == 'AJAX' && array_key_exists('hm_ajax_hook', $request->post) && !in_array($request->post['hm_ajax_hook'], $pages, true)) { | |
Hm_Functions::cease(json_encode(array('status' => 'not callable')));; | |
} | |
elseif (array_key_exists('page', $request->get) && in_array($request->get['page'], $pages, true)) { | |
$this->page = $request->get['page']; | |
} | |
elseif (!array_key_exists('page', $request->get)) { | |
$this->page = 'home'; | |
} | |
else { | |
$this->page = 'notfound'; | |
} | |
} | |
/** | |
* Process all the data handler modules for this page | |
* | |
* @param $request object request details | |
* @param $session object session interface | |
* @param $config object site config | |
* | |
* @return array combined handler module output | |
*/ | |
private function process_page($request, $session, $config) { | |
$response = array(); | |
$handler = new Hm_Request_Handler(); | |
$modules = Hm_Handler_Modules::get_for_page($this->page); | |
$response = $handler->process_request($this->page, $request, $session, $config, $modules); | |
return $response; | |
} | |
/** | |
* Merge the combined response from the handler modules with some default values | |
* | |
* @param $response array combined result of the handler modules | |
* @param $config object site config | |
* @param $request object request details | |
* @param $session object session interface | |
* | |
* @return void | |
*/ | |
private function merge_response($response, $config, $request, $session) { | |
return array_merge($response, array( | |
'router_page_name' => $this->page, | |
'router_request_type' => $request->type, | |
'router_sapi_name' => $request->sapi, | |
'router_format_name' => $request->format, | |
'router_login_state' => $session->is_active(), | |
'router_url_path' => $request->path, | |
'router_module_list' => $config->get('modules', ''), | |
'router_app_name' => $config->get('app_name', 'HM3') | |
)); | |
} | |
/** | |
* Merge input filters from module sets | |
* | |
* @param $existing array already collected filters | |
* @param $new array new filters to merge | |
* | |
* @return array merged list | |
*/ | |
static public function merge_filters($existing, $new) { | |
foreach (array('allowed_output', 'allowed_get', 'allowed_cookie', 'allowed_post', 'allowed_server', 'allowed_pages') as $v) { | |
if (array_key_exists($v, $new)) { | |
if ($v == 'allowed_pages' || $v == 'allowed_output') { | |
$existing[$v] = array_merge($existing[$v], $new[$v]); | |
} | |
else { | |
$existing[$v] += $new[$v]; | |
} | |
} | |
} | |
return $existing; | |
} | |
/** | |
* Perform an HTTP redirect | |
* | |
* @param $url string url to redirect to | |
* | |
* @return void | |
*/ | |
static public function page_redirect($url, $status=false) { | |
if (DEBUG_MODE) { | |
Hm_Debug::add(sprintf('Redirecting to %s', $url)); | |
Hm_Debug::load_page_stats(); | |
Hm_Debug::show('log'); | |
} | |
if ($status == 303) { | |
Hm_Debug::add('Redirect loop found'); | |
Hm_Functions::cease('Redirect loop discovered'); | |
} | |
Hm_Functions::header('HTTP/1.1 303 Found'); | |
Hm_Functions::header('Location: '.$url); | |
Hm_Functions::cease(); | |
} | |
} | |
?> |