From cf14306c2b3f82a81f8d56669a71633b4d4b5fce Mon Sep 17 00:00:00 2001
From: marvin-borner@live.com
Date: Mon, 16 Apr 2018 21:09:05 +0200
Subject: Main merge to user management system - files are now at /main/public/
---
.../core/src/Util/BadClassNameException.php | 18 ++
main/app/sprinkles/core/src/Util/Captcha.php | 159 ++++++++++
.../sprinkles/core/src/Util/CheckEnvironment.php | 340 +++++++++++++++++++++
main/app/sprinkles/core/src/Util/ClassMapper.php | 94 ++++++
.../sprinkles/core/src/Util/EnvironmentInfo.php | 68 +++++
.../sprinkles/core/src/Util/ShutdownHandler.php | 167 ++++++++++
main/app/sprinkles/core/src/Util/Util.php | 173 +++++++++++
7 files changed, 1019 insertions(+)
create mode 100755 main/app/sprinkles/core/src/Util/BadClassNameException.php
create mode 100755 main/app/sprinkles/core/src/Util/Captcha.php
create mode 100755 main/app/sprinkles/core/src/Util/CheckEnvironment.php
create mode 100755 main/app/sprinkles/core/src/Util/ClassMapper.php
create mode 100755 main/app/sprinkles/core/src/Util/EnvironmentInfo.php
create mode 100755 main/app/sprinkles/core/src/Util/ShutdownHandler.php
create mode 100755 main/app/sprinkles/core/src/Util/Util.php
(limited to 'main/app/sprinkles/core/src/Util')
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 @@
+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 @@
+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" => " Missing Apache module $module.",
+ "message" => "Please make sure that the $module
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" => " Apache module $module is installed and enabled.",
+ "message" => "Great, we found the $module
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" => " GD library not installed",
+ "message" => "We could not confirm that the GD
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" => " GD library installed!",
+ "message" => "Great, you have GD
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" => " Missing image manipulation function.",
+ "message" => "It appears that function $func
is not available. UserFrosting needs this to render captchas.",
+ "success" => false
+ ];
+ } else {
+ $this->resultsSuccess['function-' . $func] = [
+ "title" => " Function $func 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" => " 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 http://php.net/manual/en/book.pdo.php.",
+ "success" => false
+ ];
+ } else {
+ $this->resultsSuccess['pdo'] = [
+ "title" => " 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" => " File or directory does not exist.",
+ "message" => "We could not find the file or directory $file
.",
+ "success" => false
+ ];
+ } else {
+ $writeable = is_writable($file);
+ if ($assertWriteable !== $writeable) {
+ $problemsFound = true;
+ $this->resultsFailed['file-' . $file] = [
+ "title" => " Incorrect permissions for file or directory.",
+ "message" => "$file
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 "
+ . exec('whoami') . " "
+ . ($assertWriteable ? "has" : "does not have") . " write permissions for this directory.",
+ "success" => false
+ ];
+ } else {
+ $this->resultsSuccess['file-' . $file] = [
+ "title" => " File/directory check passed!",
+ "message" => "$file
exists and is correctly set as "
+ . ($writeable ? "writeable" : "not writeable")
+ . ".",
+ "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" => " 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" => " 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 @@
+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 @@
+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 @@
+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 php.log_errors
is enabled, and then check the PHP 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 "" . $errorTypes[$error['type']] . ": $errstr in $errfile on line $errline";
+ }
+
+ /**
+ * 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 = "
$message
"; + + return sprintf( + "" . + "