aboutsummaryrefslogtreecommitdiffhomepage
path: root/main/app/sprinkles/core/src/Util
diff options
context:
space:
mode:
authormarvin-borner@live.com2018-04-16 21:09:05 +0200
committermarvin-borner@live.com2018-04-16 21:09:05 +0200
commitcf14306c2b3f82a81f8d56669a71633b4d4b5fce (patch)
tree86700651aa180026e89a66064b0364b1e4346f3f /main/app/sprinkles/core/src/Util
parent619b01b3615458c4ed78bfaeabb6b1a47cc8ad8b (diff)
Main merge to user management system - files are now at /main/public/
Diffstat (limited to 'main/app/sprinkles/core/src/Util')
-rwxr-xr-xmain/app/sprinkles/core/src/Util/BadClassNameException.php18
-rwxr-xr-xmain/app/sprinkles/core/src/Util/Captcha.php159
-rwxr-xr-xmain/app/sprinkles/core/src/Util/CheckEnvironment.php340
-rwxr-xr-xmain/app/sprinkles/core/src/Util/ClassMapper.php94
-rwxr-xr-xmain/app/sprinkles/core/src/Util/EnvironmentInfo.php68
-rwxr-xr-xmain/app/sprinkles/core/src/Util/ShutdownHandler.php167
-rwxr-xr-xmain/app/sprinkles/core/src/Util/Util.php173
7 files changed, 1019 insertions, 0 deletions
diff --git a/main/app/sprinkles/core/src/Util/BadClassNameException.php b/main/app/sprinkles/core/src/Util/BadClassNameException.php
new file mode 100755
index 0000000..09c4ea5
--- /dev/null
+++ b/main/app/sprinkles/core/src/Util/BadClassNameException.php
@@ -0,0 +1,18 @@
+<?php
+/**
+ * UserFrosting (http://www.userfrosting.com)
+ *
+ * @link https://github.com/userfrosting/UserFrosting
+ * @license https://github.com/userfrosting/UserFrosting/blob/master/licenses/UserFrosting.md (MIT License)
+ */
+namespace UserFrosting\Sprinkle\Core\Util;
+
+/**
+ * Bad class name exception. Used when a class name is dynamically invoked, but the class does not exist.
+ *
+ * @author Alex Weissman (https://alexanderweissman.com)
+ */
+class BadClassNameException extends \LogicException
+{
+ //
+}
diff --git a/main/app/sprinkles/core/src/Util/Captcha.php b/main/app/sprinkles/core/src/Util/Captcha.php
new file mode 100755
index 0000000..c788b77
--- /dev/null
+++ b/main/app/sprinkles/core/src/Util/Captcha.php
@@ -0,0 +1,159 @@
+<?php
+/**
+ * UserFrosting (http://www.userfrosting.com)
+ *
+ * @link https://github.com/userfrosting/UserFrosting
+ * @license https://github.com/userfrosting/UserFrosting/blob/master/licenses/UserFrosting.md (MIT License)
+ */
+namespace UserFrosting\Sprinkle\Core\Util;
+
+use UserFrosting\Session\Session;
+
+/**
+ * Captcha Class
+ *
+ * Implements the captcha for user registration.
+ *
+ * @author r3wt
+ * @author Alex Weissman (https://alexanderweissman.com)
+ * @see http://www.userfrosting.com/components/#messages
+ */
+class Captcha
+{
+ /**
+ * @var string The randomly generated captcha code.
+ */
+ protected $code;
+
+ /**
+ * @var string The captcha image, represented as a binary string.
+ */
+ protected $image;
+
+ /**
+ * @var UserFrosting\Session\Session We use the session object so that the hashed captcha token will automatically appear in the session.
+ */
+ protected $session;
+
+ /**
+ * @var string
+ */
+ protected $key;
+
+ /**
+ * Create a new captcha.
+ */
+ public function __construct($session, $key)
+ {
+ $this->session = $session;
+ $this->key = $key;
+
+ if (!$this->session->has($key)) {
+ $this->session[$key] = array();
+ }
+ }
+
+ /**
+ * Generates a new captcha for the user registration form.
+ *
+ * This generates a random 5-character captcha and stores it in the session with an md5 hash.
+ * Also, generates the corresponding captcha image.
+ */
+ public function generateRandomCode()
+ {
+ $md5_hash = md5(rand(0,99999));
+ $this->code = substr($md5_hash, 25, 5);
+ $enc = md5($this->code);
+
+ // Store the generated captcha value to the session
+ $this->session[$this->key] = $enc;
+
+ $this->generateImage();
+ }
+
+ /**
+ * Returns the captcha code.
+ */
+ public function getCaptcha()
+ {
+ return $this->code;
+ }
+
+ /**
+ * Returns the captcha image.
+ */
+ public function getImage()
+ {
+ return $this->image;
+ }
+
+ /**
+ * Check that the specified code, when hashed, matches the code in the session.
+ *
+ * Also, stores the specified code in the session with an md5 hash.
+ * @param string
+ * @return bool
+ */
+ public function verifyCode($code)
+ {
+ return (md5($code) == $this->session[$this->key]);
+ }
+
+ /**
+ * Generate the image for the current captcha.
+ *
+ * This generates an image as a binary string.
+ */
+ protected function generateImage()
+ {
+ $width = 150;
+ $height = 30;
+
+ $image = imagecreatetruecolor(150, 30);
+
+ //color pallette
+ $white = imagecolorallocate($image, 255, 255, 255);
+ $black = imagecolorallocate($image, 0, 0, 0);
+ $red = imagecolorallocate($image,255,0,0);
+ $yellow = imagecolorallocate($image, 255, 255, 0);
+ $dark_grey = imagecolorallocate($image, 64,64,64);
+ $blue = imagecolorallocate($image, 0,0,255);
+
+ //create white rectangle
+ imagefilledrectangle($image,0,0,150,30,$white);
+
+ //add some lines
+ for($i=0;$i<2;$i++) {
+ imageline($image,0,rand()%10,10,rand()%30,$dark_grey);
+ imageline($image,0,rand()%30,150,rand()%30,$red);
+ imageline($image,0,rand()%30,150,rand()%30,$yellow);
+ }
+
+ // RandTab color pallette
+ $randc[0] = imagecolorallocate($image, 0, 0, 0);
+ $randc[1] = imagecolorallocate($image,255,0,0);
+ $randc[2] = imagecolorallocate($image, 255, 255, 0);
+ $randc[3] = imagecolorallocate($image, 64,64,64);
+ $randc[4] = imagecolorallocate($image, 0,0,255);
+
+ //add some dots
+ for($i=0;$i<1000;$i++) {
+ imagesetpixel($image,rand()%200,rand()%50,$randc[rand()%5]);
+ }
+
+ //calculate center of text
+ $x = ( 150 - 0 - imagefontwidth( 5 ) * strlen( $this->code ) ) / 2 + 0 + 5;
+
+ //write string twice
+ imagestring($image,5, $x, 7, $this->code, $black);
+ imagestring($image,5, $x, 7, $this->code, $black);
+ //start ob
+ ob_start();
+ imagepng($image);
+
+ //get binary image data
+ $this->image = ob_get_clean();
+
+ return $this->image;
+ }
+}
diff --git a/main/app/sprinkles/core/src/Util/CheckEnvironment.php b/main/app/sprinkles/core/src/Util/CheckEnvironment.php
new file mode 100755
index 0000000..26925d9
--- /dev/null
+++ b/main/app/sprinkles/core/src/Util/CheckEnvironment.php
@@ -0,0 +1,340 @@
+<?php
+/**
+ * UserFrosting (http://www.userfrosting.com)
+ *
+ * @link https://github.com/userfrosting/UserFrosting
+ * @license https://github.com/userfrosting/UserFrosting/blob/master/licenses/UserFrosting.md (MIT License)
+ */
+namespace UserFrosting\Sprinkle\Core\Util;
+
+use Psr\Http\Message\ResponseInterface;
+use Psr\Http\Message\ServerRequestInterface;
+use Slim\Http\Body;
+
+/**
+ * Performs pre-flight tests on your server environment to check that it meets the requirements.
+ *
+ * @author Alex Weissman (https://alexanderweissman.com)
+ */
+class CheckEnvironment
+{
+ /**
+ * @var \RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator Locator service for stream resources.
+ */
+ protected $locator;
+
+ /**
+ * @var array The results of any failed checks performed.
+ */
+ protected $resultsFailed = [];
+
+ /**
+ * @var array The results of any successful checks performed.
+ */
+ protected $resultsSuccess = [];
+
+ /**
+ * @var \Slim\Views\Twig The view object, needed for rendering error page.
+ */
+ protected $view;
+
+ /**
+ * @var \Illuminate\Cache\CacheManager Cache service for cache access.
+ */
+ protected $cache;
+
+ /**
+ * Constructor.
+ *
+ * @param $view \Slim\Views\Twig The view object, needed for rendering error page.
+ * @param $locator \RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator Locator service for stream resources.
+ */
+ public function __construct($view, $locator, $cache)
+ {
+ $this->view = $view;
+ $this->locator = $locator;
+ $this->cache = $cache;
+ }
+
+ /**
+ * Invoke the CheckEnvironment middleware, performing all pre-flight checks and returning an error page if problems were found.
+ *
+ * @param \Psr\Http\Message\ServerRequestInterface $request PSR7 request
+ * @param \Psr\Http\Message\ResponseInterface $response PSR7 response
+ * @param callable $next Next middleware
+ *
+ * @return \Psr\Http\Message\ResponseInterface
+ */
+ public function __invoke($request, $response, $next)
+ {
+ $problemsFound = false;
+
+ // If production environment and no cached checks, perform environment checks
+ if ($this->isProduction() && $this->cache->get('checkEnvironment') != 'pass') {
+ $problemsFound = $this->checkAll();
+
+ // Cache if checks passed
+ if (!$problemsFound) {
+ $this->cache->forever('checkEnvironment', 'pass');
+ }
+ } elseif (!$this->isProduction()) {
+ $problemsFound = $this->checkAll();
+ }
+
+ if ($problemsFound) {
+ $results = array_merge($this->resultsFailed, $this->resultsSuccess);
+
+ $response = $this->view->render($response, 'pages/error/config-errors.html.twig', [
+ "messages" => $results
+ ]);
+ } else {
+ $response = $next($request, $response);
+ }
+
+ return $response;
+ }
+
+ /**
+ * Run through all pre-flight checks.
+ */
+ public function checkAll()
+ {
+ $problemsFound = false;
+
+ if ($this->checkApache()) $problemsFound = true;
+
+ if ($this->checkPhp()) $problemsFound = true;
+
+ if ($this->checkPdo()) $problemsFound = true;
+
+ if ($this->checkGd()) $problemsFound = true;
+
+ if ($this->checkImageFunctions()) $problemsFound = true;
+
+ if ($this->checkPermissions()) $problemsFound = true;
+
+ return $problemsFound;
+ }
+
+ /**
+ * For Apache environments, check that required Apache modules are installed.
+ */
+ public function checkApache()
+ {
+ $problemsFound = false;
+
+ // Perform some Apache checks. We may also need to do this before any routing takes place.
+ if (strpos(php_sapi_name(), 'apache') !== false) {
+
+ $require_apache_modules = ['mod_rewrite'];
+ $apache_modules = apache_get_modules();
+
+ $apache_status = [];
+
+ foreach ($require_apache_modules as $module) {
+ if (!in_array($module, $apache_modules)) {
+ $problemsFound = true;
+ $this->resultsFailed['apache-' . $module] = [
+ "title" => "<i class='fa fa-server fa-fw'></i> Missing Apache module <b>$module</b>.",
+ "message" => "Please make sure that the <code>$module</code> Apache module is installed and enabled. If you use shared hosting, you will need to ask your web host to do this for you.",
+ "success" => false
+ ];
+ } else {
+ $this->resultsSuccess['apache-' . $module] = [
+ "title" => "<i class='fa fa-server fa-fw'></i> Apache module <b>$module</b> is installed and enabled.",
+ "message" => "Great, we found the <code>$module</code> Apache module!",
+ "success" => true
+ ];
+ }
+ }
+ }
+
+ return $problemsFound;
+ }
+
+ /**
+ * Check for GD library (required for Captcha).
+ */
+ public function checkGd()
+ {
+ $problemsFound = false;
+
+ if (!(extension_loaded('gd') && function_exists('gd_info'))) {
+ $problemsFound = true;
+ $this->resultsFailed['gd'] = [
+ "title" => "<i class='fa fa-image fa-fw'></i> GD library not installed",
+ "message" => "We could not confirm that the <code>GD</code> library is installed and enabled. GD is an image processing library that UserFrosting uses to generate captcha codes for user account registration.",
+ "success" => false
+ ];
+ } else {
+ $this->resultsSuccess['gd'] = [
+ "title" => "<i class='fa fa-image fa-fw'></i> GD library installed!",
+ "message" => "Great, you have <code>GD</code> installed and enabled.",
+ "success" => true
+ ];
+ }
+
+ return $problemsFound;
+ }
+
+ /**
+ * Check that all image* functions used by Captcha exist.
+ *
+ * Some versions of GD are missing one or more of these functions, thus why we check for them explicitly.
+ */
+ public function checkImageFunctions()
+ {
+ $problemsFound = false;
+
+ $funcs = [
+ 'imagepng',
+ 'imagecreatetruecolor',
+ 'imagecolorallocate',
+ 'imagefilledrectangle',
+ 'imageline',
+ 'imagesetpixel',
+ 'imagefontwidth',
+ 'imagestring'
+ ];
+
+ foreach ($funcs as $func) {
+ if (!function_exists($func)) {
+ $problemsFound = true;
+ $this->resultsFailed['function-' . $func] = [
+ "title" => "<i class='fa fa-code fa-fw'></i> Missing image manipulation function.",
+ "message" => "It appears that function <code>$func</code> is not available. UserFrosting needs this to render captchas.",
+ "success" => false
+ ];
+ } else {
+ $this->resultsSuccess['function-' . $func] = [
+ "title" => "<i class='fa fa-code fa-fw'></i> Function <b>$func</b> is available!",
+ "message" => "Sweet!",
+ "success" => true
+ ];
+ }
+ }
+
+ return $problemsFound;
+ }
+
+ /**
+ * Check that PDO is installed and enabled.
+ */
+ public function checkPdo()
+ {
+ $problemsFound = false;
+
+ if (!class_exists('PDO')) {
+ $problemsFound = true;
+ $this->resultsFailed['pdo'] = [
+ "title" => "<i class='fa fa-database fa-fw'></i> PDO is not installed.",
+ "message" => "I'm sorry, you must have PDO installed and enabled in order for UserFrosting to access the database. If you don't know what PDO is, please see <a href='http://php.net/manual/en/book.pdo.php'>http://php.net/manual/en/book.pdo.php</a>.",
+ "success" => false
+ ];
+ } else {
+ $this->resultsSuccess['pdo'] = [
+ "title" => "<i class='fa fa-database fa-fw'></i> PDO is installed!",
+ "message" => "You've got PDO installed. Good job!",
+ "success" => true
+ ];
+ }
+
+ return $problemsFound;
+ }
+
+ /**
+ * Check that log, cache, and session directories are writable, and that other directories are set appropriately for the environment.
+ */
+ function checkPermissions()
+ {
+ $problemsFound = false;
+
+ $shouldBeWriteable = [
+ $this->locator->findResource('log://') => true,
+ $this->locator->findResource('cache://') => true,
+ $this->locator->findResource('session://') => true
+ ];
+
+ if ($this->isProduction()) {
+ // Should be write-protected in production!
+ $shouldBeWriteable = array_merge($shouldBeWriteable, [
+ \UserFrosting\SPRINKLES_DIR => false,
+ \UserFrosting\VENDOR_DIR => false
+ ]);
+ }
+
+ // Check for essential files & perms
+ foreach ($shouldBeWriteable as $file => $assertWriteable) {
+ $is_dir = false;
+ if (!file_exists($file)) {
+ $problemsFound = true;
+ $this->resultsFailed['file-' . $file] = [
+ "title" => "<i class='fa fa-file-o fa-fw'></i> File or directory does not exist.",
+ "message" => "We could not find the file or directory <code>$file</code>.",
+ "success" => false
+ ];
+ } else {
+ $writeable = is_writable($file);
+ if ($assertWriteable !== $writeable) {
+ $problemsFound = true;
+ $this->resultsFailed['file-' . $file] = [
+ "title" => "<i class='fa fa-file-o fa-fw'></i> Incorrect permissions for file or directory.",
+ "message" => "<code>$file</code> is "
+ . ($writeable ? "writeable" : "not writeable")
+ . ", but it should "
+ . ($assertWriteable ? "be writeable" : "not be writeable")
+ . ". Please modify the OS user or group permissions so that user <b>"
+ . exec('whoami') . "</b> "
+ . ($assertWriteable ? "has" : "does not have") . " write permissions for this directory.",
+ "success" => false
+ ];
+ } else {
+ $this->resultsSuccess['file-' . $file] = [
+ "title" => "<i class='fa fa-file-o fa-fw'></i> File/directory check passed!",
+ "message" => "<code>$file</code> exists and is correctly set as <b>"
+ . ($writeable ? "writeable" : "not writeable")
+ . "</b>.",
+ "success" => true
+ ];
+ }
+ }
+ }
+ return $problemsFound;
+ }
+
+ /**
+ * Check that PHP meets the minimum required version.
+ */
+ public function checkPhp()
+ {
+ $problemsFound = false;
+
+ // Check PHP version
+ if (version_compare(phpversion(), \UserFrosting\PHP_MIN_VERSION, '<')) {
+ $problemsFound = true;
+ $this->resultsFailed['phpVersion'] = [
+ "title" => "<i class='fa fa-code fa-fw'></i> You need to upgrade your PHP installation.",
+ "message" => "I'm sorry, UserFrosting requires version " . \UserFrosting\PHP_MIN_VERSION . " or greater. Please upgrade your version of PHP, or contact your web hosting service and ask them to upgrade it for you.",
+ "success" => false
+ ];
+ } else {
+ $this->resultsSuccess['phpVersion'] = [
+ "title" => "<i class='fa fa-code fa-fw'></i> PHP version checks out!",
+ "message" => "You're using PHP " . \UserFrosting\PHP_MIN_VERSION . "or higher. Great!",
+ "success" => true
+ ];
+ }
+
+ return $problemsFound;
+ }
+
+ /**
+ * Determine whether or not we are running in production mode.
+ *
+ * @return bool
+ */
+ public function isProduction()
+ {
+ return (getenv('UF_MODE') == 'production');
+ }
+}
diff --git a/main/app/sprinkles/core/src/Util/ClassMapper.php b/main/app/sprinkles/core/src/Util/ClassMapper.php
new file mode 100755
index 0000000..5fa0881
--- /dev/null
+++ b/main/app/sprinkles/core/src/Util/ClassMapper.php
@@ -0,0 +1,94 @@
+<?php
+/**
+ * UserFrosting (http://www.userfrosting.com)
+ *
+ * @link https://github.com/userfrosting/UserFrosting
+ * @license https://github.com/userfrosting/UserFrosting/blob/master/licenses/UserFrosting.md (MIT License)
+ */
+
+namespace UserFrosting\Sprinkle\Core\Util;
+
+/**
+ * UserFrosting class mapper.
+ *
+ * This creates an abstraction layer for overrideable classes.
+ * For example, if we want to replace usages of the User class with MyUser, this abstraction layer handles that.
+ *
+ * @author Alex Weissman (https://alexanderweissman.com)
+ * @author Roger Ardibee
+ */
+class ClassMapper
+{
+ /**
+ * Mapping of generic class identifiers to specific class names.
+ */
+ protected $classMappings = [];
+
+ /**
+ * Creates an instance for a requested class identifier.
+ *
+ * @param string $identifier The identifier for the class, e.g. 'user'
+ * @param mixed ...$arg Whatever needs to be passed to the constructor.
+ */
+ public function createInstance($identifier)
+ {
+ $className = $this->getClassMapping($identifier);
+
+ $params = array_slice(func_get_args(), 1);
+
+ // We must use reflection in PHP < 5.6. See http://stackoverflow.com/questions/8734522/dynamically-call-class-with-variable-number-of-parameters-in-the-constructor
+ $reflection = new \ReflectionClass($className);
+
+ return $reflection->newInstanceArgs($params);
+ }
+
+ /**
+ * Gets the fully qualified class name for a specified class identifier.
+ *
+ * @param string $identifier
+ * @return string
+ */
+ public function getClassMapping($identifier)
+ {
+ if (isset($this->classMappings[$identifier])) {
+ return $this->classMappings[$identifier];
+ } else {
+ throw new \OutOfBoundsException("There is no class mapped to the identifier '$identifier'.");
+ }
+ }
+
+ /**
+ * Assigns a fully qualified class name to a specified class identifier.
+ *
+ * @param string $identifier
+ * @param string $className
+ * @return ClassMapper
+ */
+ public function setClassMapping($identifier, $className)
+ {
+ // Check that class exists
+ if (!class_exists($className)) {
+ throw new BadClassNameException("Unable to find the class '$className'." );
+ }
+
+ $this->classMappings[$identifier] = $className;
+
+ return $this;
+ }
+
+ /**
+ * Call a static method for a specified class.
+ *
+ * @param string $identifier The identifier for the class, e.g. 'user'
+ * @param string $methodName The method to be invoked.
+ * @param mixed ...$arg Whatever needs to be passed to the method.
+ */
+ public function staticMethod($identifier, $methodName)
+ {
+ $className = $this->getClassMapping($identifier);
+
+ $params = array_slice(func_get_args(), 2);
+
+ return call_user_func_array("$className::$methodName", $params);
+ }
+}
diff --git a/main/app/sprinkles/core/src/Util/EnvironmentInfo.php b/main/app/sprinkles/core/src/Util/EnvironmentInfo.php
new file mode 100755
index 0000000..aba9837
--- /dev/null
+++ b/main/app/sprinkles/core/src/Util/EnvironmentInfo.php
@@ -0,0 +1,68 @@
+<?php
+/**
+ * UserFrosting (http://www.userfrosting.com)
+ *
+ * @link https://github.com/userfrosting/UserFrosting
+ * @license https://github.com/userfrosting/UserFrosting/blob/master/licenses/UserFrosting.md (MIT License)
+ */
+namespace UserFrosting\Sprinkle\Core\Util;
+
+use Illuminate\Database\Capsule\Manager as Capsule;
+
+/**
+ * EnvironmentInfo Class
+ *
+ * Gets basic information about the application environment.
+ *
+ * @author Alex Weissman (https://alexanderweissman.com)
+ */
+class EnvironmentInfo
+{
+ /**
+ * @var ContainerInterface The DI container for your application.
+ */
+ public static $ci;
+
+ /**
+ * Get an array of key-value pairs containing basic information about the default database.
+ *
+ * @return string[] the properties of this database.
+ */
+ public static function database()
+ {
+ static::$ci['db'];
+
+ $pdo = Capsule::connection()->getPdo();
+ $results = [];
+
+ try {
+ $results['type'] = $pdo->getAttribute(\PDO::ATTR_DRIVER_NAME);
+ } catch (Exception $e) {
+ $results['type'] = "Unknown";
+ }
+
+ try {
+ $results['version'] = $pdo->getAttribute(\PDO::ATTR_SERVER_VERSION);
+ } catch (Exception $e) {
+ $results['version'] = "";
+ }
+
+ return $results;
+ }
+
+ /**
+ * Test whether a DB connection can be established.
+ *
+ * @return bool true if the connection can be established, false otherwise.
+ */
+ public static function canConnectToDatabase()
+ {
+ try {
+ Capsule::connection()->getPdo();
+ } catch (\PDOException $e) {
+ return false;
+ }
+
+ return true;
+ }
+}
diff --git a/main/app/sprinkles/core/src/Util/ShutdownHandler.php b/main/app/sprinkles/core/src/Util/ShutdownHandler.php
new file mode 100755
index 0000000..e7a6903
--- /dev/null
+++ b/main/app/sprinkles/core/src/Util/ShutdownHandler.php
@@ -0,0 +1,167 @@
+<?php
+/**
+ * UserFrosting (http://www.userfrosting.com)
+ *
+ * @link https://github.com/userfrosting/UserFrosting
+ * @license https://github.com/userfrosting/UserFrosting/blob/master/licenses/UserFrosting.md (MIT License)
+ */
+namespace UserFrosting\Sprinkle\Core\Util;
+
+use Interop\Container\ContainerInterface;
+use UserFrosting\Sprinkle\Core\Http\Concerns\DeterminesContentType;
+
+/**
+ * Registers a handler to be invoked whenever the application shuts down.
+ * If it shut down due to a fatal error, will generate a clean error message.
+ *
+ * @author Alex Weissman (https://alexanderweissman.com)
+ */
+class ShutdownHandler
+{
+ use DeterminesContentType;
+
+ /**
+ * @var ContainerInterface The global container object, which holds all your services.
+ */
+ protected $ci;
+
+ /**
+ * @var bool
+ */
+ protected $displayErrorInfo;
+
+ /**
+ * Constructor.
+ *
+ * @param ContainerInterface $ci The global container object, which holds all your services.
+ * @param bool $displayErrorInfo
+ */
+ public function __construct(ContainerInterface $ci, $displayErrorInfo)
+ {
+ $this->ci = $ci;
+ $this->displayErrorInfo = $displayErrorInfo;
+ }
+
+ /**
+ * Register this class with the shutdown handler.
+ *
+ * @return void
+ */
+ public function register()
+ {
+ register_shutdown_function([$this, 'fatalHandler']);
+ }
+
+ /**
+ * Set up the fatal error handler, so that we get a clean error message and alert instead of a WSOD.
+ */
+ public function fatalHandler()
+ {
+ $error = error_get_last();
+ $fatalErrorTypes = [
+ E_ERROR,
+ E_PARSE,
+ E_CORE_ERROR,
+ E_COMPILE_ERROR,
+ E_RECOVERABLE_ERROR
+ ];
+
+ // Handle fatal errors and parse errors
+ if ($error !== NULL && in_array($error['type'], $fatalErrorTypes)) {
+
+ // Build the appropriate error message (debug or client)
+ if ($this->displayErrorInfo) {
+ $errorMessage = $this->buildErrorInfoMessage($error);
+ } else {
+ $errorMessage = "Oops, looks like our server might have goofed. If you're an admin, please ensure that <code>php.log_errors</code> is enabled, and then check the <strong>PHP</strong> error log.";
+ }
+
+ // For CLI, just print the message and exit.
+ if (php_sapi_name() === 'cli') {
+ exit($errorMessage . PHP_EOL);
+ }
+
+ // For all other environments, print a debug response for the requested data type
+ echo $this->buildErrorPage($errorMessage);
+
+ // If this is an AJAX request and AJAX debugging is turned off, write message to the alert stream
+ if ($this->ci->request->isXhr() && !$this->ci->config['site.debug.ajax']) {
+ if ($this->ci->alerts && is_object($this->ci->alerts)) {
+ $this->ci->alerts->addMessageTranslated('danger', $errorMessage);
+ }
+ }
+
+ header('HTTP/1.1 500 Internal Server Error');
+ exit();
+ }
+ }
+
+ /**
+ * Build the error message string.
+ *
+ * @param array $error
+ * @return string
+ */
+ protected function buildErrorInfoMessage(array $error)
+ {
+ $errfile = $error['file'];
+ $errline = (string) $error['line'];
+ $errstr = $error['message'];
+
+ $errorTypes = [
+ E_ERROR => 'Fatal error',
+ E_PARSE => 'Parse error',
+ E_CORE_ERROR => 'PHP core error',
+ E_COMPILE_ERROR => 'Zend compile error',
+ E_RECOVERABLE_ERROR => 'Catchable fatal error'
+ ];
+
+ return "<strong>" . $errorTypes[$error['type']] . "</strong>: $errstr in <strong>$errfile</strong> on line <strong>$errline</strong>";
+ }
+
+ /**
+ * Build an error response of the appropriate type as determined by the request's Accept header.
+ *
+ * @param string $message
+ * @return string
+ */
+ protected function buildErrorPage($message)
+ {
+ $contentType = $this->determineContentType($this->ci->request, $this->ci->config['site.debug.ajax']);
+
+ switch ($contentType) {
+ case 'application/json':
+ $error = ['message' => $message];
+ return json_encode($error, JSON_PRETTY_PRINT);
+
+ case 'text/html':
+ return $this->buildHtmlErrorPage($message);
+
+ default:
+ case 'text/plain':
+ return $message;
+ }
+ }
+
+ /**
+ * Build an HTML error page from an error string.
+ *
+ * @param string $errorMessage
+ * @return string
+ */
+ protected function buildHtmlErrorPage($message)
+ {
+ $title = 'UserFrosting Application Error';
+ $html = "<p>$message</p>";
+
+ return sprintf(
+ "<html><head><meta http-equiv='Content-Type' content='text/html; charset=utf-8'>" .
+ "<title>%s</title><style>body{margin:0;padding:30px;font:12px/1.5 Helvetica,Arial,Verdana," .
+ "sans-serif;}h1{margin:0;font-size:48px;font-weight:normal;line-height:48px;}" .
+ "</style></head><body><h1>%s</h1>%s</body></html>",
+ $title,
+ $title,
+ $html
+ );
+ }
+}
diff --git a/main/app/sprinkles/core/src/Util/Util.php b/main/app/sprinkles/core/src/Util/Util.php
new file mode 100755
index 0000000..ae551cf
--- /dev/null
+++ b/main/app/sprinkles/core/src/Util/Util.php
@@ -0,0 +1,173 @@
+<?php
+/**
+ * UserFrosting (http://www.userfrosting.com)
+ *
+ * @link https://github.com/userfrosting/UserFrosting
+ * @license https://github.com/userfrosting/UserFrosting/blob/master/licenses/UserFrosting.md (MIT License)
+ */
+namespace UserFrosting\Sprinkle\Core\Util;
+
+/**
+ * Util Class
+ *
+ * Static utility functions.
+ *
+ * @author Alex Weissman (https://alexanderweissman.com)
+ */
+class Util
+{
+ /**
+ * Extracts specific fields from one associative array, and places them into another.
+ *
+ * @param mixed[] $inputArray
+ * @param string[] $fieldArray
+ * @param bool $remove
+ * @return mixed[]
+ */
+ static public function extractFields(&$inputArray, $fieldArray, $remove = true)
+ {
+ $result = [];
+
+ foreach ($fieldArray as $name) {
+ if (array_key_exists($name, $inputArray)) {
+ $result[$name] = $inputArray[$name];
+
+ // Optionally remove value from input array
+ if ($remove) {
+ unset($inputArray[$name]);
+ }
+ }
+ }
+
+ return $result;
+ }
+
+ /**
+ * Extracts numeric portion of a string (for example, for normalizing phone numbers).
+ *
+ * @param string $str
+ * @return string
+ */
+ static public function extractDigits($str)
+ {
+ return preg_replace('/[^0-9]/', '', $str);
+ }
+
+ /**
+ * Formats a phone number as a standard 7- or 10-digit string (xxx) xxx-xxxx
+ *
+ * @param string $phone
+ * @return string
+ */
+ static public function formatPhoneNumber($phone)
+ {
+ $num = static::extractDigits($phone);
+
+ $len = strlen($num);
+
+ if ($len == 7) {
+ $num = preg_replace('/([0-9]{3})([0-9]{4})/', '$1-$2', $num);
+ } elseif ($len == 10) {
+ $num = preg_replace('/([0-9]{3})([0-9]{3})([0-9]{4})/', '($1) $2-$3', $num);
+ }
+
+ return $num;
+ }
+
+ /**
+ * Nicely format an array for printing.
+ * See https://stackoverflow.com/a/9776726/2970321
+ *
+ * @param array $arr
+ * @return string
+ */
+ static public function prettyPrintArray(array $arr)
+ {
+ $json = json_encode($arr);
+ $result = '';
+ $level = 0;
+ $inQuotes = false;
+ $inEscape = false;
+ $endsLineLevel = NULL;
+ $jsonLength = strlen($json);
+
+ for ($i = 0; $i < $jsonLength; $i++) {
+ $char = $json[$i];
+ $newLineLevel = NULL;
+ $post = '';
+ if ($endsLineLevel !== NULL) {
+ $newLineLevel = $endsLineLevel;
+ $endsLineLevel = NULL;
+ }
+ if ($inEscape) {
+ $inEscape = false;
+ } elseif ($char === '"') {
+ $inQuotes = !$inQuotes;
+ } elseif (!$inQuotes) {
+ switch ($char) {
+ case '}': case ']':
+ $level--;
+ $endsLineLevel = NULL;
+ $newLineLevel = $level;
+ break;
+
+ case '{': case '[':
+ $level++;
+
+ case ',':
+ $endsLineLevel = $level;
+ break;
+
+ case ':':
+ $post = ' ';
+ break;
+
+ case ' ': case '\t': case '\n': case '\r':
+ $char = '';
+ $endsLineLevel = $newLineLevel;
+ $newLineLevel = NULL;
+ break;
+ }
+ } elseif ($char === '\\') {
+ $inEscape = true;
+ }
+
+ if ($newLineLevel !== NULL) {
+ $result .= '<br>'.str_repeat( '&nbsp;&nbsp;', $newLineLevel);
+ }
+
+ $result .= $char.$post;
+ }
+
+ return $result;
+ }
+
+ /**
+ * Generate a random phrase, consisting of a specified number of adjectives, followed by a noun.
+ *
+ * @param int $numAdjectives
+ * @param int $maxLength
+ * @param int $maxTries
+ * @param string $separator
+ * @return string
+ */
+ static public function randomPhrase($numAdjectives, $maxLength = 9999999, $maxTries = 10, $separator = '-')
+ {
+ $adjectives = include('extra://adjectives.php');
+ $nouns = include('extra://nouns.php');
+
+ for ($n = 0; $n < $maxTries; $n++) {
+ $keys = array_rand($adjectives, $numAdjectives);
+ $matches = array_only($adjectives, $keys);
+
+ $result = implode($separator, $matches);
+ $result .= $separator . $nouns[array_rand($nouns)];
+ $result = str_slug($result, $separator);
+ if (strlen($result) < $maxLength) {
+ return $result;
+ }
+ }
+
+ return '';
+ }
+}