So much refactoring...

This commit is contained in:
Joshua Sherman 2013-12-30 00:38:13 -05:00
parent 03e613d380
commit 54471c361b
9 changed files with 562 additions and 707 deletions

View file

@ -32,10 +32,9 @@ class Config extends Object
/** /**
* Config data * Config data
* *
* @access private * @var array
* @var array
*/ */
private $data = array(); public $data = array();
/** /**
* Constructor * Constructor
@ -236,19 +235,6 @@ class Config extends Object
return parent::getInstance($class); return parent::getInstance($class);
} }
/**
* Magic Setter Method
*
* Prohibits the direct modification of module variables.
*
* @param string $name name of the variable to be set
* @param mixed $value value of the variable to be set
*/
public function __set($name, $value)
{
throw new Exception('Cannot set config variables directly', E_USER_ERROR);
}
/** /**
* Magic Getter Method * Magic Getter Method
* *

View file

@ -39,341 +39,346 @@ class Controller extends Object
parent::__construct(); parent::__construct();
// Generate a generic "site down" message if the site is set to be disabled // Generate a generic "site down" message if the site is set to be disabled
// @todo Clean this up to be just a single sanity check try
if (isset($this->config->pickles['disabled']) && $this->config->pickles['disabled'] == true)
{ {
Error::fatal($_SERVER['SERVER_NAME'] . ' is currently<br>down for maintenance'); // @todo Clean this up to be just a single sanity check
} if (isset($this->config->pickles['disabled']) && $this->config->pickles['disabled'] == true)
// Checks for attributes passed in the URI
if (strstr($_REQUEST['request'], ':'))
{
$parts = explode('/', $_REQUEST['request']);
$_REQUEST['request'] = '';
foreach ($parts as $part)
{ {
if (strstr($part, ':')) // @todo Add support for custom templates
throw new Exception('
<h1>Down for Maintenance</h1>
<p>' . $_SERVER['SERVER_NAME'] . ' is currently down for maintenance. Please check back in a few minutes.</p>
<p>Additionally, a custom maintenance template was not found.</p>
<hr>
<em>Powered by <a href="https://github.com/joshtronic/pickles">PICKLES</a></em>
');
}
// Checks for attributes passed in the URI
if (strstr($_REQUEST['request'], ':'))
{
$parts = explode('/', $_REQUEST['request']);
$_REQUEST['request'] = '';
foreach ($parts as $part)
{ {
list($variable, $value) = explode(':', $part); if (strstr($part, ':'))
Browser::set($variable, $value); {
list($variable, $value) = explode(':', $part);
Browser::set($variable, $value);
}
else
{
$_REQUEST['request'] .= ($_REQUEST['request'] ? '/' : '') . $part;
}
}
}
// Catches requests that aren't lowercase
$lowercase_request = strtolower($_REQUEST['request']);
if ($_REQUEST['request'] != $lowercase_request)
{
// @todo Rework the Browser class to handle the 301 (perhaps redirect301()) to not break other code
header('Location: ' . substr_replace($_SERVER['REQUEST_URI'], $lowercase_request, 1, strlen($lowercase_request)), true, 301);
throw new Exception();
}
// Grabs the requested page
$request = $_REQUEST['request'];
// Loads the module's information
$module_class = strtr($request, '/', '_');
$module_filename = SITE_MODULE_PATH . $request . '.php';
$module_exists = file_exists($module_filename);
// Attempts to instantiate the requested module
if ($module_exists)
{
if (class_exists($module_class))
{
$module = new $module_class;
}
}
// No module instantiated, load up a generic Module
if (!isset($module))
{
$module = new Module();
}
// Determines if we need to serve over HTTP or HTTPS
if ($module->secure == false && isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'])
{
header('Location: http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'], true, 301);
throw new Exception();
}
elseif ($module->secure == true && (!isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] == false))
{
header('Location: https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'], true, 301);
throw new Exception();
}
// Validates security level
if ($module->security)
{
$is_authenticated = false;
if (is_array($module->security))
{
$module_security = $module->security;
$security_check_class = 'isLevel';
// Checks the type and validates it
if (isset($module_security['type']))
{
$security_check_type = strtoupper($module_security['type']);
if (in_array($security_check_type, ['IS', 'HAS', 'BETWEEN']))
{
$security_check_class = $security_check_type;
}
unset($module_security['type']);
}
$module_security_levels = [];
// If there's a level(s) key use it
foreach (['level', 'levels'] as $security_level_key)
{
if (isset($module_security[$security_level_key]))
{
if (is_array($module_security[$security_level_key]))
{
array_merge($module_security_levels, $module_security[$security_level_key]);
}
else
{
$module_security_levels[] = $module_security[$security_level_key];
}
unset($module_security[$security_level_key]);
}
}
// Assume everything left in the array is a level and add it to the array
array_merge($module_security_levels, $module_security);
$security_level_count = count($module_security_levels);
switch ($security_check_class)
{
// @todo Thinking of removing this?
case 'BETWEEN':
if ($security_level_count >= 2)
{
$is_authenticated = Security::betweenLevel($module_security_levels[0], array_pop($module_security_levels));
}
break;
case 'HAS':
if ($security_level_count)
{
$is_authenticated = Security::hasLevel($module_security_levels);
}
break;
case 'IS':
if ($security_level_count)
{
$is_authenticated = Security::isLevel($module_security_levels);
}
break;
}
} }
else else
{ {
$_REQUEST['request'] .= ($_REQUEST['request'] ? '/' : '') . $part; $is_authenticated = Security::isLevel($module->security);
} }
}
}
// Catches requests that aren't lowercase if (!$is_authenticated)
$lowercase_request = strtolower($_REQUEST['request']);
if ($_REQUEST['request'] != $lowercase_request)
{
// @todo Rework the Browser class to handle the 301 (perhaps redirect301()) to not break other code
header('Location: ' . substr_replace($_SERVER['REQUEST_URI'], $lowercase_request, 1, strlen($lowercase_request)), true, 301);
exit;
}
// Grabs the requested page
$request = $_REQUEST['request'];
// Loads the module's information
$module_class = strtr($request, '/', '_');
$module_filename = SITE_MODULE_PATH . $request . '.php';
$module_exists = file_exists($module_filename);
// Attempts to instantiate the requested module
if ($module_exists)
{
// @todo Is this redundant because of our autoloader?
require_once $module_filename;
if (class_exists($module_class))
{
$module = new $module_class;
}
}
// No module instantiated, load up a generic Module
if (!isset($module))
{
$module = new Module();
}
// Determines if we need to serve over HTTP or HTTPS
if ($module->secure == false && isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'])
{
Browser::redirect('http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']);
}
elseif ($module->secure == true && (!isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] == false))
{
Browser::redirect('https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']);
}
// Validates security level
if ($module->security)
{
$is_authenticated = false;
if (is_array($module->security))
{
$module_security = $module->security;
$security_check_class = 'isLevel';
// Checks the type and validates it
if (isset($module_security['type']))
{ {
$security_check_type = strtoupper($module_security['type']); if ($_SERVER['REQUEST_METHOD'] == 'POST')
if (in_array($security_check_type, ['IS', 'HAS', 'BETWEEN']))
{ {
$security_check_class = $security_check_type; // @todo Perhaps I could force a logout / redirect to the login page
exit('{"status": "error", "message": "You are not properly authenticated, try logging out and back in."}');
} }
else
unset($module_security['type']);
}
$module_security_levels = [];
// If there's a level(s) key use it
foreach (['level', 'levels'] as $security_level_key)
{
if (isset($module_security[$security_level_key]))
{ {
if (is_array($module_security[$security_level_key])) // Sets variable for the destination
{ $_SESSION['__pickles']['login']['destination'] = $_REQUEST['request'] ? $_REQUEST['request'] : '/';
array_merge($module_security_levels, $module_security[$security_level_key]);
}
else
{
$module_security_levels[] = $module_security[$security_level_key];
}
unset($module_security[$security_level_key]); // Redirect to login page
Browser::redirect('/login');
} }
} }
}
// Assume everything left in the array is a level and add it to the array // Gets the profiler status
array_merge($module_security_levels, $module_security); $profiler = $this->config->pickles['profiler'];
$security_level_count = count($module_security_levels); $profiler = $profiler === true || stripos($profiler, 'timers') !== false;
switch ($security_check_class) $default_method = '__default';
$role_method = null;
if (isset($_SESSION['__pickles']['security']['role']) && !String::isEmpty($_SESSION['__pickles']['security']['role']))
{
$role_method = '__default_' . $_SESSION['__pickles']['security']['role'];
if (method_exists($module, $role_method))
{ {
// @todo Thinking of removing this? $default_method = $role_method;
case 'BETWEEN':
if ($security_level_count >= 2)
{
$is_authenticated = Security::betweenLevel($module_security_levels[0], array_pop($module_security_levels));
}
break;
case 'HAS':
if ($security_level_count)
{
$is_authenticated = Security::hasLevel($module_security_levels);
}
break;
case 'IS':
if ($security_level_count)
{
$is_authenticated = Security::isLevel($module_security_levels);
}
break;
} }
} }
else
{
$is_authenticated = Security::isLevel($module->security);
}
if (!$is_authenticated) // Attempts to execute the default method
// @todo Seems a bit redundant, refactor
if ($default_method == $role_method || method_exists($module, $default_method))
{ {
if ($_SERVER['REQUEST_METHOD'] == 'POST') // Starts a timer before the module is executed
if ($profiler)
{ {
// @todo Perhaps I could force a logout / redirect to the login page Profiler::timer('module ' . $default_method);
exit('{"status": "error", "message": "You are not properly authenticated, try logging out and back in."}'); }
$valid_request = false;
$error_message = 'An unexpected error has occurred.';
// Determines if the request method is valid for this request
if ($module->method)
{
if (!is_array($module->method))
{
$module->method = [$module->method];
}
foreach ($module->method as $method)
{
if ($_SERVER['REQUEST_METHOD'] == $method)
{
$valid_request = true;
break;
}
}
if (!$valid_request)
{
$error_message = 'There was a problem with your request method.';
}
} }
else else
{ {
// Sets variable for the destination $valid_request = true;
$_SESSION['__pickles']['login']['destination'] = $_REQUEST['request'] ? $_REQUEST['request'] : '/';
// Redirect to login page
Browser::redirect('/login');
} }
$valid_form_input = true;
if ($valid_request && $module->validate)
{
$validation_errors = $module->__validate();
if ($validation_errors)
{
$error_message = implode(' ', $validation_errors);
$valid_form_input = false;
}
}
/**
* Note to Self: When building in caching will need to let the
* module know to use the cache, either passing in a variable
* or setting it on the object
*/
if ($valid_request && $valid_form_input)
{
$module_return = $module->$default_method();
if (!is_array($module_return))
{
$module_return = $module->return_data;
}
else
{
$module_return = array_merge($module_return, $module->return_data);
}
}
// Stops the module timer
if ($profiler)
{
Profiler::timer('module ' . $default_method);
}
// @todo Set this in the module and use $module->return and rename module->return to module->data?
$module->return = ['template', 'json'];
// Checks if we have any templates
$parent_template = $module->template;
$template_exists = $this->validateTemplates($module, $parent_template);
// No templates? 404 that shit
if (!$module_exists && !$template_exists)
{
Browser::status(404);
$_REQUEST['request'] = '__shared/404';
if (!$this->validateTemplates($module, $parent_template))
{
throw new Exception('
<h1>Not Found</h1>
<p>The requested URL /' . $request . ' was not found on this server.</p>
<p>Additionally, a custom error template was not found.</p>
<hr>
<em>Powered by <a href="https://github.com/joshtronic/pickles">PICKLES</a></em>
');
}
}
$display = new Display();
$display->return = $module->return;
$display->templates = $module->template;
$display->module = isset($module_return) ? $module_return : ['status' => 'error', 'message' => $error_message];
// @todo Check for $module->meta variable first, then remove entirely when sites are updated
$display->meta = [
'title' => $module->title,
'description' => $module->description,
'keywords' => $module->keywords
];
} }
}
// Gets the profiler status // Starts a timer for the display rendering
$profiler = $this->config->pickles['profiler'];
$profiler = $profiler === true || stripos($profiler, 'timers') !== false;
$default_method = '__default';
$role_method = null;
if (isset($_SESSION['__pickles']['security']['role']) && !String::isEmpty($_SESSION['__pickles']['security']['role']))
{
$role_method = '__default_' . $_SESSION['__pickles']['security']['role'];
if (method_exists($module, $role_method))
{
$default_method = $role_method;
}
}
// Attempts to execute the default method
if ($default_method == $role_method || method_exists($module, $default_method))
{
// Starts a timer before the module is executed
if ($profiler) if ($profiler)
{ {
Profiler::timer('module ' . $default_method); Profiler::timer('display render');
} }
$valid_request = false; // Renders the content
$error_message = 'An unexpected error has occurred.'; $output = $display->render();
// Determines if the request method is valid for this request // Stops the display timer
if ($module->method)
{
if (!is_array($module->method))
{
$module->method = [$module->method];
}
$request_method = $_SERVER['REQUEST_METHOD'];
foreach ($module->method as $method)
{
if ($request_method == strtoupper($method))
{
$valid_request = true;
break;
}
}
if (!$valid_request)
{
$error_message = 'There was a problem with your request method.';
}
}
else
{
$valid_request = true;
}
$valid_form_input = true;
if ($valid_request && $module->validate)
{
$validation_errors = $module->__validate();
if ($validation_errors)
{
$error_message = implode(' ', $validation_errors);
$valid_form_input = false;
}
}
/**
* Note to Self: When building in caching will need to let the
* module know to use the cache, either passing in a variable
* or setting it on the object
*/
if ($valid_request && $valid_form_input)
{
$module_return = $module->$default_method();
if (!is_array($module_return))
{
$module_return = $module->return_data;
}
else
{
$module_return = array_merge($module_return, $module->return_data);
}
}
// Stops the module timer
if ($profiler) if ($profiler)
{ {
Profiler::timer('module ' . $default_method); Profiler::timer('display render');
} }
}
catch (Exception $e)
{
$output = $e->getMessage();
}
finally
{
echo $output;
// @todo Set this in the module and use $module->return and rename module->return to module->data? // Display the Profiler's report if the stars are aligned
$module->return = ['template', 'json']; if ($this->config->pickles['profiler'])
// Checks if we have any templates
$parent_template = $module->template;
$template_exists = $this->validateTemplates($module, $parent_template);
// No templates? 404 that shit
if (!$module_exists && !$template_exists)
{ {
Browser::status(404); Profiler::report();
$_REQUEST['request'] = '__shared/404';
if (!$this->validateTemplates($module, $parent_template))
{
exit('
<h1>Not Found</h1>
<p>The requested URL /' . $request . ' was not found on this server.</p>
<p>Additionally, a custom error template was not found.</p>
<hr>
<em>Powered by <a href="https://github.com/joshtronic/pickles">PICKLES</a></em>
');
}
} }
$display = new Display();
$display->return = $module->return;
$display->templates = $module->template;
$display->module = isset($module_return) ? $module_return : ['status' => 'error', 'message' => $error_message];
// @todo Check for $module->meta variable first, then remove entirely when sites are updated
$display->meta = [
'title' => $module->title,
'description' => $module->description,
'keywords' => $module->keywords
];
}
// Starts a timer for the display rendering
if ($profiler)
{
Profiler::timer('display render');
}
// Renders the content
$output = $display->render();
echo $output;
// Stops the display timer
if ($profiler)
{
Profiler::timer('display render');
}
}
/**
* Destructor
*
* Dumps out the Profiler's report if applicable.
*/
public function __destruct()
{
parent::__destruct();
// Display the Profiler's report if the stars are aligned
if ($this->config->pickles['profiler'])
{
Profiler::report();
} }
} }
// @todo Document me
private function validateTemplates(&$module, $parent_template) private function validateTemplates(&$module, $parent_template)
{ {
$templates = [ $templates = [

View file

@ -265,7 +265,9 @@ class Dynamic extends Object
&& extension_loaded('curl') && extension_loaded('curl')
&& $this->config->pickles['minify'] === true) && $this->config->pickles['minify'] === true)
{ {
exec('java -jar ' . PICKLES_PATH . 'vendors/google/closure-compiler/compiler.jar --js=' . $original_filename . ' --compilation_level=' . ($level . '_' . ($level == 'WHITESPACE' ? 'ONLY' : 'OPTIMIZATIONS')) . ' --js_output_file=' . $minified_filename); $config = Config::getInstance();
exec('java -jar ' . $config->pickles['path'] . 'vendors/google/closure-compiler/compiler.jar --js=' . $original_filename . ' --compilation_level=' . ($level . '_' . ($level == 'WHITESPACE' ? 'ONLY' : 'OPTIMIZATIONS')) . ' --js_output_file=' . $minified_filename);
$reference = $minified_reference; $reference = $minified_reference;
} }

View file

@ -1,104 +0,0 @@
<?php
/**
* Error Reporting for PICKLES
*
* PHP version 5
*
* Licensed under The MIT License
* Redistribution of these files must retain the above copyright notice.
*
* @author Joshua Sherman <pickles@joshtronic.com>
* @copyright Copyright 2007-2013, Joshua Sherman
* @license http://www.opensource.org/licenses/mit-license.html
* @package PICKLES
* @link https://github.com/joshtronic/pickles
*/
/**
* Error Class
*
* Standardized error reporting, mostly used to display fatal errors.
*/
class Error
{
/**
* Fatal Error
*
* Displays a friendly error to the user via HTML, logs it then exits.
*
* @static
* @param string $message the message to be displayed to the user
*/
public static function fatal($message)
{
$config = Config::getInstance();
if ($config->pickles['logging'] === true)
{
if (Log::error($message) == false)
{
$message .= '<br><br>This error message could not be logged as the log path or log file is not writable';
}
}
?>
<!DOCTYPE html>
<html>
<head>
<title><?php echo $_SERVER['SERVER_NAME']; ?> - error</title>
<style>
html
{
background: #eee;
font-family: "Lucida Sans", "Lucida Grande", "Lucida Sans Unicode", Verdana, Arial, sans-serif;
width: 100%;
height: 100%;
font-size: 1em;
}
body
{
text-align: center;
margin-top: 100px;
}
div
{
font-size: 150%;
color: #600;
text-shadow: 2px 2px 2px #eb8383;
margin: 0;
font-weight: bold;
background: #ff9c9c;
padding: 20px;
border-radius: 20px;
-moz-border-radius: 20px;
-webkit-border-radius: 20px;
width: 550px;
margin: 0 auto;
border: 3px solid #890f0f;
}
h1, a
{
font-size: 70%;
color: #999;
text-decoration: none;
}
a:hover
{
color: #000;
}
</style>
</head>
<body>
<h1><?php echo $_SERVER['SERVER_NAME']; ?></h1>
<div><?php echo $message; ?></div>
<a href="https://github.com/joshtronic/pickles" target="_blank">Powered by PICKLES</a>
</body>
</html>
<?php
exit;
}
}
?>

View file

@ -182,7 +182,7 @@ class Profiler
'log' => $log, 'log' => $log,
'type' => $data_type, 'type' => $data_type,
'time' => $time, 'time' => $time,
'elapsed' => $time - PICKLES_START_TIME, 'elapsed' => $time - $_SERVER['REQUEST_TIME_FLOAT'],
'memory' => memory_get_usage(), 'memory' => memory_get_usage(),
); );
} }
@ -325,9 +325,9 @@ class Profiler
} }
else else
{ {
$start_time = PICKLES_START_TIME; $start_time = $_SERVER['REQUEST_TIME_FLOAT'];
$peak_usage = self::formatSize(memory_get_peak_usage()); $peak_usage = self::formatSize(memory_get_peak_usage());
$end_time = self::$profile[count(self::$profile) - 1]['time']; // TODO $end_time = self::$profile[count(self::$profile) - 1]['time']; // @todo No idea what though?
$duration = ($end_time - $start_time); $duration = ($end_time - $start_time);
$logs = count(self::$profile); $logs = count(self::$profile);

View file

@ -23,30 +23,27 @@
// {{{ PICKLES Constants // {{{ PICKLES Constants
// Grabs the start time in case we're profiling // @todo Finish reworking constants to be part of the Config object
define('PICKLES_START_TIME', microtime(true));
// Establishes our PICKLES paths
define('PICKLES_PATH', dirname(__FILE__) . '/');
define('PICKLES_CLASS_PATH', PICKLES_PATH . 'classes/');
define('PICKLES_VENDOR_PATH', PICKLES_PATH . 'vendors/');
// Establishes our site paths, sanity check is to allow vfsStream in our tests // Establishes our site paths, sanity check is to allow vfsStream in our tests
if (!defined('SITE_PATH')) if (!defined('SITE_PATH'))
{ {
define('SITE_PATH', getcwd() . '/../'); define('SITE_PATH', getcwd() . '/../');
} }
define('SITE_CLASS_PATH', SITE_PATH . 'classes/'); if (!defined('SITE_CLASS_PATH'))
define('SITE_MODEL_PATH', SITE_PATH . 'models/'); {
define('SITE_MODULE_PATH', SITE_PATH . 'modules/'); define('SITE_CLASS_PATH', SITE_PATH . 'classes/');
define('SITE_TEMPLATE_PATH', SITE_PATH . 'templates/'); define('SITE_MODEL_PATH', SITE_PATH . 'models/');
// @todo The following 2 constants are being used in sites will need to update them before removing
define('SITE_MODULE_PATH', SITE_PATH . 'modules/');
define('SITE_TEMPLATE_PATH', SITE_PATH . 'templates/');
define('PRIVATE_PATH', SITE_PATH . 'private/'); define('PRIVATE_PATH', SITE_PATH . 'private/');
define('LOG_PATH', PRIVATE_PATH . 'logs/'); define('LOG_PATH', PRIVATE_PATH . 'logs/');
// Creates a variable to flag if we're on the command line // Creates a variable to flag if we're on the command line
define('IS_CLI', !isset($_SERVER['REQUEST_METHOD'])); define('IS_CLI', !isset($_SERVER['REQUEST_METHOD']));
}
// }}} // }}}
// {{{ Defaults some important configuration options // {{{ Defaults some important configuration options
@ -55,10 +52,6 @@ define('IS_CLI', !isset($_SERVER['REQUEST_METHOD']));
ini_set('display_errors', true); ini_set('display_errors', true);
error_reporting(-1); error_reporting(-1);
// Sets the error and exception handlers
// set_error_handler('__handleError');
// set_exception_handler('__handleException');
// Defaults timezone to UTC if not set // Defaults timezone to UTC if not set
if (ini_get('date.timezone') == '') if (ini_get('date.timezone') == '')
{ {
@ -74,14 +67,75 @@ ini_set('session.gc_probability', 1);
ini_set('session.gc_divisor', 1000); ini_set('session.gc_divisor', 1000);
ini_set('session.hash_function', 1); ini_set('session.hash_function', 1);
// }}}
// {{{ Auto[magical] Loader
/**
* Magic function to automatically load classes
*
* Attempts to load a core PICKLES class or a site level data model or
* module class.
*
* @param string $class Name of the class to be loaded
* @return boolean Return value of require_once() or false (default)
*/
function __autoload($class)
{
$loaded = false;
$filename = preg_replace('/_/', '/', $class) . '.php';
$pickles_path = dirname(__FILE__) . '/';
$pickles_paths = [
'class' => $pickles_path . 'classes/',
'vendor' => $pickles_path . 'vendors/',
];
if ($class == 'AYAH')
{
$loaded = require_once $pickles_paths['vendor'] . 'ayah/' . strtolower($filename);
}
else
{
// Path as the key, boolean value is whether ot not to convert back to hyphenated
$paths = [
$pickles_paths['class'] => false,
SITE_CLASS_PATH => false,
SITE_MODEL_PATH => false,
SITE_MODULE_PATH => true,
];
foreach ($paths as $path => $hyphenated)
{
// Converts the filename back to hypenated
if ($hyphenated == true)
{
$filename = strtolower(preg_replace('/([A-Z]{1})/', '-$1', $filename));;
}
if (file_exists($path . $filename))
{
$loaded = require_once $path . $filename;
break;
}
}
}
return $loaded;
}
spl_autoload_register('__autoload');
// }}} // }}}
// {{{ Loads the configuration file and sets any configuration options // {{{ Loads the configuration file and sets any configuration options
// Loads the base config // Loads the base config
$config = Config::getInstance(); $config = Config::getInstance();
// Injects PICKLES variables into the config
$config->data['pickles']['path'] = dirname(__FILE__) . '/';
// Configures any available PHP configuration options // Configures any available PHP configuration options
if (is_array($config->php) && count($config->php) > 0) if (is_array($config->php) && count($config->php))
{ {
foreach ($config->php as $variable => $value) foreach ($config->php as $variable => $value)
{ {
@ -115,261 +169,6 @@ if (!isset($_REQUEST['request']))
$_REQUEST['request'] = 'home'; $_REQUEST['request'] = 'home';
} }
// }}}
// {{{ Auto[magical] Loader
/**
* Magic function to automatically load classes
*
* Attempts to load a core PICKLES class or a site level data model or
* module class.
*
* @param string $class Name of the class to be loaded
* @return boolean Return value of require_once() or false (default)
*/
function __autoload($class)
{
$loaded = false;
$filename = preg_replace('/_/', '/', $class) . '.php';
if ($class == 'AYAH')
{
$loaded = require_once PICKLES_VENDOR_PATH . 'ayah/' . strtolower($filename);
}
else
{
// Path as the key, boolean value is whether ot not to convert back to hyphenated
$paths = array(
PICKLES_CLASS_PATH => false,
SITE_CLASS_PATH => false,
SITE_MODEL_PATH => false,
SITE_MODULE_PATH => true,
);
foreach ($paths as $path => $hyphenated)
{
// Converts the filename back to hypenated
if ($hyphenated == true)
{
$filename = strtolower(preg_replace('/([A-Z]{1})/', '-$1', $filename));;
}
if (file_exists($path . $filename))
{
$loaded = require_once $path . $filename;
break;
}
}
}
return $loaded;
}
spl_autoload_register('__autoload');
// }}}
// {{{ Error Handler
/**
* Error handling function that thinks it's magical
*
* Catches errors (warnings and the like) and throws it back out as an
* ErrorException. This really helps trapping complex errors that need a ton of
* sanity checks, just try / catch and you're good. Also, this isn't a magic
* function, but I opted to use the __ prefix to help avoid a naming collision
* since namespace support is 5.3+ and PICKLES strives to be 5.0+ compatible.
*
* Keep in mind that fatal errors cannot and will not be handled.
*
* @param integer $errno the level of the error raised
* @param string $errstr the error message
* @param string $errfile filename that the error was raised in
* @param integer $errline line number the error was raised at
* @param array $errcontext array of every variable that existed in scope
* @return ErrorException not really returned, but worth documenting
*/
function __handleError($errno, $errstr, $errfile, $errline, array $errcontext)
{
// Handle hacktastic @ error suppression. Seriously, don't ever use @
if (error_reporting() === 0)
{
return false;
}
throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
}
// }}}
// {{{ Exception Handler
/**
* Top level exception handling function
*
* Catches uncaught exceptions and displays them.
*
* @param object $exception the exception
*/
function __handleException($exception)
{
if (IS_CLI == true)
{
$lines = array();
$maxes = array('key' => 0, 'method' => 0, 'file' => 0, 'line' => 4);
$trace = $exception->getTrace();
rsort($trace);
foreach ($trace as $key => $data)
{
$method = '';
if (isset($data['class']))
{
$method .= $data['class'] . $data['type'];
}
$method .= $data['function'] . '()';
$line = array(
'key' => $key + 1 . '.',
'method' => $method,
'file' => (isset($data['file']) ? $data['file'] : __FILE__),
'line' => (isset($data['line']) ? $data['line'] : '0')
);
foreach (array_keys($maxes) as $variable)
{
$length = strlen($line[$variable]);
if ($length > $maxes[$variable])
{
$maxes[$variable] = $length;
}
}
$lines[] = $line;
}
$max_length = array_sum($maxes) + 11;
$horizontal_border = '+' . str_repeat('-', $max_length) . '+' . "\n";
echo $horizontal_border;
echo '|' . str_pad('Uncaught Exception', $max_length, ' ', STR_PAD_BOTH) . '|' . "\n";
echo $horizontal_border;
echo '|' . str_pad(' ' . $exception->getMessage(), $max_length) . '|' . "\n";
echo '|' . str_pad(' in ' . $exception->getFile() . ' on line ' . $exception->getLine(), $max_length) . '|' . "\n";
echo $horizontal_border;
echo '| ' . str_pad('Trace', $maxes['key'] + $maxes['method'] + 3) . ' | ' . str_pad('File', $maxes['file']) . ' | ' . str_pad('Line', $maxes['line']) . ' |' . "\n";
echo $horizontal_border;
foreach ($lines as $line)
{
echo '| ';
echo implode(
array(
str_pad($line['key'], $maxes['key'], ' ', STR_PAD_LEFT),
str_pad($line['method'], $maxes['method']),
str_pad($line['file'], $maxes['file']),
str_pad($line['line'], $maxes['line'], ' ', STR_PAD_LEFT)
),
' | '
);
echo ' |' . "\n";
}
echo $horizontal_border;
}
else
{
?>
<style>
#pickles-exception
{
background: #212121;
width: 800px;
margin: 0 auto;
margin-top: 20px;
margin-bottom: 20px;
border-radius: 20px;
-moz-border-radius: 20px;
-webkit-border-radius: 20px;
box-shadow: 0 3px 4px #000;
-moz-box-shadow: 0 3px 4px #000;
-webkit-box-shadow: 0 3px 4px #000;
border: 6px solid #666;
padding: 10px 20px 20px;
font-family: monospace;
font-size: 12px;
text-align: left;
}
#pickles-exception table
{
width: 100%;
}
#pickles-exception table tr th, #pickles-exception table tr td
{
padding: 10px;
}
#pickles-exception .even
{
background-color: #323232;
}
#pickles-exception, #pickles-exception table tr td, #pickles-exception table tr th
{
color: #efefe8;
}
</style>
<div id="pickles-exception">
<strong style="font-size:1.5em">Uncaught Exception</strong><br /><br />
<table style="border-collapse:separate;border-spacing:1px;border-radius:10px;text-shadow:1px 1px 1px #000;text-align:center">
<tr><td style="background-color:#480000;padding:10px">
<div style="font-size:1.5em;font-style:italic"><?php echo $exception->getMessage(); ?></div>
</td></tr>
<tr><td style="background-color:#552200;padding:10px">
<div style="font-size:1.2em"><?php echo $exception->getFile(); ?> on line <?php echo $exception->getLine(); ?></div>
</td></tr>
</table>
<table>
<tr>
<th style="text-align:left" colspan="2">Trace</th>
<th style="text-align:left">File</th>
<th style="text-align:right">Line</th>
</tr>
<?php
$trace = $exception->getTrace();
rsort($trace);
foreach ($trace as $key => $data)
{
$method = '';
if (isset($data['class']))
{
$method .= $data['class'] . $data['type'];
}
$method .= $data['function'] . '()';
?>
<tr>
<td style="font-weight:bold;color:#999"><?php echo $key + 1; ?>.</td>
<td><?php echo $method; ?></td>
<td><?php echo isset($data['file']) ? $data['file'] : __FILE__; ?></td>
<td style="text-align:right"><?php echo isset($data['line']) ? $data['line'] : '0'; ?></td>
</tr>
<?php
}
?>
</table>
</div>
<br /><br />
<?php
}
}
// }}} // }}}
?> ?>

View file

@ -5,20 +5,11 @@ ob_start();
require_once '.composer/autoload.php'; require_once '.composer/autoload.php';
$root = org\bovigo\vfs\vfsStream::setup('site'); $root = org\bovigo\vfs\vfsStream::setup('site');
define('SITE_PATH', org\bovigo\vfs\vfsStream::url('site/'));
require_once 'classes/Convert.php'; if (!defined('SITE_PATH'))
require_once 'classes/Date.php'; {
require_once 'classes/Time.php'; define('SITE_PATH', org\bovigo\vfs\vfsStream::url('site/'));
require_once 'classes/String.php'; }
require_once 'classes/Object.php';
require_once 'classes/Config.php';
require_once 'classes/Display.php';
require_once 'classes/File.php';
require_once 'classes/API/Common.php';
require_once 'classes/API/Gravatar.php';
require_once 'pickles.php'; require_once 'pickles.php';

View file

@ -0,0 +1,176 @@
<?php
class ControllerTest extends PHPUnit_Framework_TestCase
{
private $config;
public function setUp()
{
$this->config = Config::getInstance();
$this->config->data['pickles']['disabled'] = false;
$this->config->data['pickles']['profiler'] = false;
$_SERVER['REQUEST_URI'] = '';
if (!file_exists(SITE_MODULE_PATH))
{
mkdir(SITE_MODULE_PATH, 0644);
}
unlink(SITE_MODULE_PATH . 'testing.php');
$_SERVER['HTTP_HOST'] = 'testsite.com';
$_SERVER['REQUEST_URI'] = '/home';
$_REQUEST['request'] = 'home';
$module = '<?php class home extends Module { } ?>';
file_put_contents(SITE_MODULE_PATH . 'home.php', $module);
}
public function testSiteDown()
{
$_SERVER['SERVER_NAME'] = 'Test Server';
$this->config->data['pickles']['disabled'] = true;
$this->expectOutputRegex('/Test Server is currently down for maintenance/');
new Controller();
}
/*
public function testCustomSiteDown()
{
$this->fail();
}
public function testAttributesInURI()
{
/testing/id:123/foo:bar
$this->fail();
}
*/
public function testUpperCaseURI()
{
$_SERVER['REQUEST_URI'] = '/TESTING';
$_REQUEST['request'] = 'TESTING';
new Controller();
$this->assertTrue(in_array('Location: /testing', xdebug_get_headers()));
}
public function testForceSecure()
{
$_SERVER['REQUEST_URI'] = '/secure';
$_REQUEST['request'] = 'secure';
$module = '
<?php
class secure extends Module
{
public $secure = true;
}
?>
';
file_put_contents(SITE_MODULE_PATH . 'secure.php', $module);
new Controller();
$this->assertTrue(in_array('Location: https://testsite.com/secure', xdebug_get_headers()));
}
public function testForceInsecure()
{
$_SERVER['HTTPS'] = 'on';
$_SERVER['REQUEST_URI'] = '/insecure';
$_REQUEST['request'] = 'insecure';
$module = '
<?php
class insecure extends Module
{
public $secure = false;
}
?>
';
file_put_contents(SITE_MODULE_PATH . 'insecure.php', $module);
new Controller();
$this->assertTrue(in_array('Location: http://testsite.com/insecure', xdebug_get_headers()));
}
/*
public function testNotAuthenticated()
{
$this->fail();
}
public function testNotAuthenticatedPOST()
{
$this->fail();
}
public function testAuthenticated()
{
$this->fail();
}
public function testHasLevelAccess()
{
$this->fail();
}
public function testIsLevelAccess()
{
$this->fail();
}
public function testRoleDefaultMethod()
{
$this->fail();
}
public function testBadRequestMethod()
{
$this->fail();
}
// @todo Reuse one of the Module tests?
public function testValidationErrors()
{
$this->fail();
}
public function testError404()
{
$this->fail();
}
public function testCustomError404()
{
$this->fail();
}
// @todo Reuse one of the Display tests?
public function testOutput()
{
$this->fail();
}
*/
public function testProfilerOutput()
{
$this->config->data['pickles']['profiler'] = true;
$this->expectOutputRegex('/id="pickles-profiler"/');
new Controller();
}
}
?>

View file

@ -3,8 +3,8 @@
class ConvertTest extends PHPUnit_Framework_TestCase class ConvertTest extends PHPUnit_Framework_TestCase
{ {
/** /**
* @dataProvider providerArrayToXML * @dataProvider providerArrayToXML
*/ */
public function testArrayToXML($a, $b, $c) public function testArrayToXML($a, $b, $c)
{ {
$this->assertEquals(Convert::arrayToXML($a, $b), $c); $this->assertEquals(Convert::arrayToXML($a, $b), $c);