Profiler::log($object, 'methodName');
+ */
+class Profiler
+{
+ /**
+ * Logs
+ *
+ * Array of logged events
+ *
+ * @static
+ * @access private
+ * @var array
+ */
+ private static $logs = [];
+
+ /**
+ * Timers
+ *
+ * Array of active timers
+ *
+ * @static
+ * @access private
+ * @var array
+ */
+ private static $timers = [];
+
+ /**
+ * Log
+ *
+ * Logs the event to be displayed later on. Due to the nature of how much
+ * of a pain it is to determine which class method called this method I
+ * opted to make the method a passable argument for ease of use. Perhaps
+ * I'll revisit in the future. Handles all elapsed time calculations and
+ * memory usage.
+ *
+ * @static
+ * @param mixed $data data to log
+ * @param string $method name of the class method being logged
+ */
+ public static function log($data, $method = false, $type = false)
+ {
+ $time = microtime(true);
+ $data_type = ($data == 'timer' ? $data : gettype($data));
+
+ // Tidys the data by type
+ switch ($data_type)
+ {
+ case 'object':
+ $details['class'] = get_class($data);
+
+ if ($method != '')
+ {
+ $details['method'] = $method . '()';
+ }
+
+ $data_type = $data_type;
+ break;
+
+ case 'timer':
+ $details = $method;
+ $data_type = $data_type;
+ break;
+
+ default:
+ if ($type != false)
+ {
+ $data_type = $type;
+ }
+
+ $details = $data;
+ break;
+ }
+
+ self::$logs[] = [
+ 'type' => $data_type,
+ 'timestamp' => $time,
+ 'elapsed_time' => $time - $_SERVER['REQUEST_TIME_FLOAT'],
+ 'memory_usage' => memory_get_usage(),
+ 'details' => $details,
+ ];
+ }
+
+ /**
+ * Query
+ *
+ * Serves as a wrapper to get query data to the log function
+ *
+ * @static
+ * @param string $query the query being executed
+ * @param array $input_parameters optional prepared statement data
+ * @param array $results optional results of the query
+ * @param float $duration the speed of the query
+ * @param array $explain EXPLAIN data for the query
+ */
+ public static function query($query, $input_parameters = false, $results = false, $duration = false, $explain = false)
+ {
+ $log = [
+ 'query' => $query,
+ 'parameters' => $input_parameters,
+ 'results' => $results,
+ 'execution_time' => $duration,
+ ];
+
+ if ($explain)
+ {
+ $log['explain'] = $explain;
+ }
+
+ self::log($log, false, 'database');
+ }
+
+ /**
+ * Timer
+ *
+ * Logs the start and end of a timer.
+ *
+ * @param string $timer name of the timer
+ * @return boolean whether or not timer profiling is enabled
+ */
+ public static function timer($timer)
+ {
+ // Starts the timer
+ if (!isset(self::$timers[$timer]))
+ {
+ self::$timers[$timer] = microtime(true);
+
+ self::Log('timer', [
+ 'action' => 'start',
+ 'name' => $timer
+ ]);
+ }
+ // Ends the timer
+ else
+ {
+ self::Log('timer', [
+ 'action' => 'stop',
+ 'name' => $timer,
+ 'elapsed_time' => (microtime(true) - self::$timers[$timer])
+ ]);
+
+ unset(self::$timers[$timer]);
+ }
+ }
+
+ /**
+ * Report
+ *
+ * Generates the Profiler report that is displayed by the Controller.
+ * Contains all the HTML needed to display the data properly inline on the
+ * page. Will generally be displayed after the closing HTML tag.
+ */
+ public static function report()
+ {
+ $report = [
+ 'request_time' => $_SERVER['REQUEST_TIME_FLOAT'],
+ 'execution_time' => self::$logs[count(self::$logs) - 1]['timestamp']
+ - $_SERVER['REQUEST_TIME_FLOAT'],
+ 'peak_memory_usage' => memory_get_peak_usage(),
+ 'max_execution_time' => ini_get('max_execution_time'),
+ 'memory_limit' => ini_get('memory_limit'),
+ 'included_files' => count(get_included_files()),
+ 'logs' => self::$logs,
+ ];
+
+ self::$logs = [];
+ self::$timers = [];
+
+ return $report;
+ }
+}
+
diff --git a/src/Resource.php b/src/Resource.php
new file mode 100644
index 0000000..fadd62f
--- /dev/null
+++ b/src/Resource.php
@@ -0,0 +1,387 @@
+uids = $uids;
+ $method = $_SERVER['REQUEST_METHOD'];
+
+ try
+ {
+ // Checks if auth flag is explicity true or true for the method
+ if ($this->auth === true
+ || (isset($this->auth[$method]) && $this->auth[$method]))
+ {
+ if (isset($this->config['oauth'][$_SERVER['__version']]))
+ {
+ $server = new ResourceServer(
+ new SessionStorage,
+ new AccessTokenStorage,
+ new ClientStorage,
+ new ScopeStorage
+ );
+
+ $server->isValidRequest();
+ }
+ else
+ {
+ throw new \Exception('Authentication is not configured properly.', 401);
+ }
+ }
+
+ // Hacks together some new globals
+ if (in_array($method, ['PUT', 'DELETE']))
+ {
+ $GLOBALS['_' . $method] = [];
+
+ // @todo Populate it
+ }
+
+ $filter = isset($this->filter[$method]);
+ $validate = isset($this->validate[$method]);
+
+ if ($filter || $validate)
+ {
+ $global =& $GLOBALS['_' . $method];
+
+ // Checks that the required parameters are present
+ // @todo Add in support for uid:* variables
+ if ($validate)
+ {
+ $variables = [];
+
+ foreach ($this->validate[$method] as $variable => $rules)
+ {
+ if (!is_array($rules))
+ {
+ $variable = $rules;
+ }
+
+ $variables[] = $variable;
+ }
+
+ $missing_variables = array_diff($variables, array_keys($global));
+
+ if ($missing_variables !== array())
+ {
+ foreach ($missing_variables as $variable)
+ {
+ $this->errors[$variable][] = 'The ' . $variable . ' parameter is required.';
+ }
+ }
+ }
+
+ foreach ($global as $variable => $value)
+ {
+ // Applies any filters
+ if ($filter && isset($this->filter[$method][$variable]))
+ {
+ $function = $this->filter[$method][$variable];
+
+ if ($function == 'password_hash')
+ {
+ $global[$variable] = password_hash($value, PASSWORD_DEFAULT);
+ }
+ else
+ {
+ $global[$variable] = $function($value);
+ }
+ }
+
+ if ($validate && isset($this->validate[$method][$variable]))
+ {
+ $rules = $this->validate[$method][$variable];
+
+ if (is_array($rules))
+ {
+ if (isset($global[$variable]) && !String::isEmpty($global[$variable]))
+ {
+ if (is_array($rules))
+ {
+ foreach ($rules as $rule => $message)
+ {
+ $rule = explode(':', $rule);
+
+ for ($i = 1; $i <= 2; $i++)
+ {
+ if (!isset($rule[$i]))
+ {
+ $rule[$i] = false;
+ }
+ }
+
+ switch ($rule[0])
+ {
+ // {{{ Checks using filter_var()
+
+ case 'filter':
+ switch ($rule[1])
+ {
+ case 'boolean':
+ case 'email':
+ case 'float':
+ case 'int':
+ case 'ip':
+ case 'url':
+ $filter = constant('FILTER_VALIDATE_' . strtoupper($rule[1]));
+
+ if (!filter_var($value, $filter))
+ {
+ $this->errors[$variable][] = $message;
+ }
+ break;
+
+ default:
+ $this->errors[$variable] = 'Invalid filter, expecting boolean, email, float, int, ip or url.';
+ break;
+ }
+
+ break;
+
+ // }}}
+ // {{{ Checks using strlen()
+
+ case 'length':
+ $length = strlen($value);
+
+ switch ($rule[1])
+ {
+ case '<':
+ $valid = $length < $rule[2];
+ break;
+
+ case '<=':
+ $valid = $length <= $rule[2];
+ break;
+
+ case '==':
+ $valid = $length == $rule[2];
+ break;
+
+ case '!=':
+ $valid = $length != $rule[2];
+ break;
+
+ case '>=':
+ $valid = $length >= $rule[2];
+ break;
+
+ case '>':
+ $valid = $length > $rule[2];
+ break;
+
+ default:
+ $valid = false;
+ $message = 'Invalid operator, expecting <, <=, ==, !=, >= or >.';
+ break;
+ }
+
+ if (!$valid)
+ {
+ $this->errors[$variable][] = $message;
+ }
+
+ break;
+
+ // }}}
+ // {{{ Checks using preg_match()
+
+ case 'regex':
+ if (preg_match($rule[1], $value))
+ {
+ $this->errors[$variable][] = $message;
+ }
+ break;
+
+ // }}}
+ // @todo case 'alpha':
+ // @todo case 'alphanumeric':
+ // @todo case 'date':
+ // @todo case 'range':
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // if PUT or DELETE, need to update the super globals directly as
+ // they do not stay in sync. Probably need to make them global in
+ // this class method
+ //
+ // $_PUT = $GLOBALS['_PUT'];
+ }
+
+ if ($this->errors)
+ {
+ throw new \Exception('Missing or invalid parameters.', 400);
+ }
+
+ parent::__construct();
+
+ // Checks if the request method has been implemented
+ if (get_class($this) != 'Pickles\\Resource')
+ {
+ if (!method_exists($this, $method))
+ {
+ throw new \Exception('Method not allowed.', 405);
+ }
+ else
+ {
+ // Starts a timer before the resource is executed
+ if ($this->config['profiler'])
+ {
+ $timer = get_class($this) . '->' . $method . '()';
+ Profiler::timer($timer);
+ }
+
+ $this->response = $this->$method();
+
+ // Stops the resource timer
+ if ($this->config['profiler'])
+ {
+ Profiler::timer($timer);
+ }
+ }
+ }
+ }
+ catch (\Exception $e)
+ {
+ $code = $e->getCode();
+
+ // Anything below 200 is probably a PHP error
+ if ($code < 200)
+ {
+ $code = 500;
+ }
+
+ $this->status = $code;
+ $this->message = $e->getMessage();
+ }
+ }
+
+ public function respond()
+ {
+ http_response_code($this->status);
+ header('Content-Type: application/json');
+ header('X-Powered-By: Pickles (http://picklesphp.com)');
+
+ $meta = [
+ 'status' => $this->status,
+ 'message' => $this->message,
+ ];
+
+ // Forces errors to be an array of arrays
+ if ($this->errors)
+ {
+ foreach ($this->errors as $key => $error)
+ {
+ if (!is_array($error))
+ {
+ $this->errors[$key] = [$error];
+ }
+ }
+ }
+
+ foreach (['echo', 'limit', 'offset', 'errors'] as $variable)
+ {
+ if ($this->$variable)
+ {
+ $meta[$variable] = $this->$variable;
+ }
+ }
+
+ $response = ['meta' => $meta];
+
+ foreach (['response', 'profiler'] as $variable)
+ {
+ if ($this->$variable)
+ {
+ $response[$variable] = $this->$variable;
+ }
+ }
+
+ if ($this->config['profiler'])
+ {
+ $response['profiler'] = Profiler::report();
+ }
+
+ $pretty = isset($_REQUEST['pretty']) ? JSON_PRETTY_PRINT : false;
+
+ echo json_encode($response, $pretty);
+ }
+}
+
diff --git a/src/Router.php b/src/Router.php
new file mode 100644
index 0000000..2089c90
--- /dev/null
+++ b/src/Router.php
@@ -0,0 +1,113 @@
+new Pickles\Router;
+ */
+class Router extends Object
+{
+ /**
+ * Constructor
+ *
+ * To save a few keystrokes, the Controller is executed as part of the
+ * constructor instead of via a method. You either want the Controller or
+ * you don't.
+ */
+ public function __construct()
+ {
+ parent::__construct();
+
+ try
+ {
+ // Secure by default
+ if (!isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] == false)
+ {
+ throw new \Exception('HTTPS is required.', 400);
+ }
+
+ // Grabs the requested page
+ $request = $_REQUEST['request'];
+ $components = explode('/', $request);
+ $nouns = [];
+ $uids = [];
+ $version = array_shift($components);
+ $_SERVER['__version'] = substr($version, 1);
+
+ // Checks if we're trying to rock some OAuth
+ if ($components[0] == 'oauth')
+ {
+ $class = 'Pickles\OAuth2\Resource';
+ }
+ else
+ {
+ // Loops through the components to determine nouns and IDs
+ foreach ($components as $index => $component)
+ {
+ if ($index % 2)
+ {
+ $uids[end($nouns)] = $component;
+ }
+ else
+ {
+ $nouns[] = $component;
+ }
+ }
+
+ // Creates our class name
+ array_unshift($nouns, '', 'Pickles', 'App', 'Resources', $version);
+ $class = implode('\\', $nouns);
+ }
+
+ // Checks that the file is present and contains our class
+ if (!class_exists($class))
+ {
+ throw new \Exception('Not Found.', 404);
+ }
+
+ // Instantiates our resource with the UIDs
+ $resource = new $class($uids);
+ }
+ catch (\Exception $e)
+ {
+ // Creates a resource object if we don't have one
+ if (!isset($resource))
+ {
+ $resource = new Resource;
+ }
+
+ $code = $e->getCode();
+
+ // Anything below 200 is probably a PHP error
+ if ($code < 200)
+ {
+ $code = 500;
+ }
+
+ $resource->status = $code;
+ $resource->message = $e->getMessage();
+ }
+
+ $resource->respond();
+ }
+}
+
diff --git a/src/classes/String.php b/src/String.php
similarity index 98%
rename from src/classes/String.php
rename to src/String.php
index f51ac3c..3b8dc8d 100644
--- a/src/classes/String.php
+++ b/src/String.php
@@ -3,18 +3,17 @@
/**
* String Utility Collection
*
- * PHP version 5
- *
* Licensed under The MIT License
* Redistribution of these files must retain the above copyright notice.
*
- * @author Josh Sherman $config = new Config($filename);
- */
-class Config extends Object
-{
- /**
- * Config data
- *
- * @var array
- */
- public $data = [];
-
- /**
- * Constructor
- *
- * Calls the parent constructor and loads the passed file.
- */
- public function __construct()
- {
- parent::__construct();
-
- $filename = SITE_PATH . 'config.php';
- $environments = false;
- $environment = false;
- $is_cli = !isset($_SERVER['REQUEST_METHOD']);
-
-
- // Sanity checks the config file
- if (file_exists($filename) && is_file($filename) && is_readable($filename))
- {
- require $filename;
- }
-
- // Checks that we have the config array
- if (isset($config))
- {
- // Determines the environment
- if (isset($config['environment']))
- {
- $environment = $config['environment'];
- }
- else
- {
- if (isset($config['environments']) && is_array($config['environments']))
- {
- $environments = $config['environments'];
-
- // If we're on the CLI, check an environment was even passed in
- // @todo is checking for argc enough?
- if ($is_cli && $_SERVER['argc'] < 2)
- {
- throw new Exception('You must pass an environment (e.g. php script.php new Controller();
- */
-class Controller extends Object
-{
- /**
- * Constructor
- *
- * To save a few keystrokes, the Controller is executed as part of the
- * constructor instead of via a method. You either want the Controller or
- * you don't.
- */
- public function __construct()
- {
- parent::__construct();
-
- // Generate a generic "site down" message if the site is set to be disabled
- try
- {
- // @todo Clean this up to be just a single sanity check
- if (isset($this->config->pickles['disabled']) && $this->config->pickles['disabled'])
- {
- $custom_template = SITE_TEMPLATE_PATH . '__shared/maintenance.phtml';
-
- if (file_exists($custom_template))
- {
- require_once $custom_template;
- }
- else
- {
- echo '
- - ' . $_SERVER['SERVER_NAME'] . ' is currently down for maintenance. - Please check back in a few minutes. -
-Additionally, a custom maintenance template was not found.
-The requested URL /' . $request . ' was not found on this server.
-Additionally, a custom error template was not found.
-Profiler::log('some action you want to track');
- * @usage Profiler::log($object, 'methodName');
- */
-class Profiler
-{
- /**
- * Profile
- *
- * Array of logged events
- *
- * @static
- * @access private
- * @var array
- */
- private static $profile = [];
-
- /**
- * Queries
- *
- * Number of queries that have been logged
- *
- * @static
- * @access private
- * @var integer
- */
- private static $queries = 0;
-
- /**
- * Timers
- *
- * Array of active timers
- *
- * @static
- * @access private
- * @var array
- */
- private static $timers = [];
-
- /**
- * Enabled
- *
- * Checks if the profiler is set to boolean true or if the passed type is
- * specified in the profiler configuration value.
- *
- * @param array $type type(s) to check
- * @return boolean whether or not the type is enabled
- */
- public static function enabled(/* polymorphic */)
- {
- $config = Config::getInstance();
- $config = isset($config->pickles['profiler']) ? $config->pickles['profiler'] : false;
-
- // Checks if we're set to boolean true
- if ($config === true)
- {
- return true;
- }
- else
- {
- $types = func_get_args();
-
- foreach ($types as $type)
- {
- if (stripos($config, $type) !== false)
- {
- return true;
- }
- }
- }
-
- return false;
- }
-
- /**
- * Log
- *
- * Logs the event to be displayed later on. Due to the nature of how much
- * of a pain it is to determine which class method called this method I
- * opted to make the method a passable argument for ease of use. Perhaps
- * I'll revisit in the future. Handles all elapsed time calculations and
- * memory usage.
- *
- * @static
- * @param mixed $data data to log
- * @param string $method name of the class method being logged
- */
- public static function log($data, $method = false, $type = false)
- {
- $time = microtime(true);
- $data_type = ($data == 'timer' ? $data : gettype($data));
-
- // Tidys the data by type
- switch ($data_type)
- {
- case 'array':
- $log = '' . print_r($data, true) . ''; - break; - - case 'object': - $log = '[' . get_parent_class($data) . '] ' - . '' . get_class($data) . '' - . ($method != '' ? '->' . $method . '()' : ''); - - $data_type = '' . $data_type . ''; - break; - - case 'timer': - $log = $method; - - $data_type = '' . $data_type . ''; - break; - - case 'string': - default: - if ($type != false) - { - $data_type = $type; - } - - $log = $data; - break; - } - - self::$profile[] = [ - 'log' => $log, - 'type' => $data_type, - 'time' => $time, - 'elapsed' => $time - $_SERVER['REQUEST_TIME_FLOAT'], - 'memory' => memory_get_usage(), - ]; - } - - /** - * Log Query - * - * Serves as a wrapper to get query data to the log function - * - * @static - * @param string $query the query being executed - * @param array $input_parameters optional prepared statement data - * @param array $explain EXPLAIN data for the query - * @param float $duration the speed of the query - */ - public static function logQuery($query, $input_parameters = false, $explain = false, $duration = false) - { - self::$queries++; - - $log = ''; - - if ($input_parameters != 'false' && is_array($input_parameters)) - { - $log .= '
- Console
- = $logs; ?>
- |
-
- Load Time
- = number_format($duration * 100, 3) . ' ms / ' . ini_get('max_execution_time'); ?>
- |
-
- Memory Usage
- = $peak_usage . ' / ' . ini_get('memory_limit'); ?>
- |
-
- Database
- = $queries; ?>
- |
-
- Includes
- = $files; ?>
- |
-
Console | -Memory | -Time | -|
---|---|---|---|
= $entry['type']; ?> | -= $entry['log']; ?> | -= self::formatSize($entry['memory']); ?> | -= number_format($entry['elapsed'] * 100, 3); ?> ms | -
Security::login(10);
- * @usage Security::isLevel(SECURITY_LEVEL_ADMIN);
- */
-class Security
-{
- /**
- * Lookup Cache
- *
- * Used to minimize database lookups
- *
- * @static
- * @access private
- * @var array
- */
- private static $cache = [];
-
- /**
- * Generate Hash
- *
- * Generates an SHA1 hash from the provided string. Salt optional.
- *
- * @param string $source value to hash
- * @param mixed $salts optional salt or salts
- * @return string SHA1 hash
- * @todo Transition away from this
- */
- public static function generateHash($source, $salts = null)
- {
- // Determines which salt(s) to use
- if ($salts == null)
- {
- $config = Config::getInstance();
-
- if (isset($config->security['salt']) && $config->security['salt'] != null)
- {
- $salts = $config->security['salt'];
- }
- else
- {
- $salts = ['P1ck73', 'Ju1C3'];
- }
- }
-
- // Forces the variable to be an array
- if (!is_array($salts))
- {
- $salts = [$salts];
- }
-
- // Loops through the salts, applies them and calculates the hash
- $hash = $source;
-
- foreach ($salts as $salt)
- {
- $hash = sha1($salt . $hash);
- }
-
- return $hash;
- }
-
- /**
- * Generate SHA-256 Hash
- *
- * Generates an SHA-256 hash from the provided string and salt. Borrowed the
- * large iteration logic from fCryptography::hashWithSalt() as, and I quote,
- * "makes rainbow table attacks infesible".
- *
- * @param string $source value to hash
- * @param mixed $salt value to use as salt
- * @return string SHA-256 hash
- * @link https://github.com/flourishlib/flourish-classes/blob/master/fCryptography.php
- */
- public static function generateSHA256Hash($source, $salt)
- {
- $sha256 = sha1($salt . $source);
-
- for ($i = 0; $i < 1000; $i++)
- {
- $sha256 = hash('sha256', $sha256 . (($i % 2 == 0) ? $source : $salt));
- }
-
- return $sha256;
- }
-
- /**
- * Check Session
- *
- * Checks if sessions are enabled.
- *
- * @static
- * @access private
- * @return boolean whether or not sessions are enabled
- */
- private static function checkSession()
- {
- if (session_id() == '')
- {
- return false;
- }
- else
- {
- return true;
- }
- }
-
- /**
- * Check Level
- *
- * Checks if a passed level is an integer and/or properly defined in the
- * site's configuration file.
- *
- * @static
- * @access private
- * @param mixed access level to validate
- * @return whether ot not the access level is valid
- */
- private static function checkLevel(&$access_level)
- {
- return is_int($access_level);
- }
-
- /**
- * Login
- *
- * Creates a session variable containing the user ID and generated token.
- * The token is also assigned to a cookie to be used when validating the
- * security level. When the level value is present, the class will by pass
- * the database look up and simply use that value when validating (the less
- * paranoid scenario).
- *
- * @static
- * @param integer $user_id ID of the user that's been logged in
- * @param integer $level optional level for the user being logged in
- * @param string $role textual representation of the user's level
- * @return boolean whether or not the login could be completed
- */
- public static function login($user_id, $level = null, $role = null)
- {
- if (self::checkSession())
- {
- $token = sha1(microtime());
-
- $_SESSION['__pickles']['security'] = [
- 'token' => $token,
- 'user_id' => (int)$user_id,
- 'level' => $level,
- 'role' => $role,
- ];
-
- setcookie('pickles_security_token', $token);
-
- return true;
- }
- else
- {
- return false;
- }
- }
-
- /**
- * Logout
- *
- * Clears out the security information in the session and the cookie.
- *
- * @static
- * @return boolean true
- */
- public static function logout()
- {
- if (isset($_SESSION['__pickles']['security']))
- {
- $_SESSION['__pickles']['security'] = null;
- unset($_SESSION['__pickles']['security']);
-
- setcookie('pickles_security_token', '', time() - 3600);
- }
-
- return true;
- }
-
- /**
- * Get User Level
- *
- * Looks up the user level in the database and caches it. Cache is used
- * for any subsequent look ups for the user. Also validates the session
- * variable against the cookie to ensure everything is legit. If the user
- * level is set in the session, that value will take precedence.
- *
- * return integer user level or false
- */
- private static function getUserLevel()
- {
- if (self::checkSession() == true && isset($_SESSION['__pickles']['security']['user_id']))
- {
- // Checks the session against the cookie
- if (isset($_SESSION['__pickles']['security']['token'], $_COOKIE['pickles_security_token'])
- && $_SESSION['__pickles']['security']['token'] != $_COOKIE['pickles_security_token'])
- {
- Security::logout();
- }
- elseif (isset($_SESSION['__pickles']['security']['level']) && $_SESSION['__pickles']['security']['level'] != null)
- {
- return $_SESSION['__pickles']['security']['level'];
- }
- // Used to hit the database to determine the user's level, found it
- // to be overkill and just opted for a simple logout.
- else
- {
- Security::logout();
- }
- }
-
- return false;
- }
-
- /**
- * Is Level
- *
- * Checks the user's access level is exactly the passed level
- *
- * @static
- * @param integer $access_level access level to be checked against
- * @return boolean whether or not the user is that level
- */
- public static function isLevel()
- {
- $is_level = false;
-
- if (self::checkSession())
- {
- $arguments = func_get_args();
- if (is_array($arguments[0]))
- {
- $arguments = $arguments[0];
- }
-
- foreach ($arguments as $access_level)
- {
- if (self::checkLevel($access_level))
- {
- if (self::getUserLevel() == $access_level)
- {
- $is_level = true;
- }
- }
- }
- }
-
- return $is_level;
- }
-
- /**
- * Has Level
- *
- * Checks the user's access level against the passed level.
- *
- * @static
- * @param integer $access_level access level to be checked against
- * @return boolean whether or not the user has access
- */
- public static function hasLevel()
- {
- $has_level = false;
-
- if (self::checkSession())
- {
- $arguments = func_get_args();
-
- if (is_array($arguments[0]))
- {
- $arguments = $arguments[0];
- }
-
- foreach ($arguments as $access_level)
- {
- if (self::checkLevel($access_level))
- {
- if (self::getUserLevel() >= $access_level)
- {
- $has_level = true;
- }
- }
- }
- }
-
- return $has_level;
- }
-
- /**
- * Between Level
- *
- * Checks the user's access level against the passed range.
- *
- * @static
- * @param integer $low access level to be checked against
- * @param integer $high access level to be checked against
- * @return boolean whether or not the user has access
- */
- public static function betweenLevel($low, $high)
- {
- $between_level = false;
-
- if (self::checkSession())
- {
- if (self::checkLevel($low) && self::checkLevel($high))
- {
- $user_level = self::getUserLevel();
-
- if ($user_level >= $low && $user_level <= $high)
- {
- $between_level = true;
- }
- }
- }
-
- return $between_level;
- }
-}
-
diff --git a/src/classes/Session.php b/src/classes/Session.php
deleted file mode 100644
index 62b6869..0000000
--- a/src/classes/Session.php
+++ /dev/null
@@ -1,125 +0,0 @@
-
- * @copyright Copyright 2007-2014, Josh Sherman
- * @license http://www.opensource.org/licenses/mit-license.html
- * @package PICKLES
- * @link https://github.com/joshtronic/pickles
- */
-
-/**
- * Session Class
- *
- * Provides session handling via database instead of the file based session
- * handling built into PHP. Using this class requires an array to be defined
- * in place of the boolean true/false (on/off). If simply an empty array, the
- * datasource will default to the value in $config['pickles']['datasource'] and
- * if the table will default to "sessions". The format is as follows:
- */
-class Session extends Object
-{
- /**
- * Constructor
- *
- * All of our set up logic for the session in contained here. This class is
- * initially instantiated from pickles.php. Non-file handlers need to be
- * configured in the site's config. MySQL support was dropped in favor of
- * in memory stores or simply relying on file based sessions. Why? Because
- * using MySQL for sessions is very write intensive and having done it in
- * the past I don't recommend it. If you run a single server, files are
- * good enough if your volume is lower. Memcache[d] is fine if you don't
- * mind logging all of your users off your site when you restart the
- * service and/or you run out of memory for the process. Redis is the best
- * choice as it can be configured to be persistent and lives in memory.
- * This is assuming you don't just want to roll your own sessions, which is
- * pretty damn easy as well.
- */
- public function __construct()
- {
- if (isset($_SERVER['REQUEST_METHOD']))
- {
- parent::__construct();
-
- // Sets up our configuration variables
- if (isset($this->config->pickles['sessions']))
- {
- $session = $this->config->pickles['sessions'];
- }
-
- $datasources = $this->config->datasources;
- $handler = 'files';
- $datasource = false;
-
- if (isset($session, $datasources[$session]))
- {
- $datasource = $datasources[$session];
- $handler = $datasource['type'];
-
- if ($handler != 'files')
- {
- if (isset($datasource['hostname'], $datasource['port']))
- {
- $host = ($handler != 'memcached' ? 'tcp://' : '')
- . $datasource['hostname'] . ':' . $datasource['port'];
- }
- else
- {
- throw new Exception('You must provide both the hostname and port for the datasource.');
- }
- }
- }
-
- switch ($handler)
- {
- case 'memcache':
- ini_set('session.save_handler', 'memcache');
- ini_set('session.save_path', $host . '?persistent=1&weight=1&timeout=1&retry_interval=15');
- break;
-
- case 'memcached':
- ini_set('session.save_handler', 'memcached');
- ini_set('session.save_path', $host);
- break;
-
- case 'redis':
- $save_path = $host . '?weight=1';
-
- // Database ignored by phpredis when this was coded
- if (isset($datasource['database']))
- {
- $save_path .= '&database=' . $datasource['database'];
- }
-
- if (isset($datasource['prefix']))
- {
- $save_path .= '&prefix=' . $datasource['prefix'];
- }
-
- ini_set('session.save_handler', 'redis');
- ini_set('session.save_path', $save_path);
- break;
-
- case 'files':
- ini_set('session.save_handler', 'files');
- break;
- }
-
- // Don't start sessions for people without a user agent and bots.
- if (isset($_SERVER['HTTP_USER_AGENT'])
- && !String::isEmpty($_SERVER['HTTP_USER_AGENT'])
- && !preg_match('/(Baidu|Gigabot|Googlebot|libwww-perl|lwp-trivial|msnbot|SiteUptime|Slurp|WordPress|ZIBB|ZyBorg)/i', $_SERVER['HTTP_USER_AGENT']))
- {
- session_start();
- }
- }
- }
-}
-
diff --git a/src/classes/Sort.php b/src/classes/Sort.php
deleted file mode 100644
index ff01ec9..0000000
--- a/src/classes/Sort.php
+++ /dev/null
@@ -1,71 +0,0 @@
-
- * @copyright Copyright 2007-2014, Josh Sherman
- * @license http://www.opensource.org/licenses/mit-license.html
- * @package PICKLES
- * @link https://github.com/joshtronic/pickles
- */
-
-/**
- * Sort Class
- *
- * I got tired of writing separate usort functions to sort by different array
- * keys in the array, this class solves that.
- */
-class Sort
-{
- /**
- * Ascending
- *
- * Variable to utilize ascending sort
- *
- * @var integer
- */
- const ASC = 'ASC';
-
- /**
- * Descending
- *
- * Variable to utilize descending sort
- *
- * @var integer
- */
- const DESC = 'DESC';
-
- /**
- * Sort By
- *
- * Sorts an array by the specified column, optionally in either direction.
- *
- * @param string $field field to sort by
- * @param array $array array to sort
- * @param string $direction optional direction to sort
- * @retun boolean true because sorting is done by reference
- */
- public static function by($field, &$array, $direction = Sort::ASC)
- {
- usort($array, create_function('$a, $b', '
- $a = $a["' . $field . '"];
- $b = $b["' . $field . '"];
-
- if ($a == $b)
- {
- return 0;
- }
-
- return ($a ' . ($direction == Sort::DESC ? '>' : '<') .' $b) ? -1 : 1;
- '));
-
- return true;
- }
-}
-
diff --git a/src/classes/Validate.php b/src/classes/Validate.php
deleted file mode 100644
index 2f613a3..0000000
--- a/src/classes/Validate.php
+++ /dev/null
@@ -1,175 +0,0 @@
-
- * @copyright Copyright 2007-2014, Josh Sherman
- * @license http://www.opensource.org/licenses/mit-license.html
- * @package PICKLES
- * @link https://github.com/joshtronic/pickles
- */
-
-/**
- * Validate Class
- *
- * Validation layer that's used by the Modules to validate passed data. Handles
- * single sanity checks against a variable so the validation itself can be used
- * in other places in the system
- */
-class Validate
-{
- /**
- * Is Valid?
- *
- * Checks if a variable is valid based on the passed rules.
- *
- * @param mixed $value the value to be validated
- * @param array $rules an array of rules (and messages) to validate with
- * @return mixed boolean true if valid, array of errors if invalid
- */
- public static function isValid($value, $rules)
- {
- $errors = [];
-
- if (is_array($rules))
- {
- foreach ($rules as $rule => $message)
- {
- $rule = explode(':', $rule);
-
- switch (strtolower($rule[0]))
- {
- // @todo case 'alpha':
- // @todo case 'alphanumeric':
- // @todo case 'date':
-
- // {{{ Checks using filter_var()
-
- case 'filter':
- if (count($rule) < 2)
- {
- throw new Exception('Invalid validation rule, expected: "validate:boolean|email|float|int|ip|url".');
- }
- else
- {
- switch (strtolower($rule[1]))
- {
- case 'boolean':
- case 'email':
- case 'float':
- case 'int':
- case 'ip':
- case 'url':
- $filter = constant('FILTER_VALIDATE_' . strtoupper($rule[1]));
- break;
-
- default:
- throw new Exception('Invalid filter, expecting boolean, email, float, int, ip or url.');
- break;
- }
-
- if (!filter_var($value, $filter))
- {
- $errors[] = $message;
- }
- }
-
- break;
-
- // }}}
- // {{{ Checks using strlen()
-
- case 'length':
- if (count($rule) < 3)
- {
- throw new Exception('Invalid validation rule, expected: "length:<|<=|==|!=|>=|>:integer".');
- }
- else
- {
- if (!filter_var($rule[2], FILTER_VALIDATE_INT))
- {
- throw new Exception('Invalid length value, expecting an integer.');
- }
- else
- {
- $length = strlen($value);
-
- switch ($rule[1])
- {
- case '<':
- $valid = $length < $rule[2];
- break;
-
- case '<=':
- $valid = $length <= $rule[2];
- break;
-
- case '==':
- $valid = $length == $rule[2];
- break;
-
- case '!=':
- $valid = $length != $rule[2];
- break;
-
- case '>=':
- $valid = $length >= $rule[2];
- break;
-
- case '>':
- $valid = $length > $rule[2];
- break;
-
- default:
- throw new Exception('Invalid operator, expecting <, <=, ==, !=, >= or >.');
- break;
- }
-
- if (!$valid)
- {
- $errors[] = $message;
- }
- }
- }
-
- break;
-
- // }}}
-
- // @todo case 'range':
-
- // {{{ Checks using preg_match()
-
- case 'regex':
- if (count($rule) < 3)
- {
- throw new Exception('Invalid validation rule, expected: "regex:is|not:string".');
- }
- else
- {
- $rule[1] = strtolower($rule[1]);
-
- if (($rule[1] == 'is' && preg_match($rule[2], $value))
- || ($rule[1] == 'not' && !preg_match($rule[2], $value)))
- {
- $errors[] = $message;
- }
- }
- break;
-
- // }}}
- }
-
- }
- }
-
- return count($errors) ? $errors : true;
- }
-}
-
diff --git a/src/pickles.php b/src/pickles.php
deleted file mode 100644
index accdec6..0000000
--- a/src/pickles.php
+++ /dev/null
@@ -1,162 +0,0 @@
-
- * @copyright Copyright 2007-2014, Josh Sherman
- * @license http://www.opensource.org/licenses/mit-license.html
- * @package PICKLES
- * @link https://github.com/joshtronic/pickles
- * @usage require_once 'pickles.php';
- */
-
-// {{{ PICKLES Constants
-
-// @todo Finish reworking constants to be part of the Config object
-if (!defined('SITE_PATH'))
-{
- // Establishes our site paths, sanity check is to allow vfsStream in our tests
- define('SITE_PATH', getcwd() . '/../');
-}
-
-if (!defined('SITE_CLASS_PATH'))
-{
- define('SITE_CLASS_PATH', SITE_PATH . 'classes/');
- 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('LOG_PATH', PRIVATE_PATH . 'logs/');
-}
-
-// }}}
-// {{{ Defaults some important configuration options
-
-// Turns on error before the config is loaded to help catch parse errors
-ini_set('display_errors', true);
-error_reporting(-1);
-
-// Defaults timezone to UTC if not set
-if (ini_get('date.timezone') == '')
-{
- ini_set('date.timezone', 'Etc/UTC');
-}
-
-// Sets the session variables
-ini_set('session.cache_expire', 86400);
-ini_set('session.entropy_file', '/dev/urandom');
-ini_set('session.entropy_length', 512);
-ini_set('session.gc_maxlifetime', 86400);
-ini_set('session.gc_probability', 1);
-ini_set('session.gc_divisor', 1000);
-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/',
- ];
-
- // 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 base config
-$config = Config::getInstance();
-
-// Injects PICKLES variables into the config
-$config->data['pickles']['path'] = dirname(__FILE__) . '/';
-
-// Configures any available PHP configuration options
-if (is_array($config->php) && count($config->php))
-{
- foreach ($config->php as $variable => $value)
- {
- ini_set($variable, $value);
- }
-}
-
-// Starts session handling (old)
-if (isset($config->pickles['session']))
-{
- if (session_id() == '' && $config->pickles['session'] !== false)
- {
- new Session();
- }
-}
-
-// Starts session handling (new)
-if (isset($config->pickles['sessions']))
-{
- if (session_id() == '' && $config->pickles['sessions'] !== false)
- {
- new Session();
- }
-}
-
-// }}}
-// {{{ Defaults some internals for ease of use
-
-if (!isset($_REQUEST['request']))
-{
- $_REQUEST['request'] = 'home';
-}
-
-// }}}
-
diff --git a/tests/Pickles/ConfigTest.php b/tests/Pickles/ConfigTest.php
new file mode 100644
index 0000000..d7b6607
--- /dev/null
+++ b/tests/Pickles/ConfigTest.php
@@ -0,0 +1,174 @@
+)
+ */
+ public function testMissingCLIEnvironment()
+ {
+ $_SERVER['argc'] = 1;
+
+ file_put_contents('/tmp/pickles.php', ' [
+ "local" => "127.0.0.1",
+ "production" => "123.456.789.0",
+ ],
+ ];
+ ');
+
+ new Pickles\Config('/tmp/pickles.php');
+ }
+
+ /**
+ * @expectedException Exception
+ * @expectedExceptionMessage You must pass an environment (e.g. php script.php