From 04d6d5ca99ebfd1cebb8ce06618fb3811fc1a8aa Mon Sep 17 00:00:00 2001 From: Charles Date: Thu, 9 Jan 2020 10:55:03 +0100 Subject: phpmyadmin working --- srcs/phpmyadmin/libraries/classes/ErrorHandler.php | 604 +++++++++++++++++++++ 1 file changed, 604 insertions(+) create mode 100644 srcs/phpmyadmin/libraries/classes/ErrorHandler.php (limited to 'srcs/phpmyadmin/libraries/classes/ErrorHandler.php') diff --git a/srcs/phpmyadmin/libraries/classes/ErrorHandler.php b/srcs/phpmyadmin/libraries/classes/ErrorHandler.php new file mode 100644 index 0000000..f5cf124 --- /dev/null +++ b/srcs/phpmyadmin/libraries/classes/ErrorHandler.php @@ -0,0 +1,604 @@ +error_reporting = error_reporting(); + } + } + + /** + * Destructor + * + * stores errors in session + * + */ + public function __destruct() + { + if (isset($_SESSION)) { + if (! isset($_SESSION['errors'])) { + $_SESSION['errors'] = []; + } + + // remember only not displayed errors + foreach ($this->errors as $key => $error) { + /** + * We don't want to store all errors here as it would + * explode user session. + */ + if (count($_SESSION['errors']) >= 10) { + $error = new Error( + 0, + __('Too many error messages, some are not displayed.'), + __FILE__, + __LINE__ + ); + $_SESSION['errors'][$error->getHash()] = $error; + break; + } elseif (($error instanceof Error) + && ! $error->isDisplayed() + ) { + $_SESSION['errors'][$key] = $error; + } + } + } + } + + /** + * Toggles location hiding + * + * @param boolean $hide Whether to hide + * + * @return void + */ + public function setHideLocation(bool $hide): void + { + $this->hide_location = $hide; + } + + /** + * returns array with all errors + * + * @param bool $check Whether to check for session errors + * + * @return Error[] + */ + public function getErrors(bool $check = true): array + { + if ($check) { + $this->checkSavedErrors(); + } + return $this->errors; + } + + /** + * returns the errors occurred in the current run only. + * Does not include the errors saved in the SESSION + * + * @return Error[] + */ + public function getCurrentErrors(): array + { + return $this->errors; + } + + /** + * Pops recent errors from the storage + * + * @param int $count Old error count + * + * @return Error[] + */ + public function sliceErrors(int $count): array + { + $errors = $this->getErrors(false); + $this->errors = array_splice($errors, 0, $count); + return array_splice($errors, $count); + } + + /** + * Error handler - called when errors are triggered/occurred + * + * This calls the addError() function, escaping the error string + * Ignores the errors wherever Error Control Operator (@) is used. + * + * @param integer $errno error number + * @param string $errstr error string + * @param string $errfile error file + * @param integer $errline error line + * + * @return void + */ + public function handleError( + int $errno, + string $errstr, + string $errfile, + int $errline + ): void { + if (function_exists('error_reporting')) { + /** + * Check if Error Control Operator (@) was used, but still show + * user errors even in this case. + */ + if (error_reporting() == 0 && + $this->error_reporting != 0 && + ($errno & (E_USER_WARNING | E_USER_ERROR | E_USER_NOTICE)) == 0 + ) { + return; + } + } else { + if (($errno & (E_USER_WARNING | E_USER_ERROR | E_USER_NOTICE)) == 0) { + return; + } + } + + $this->addError($errstr, $errno, $errfile, $errline, true); + } + + /** + * Add an error; can also be called directly (with or without escaping) + * + * The following error types cannot be handled with a user defined function: + * E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR, + * E_COMPILE_WARNING, + * and most of E_STRICT raised in the file where set_error_handler() is called. + * + * Do not use the context parameter as we want to avoid storing the + * complete $GLOBALS inside $_SESSION['errors'] + * + * @param string $errstr error string + * @param integer $errno error number + * @param string $errfile error file + * @param integer $errline error line + * @param boolean $escape whether to escape the error string + * + * @return void + */ + public function addError( + string $errstr, + int $errno, + string $errfile, + int $errline, + bool $escape = true + ): void { + if ($escape) { + $errstr = htmlspecialchars($errstr); + } + // create error object + $error = new Error( + $errno, + $errstr, + $errfile, + $errline + ); + $error->setHideLocation($this->hide_location); + + // do not repeat errors + $this->errors[$error->getHash()] = $error; + + switch ($error->getNumber()) { + case E_STRICT: + case E_DEPRECATED: + case E_NOTICE: + case E_WARNING: + case E_CORE_WARNING: + case E_COMPILE_WARNING: + case E_RECOVERABLE_ERROR: + /* Avoid rendering BB code in PHP errors */ + $error->setBBCode(false); + break; + case E_USER_NOTICE: + case E_USER_WARNING: + case E_USER_ERROR: + // just collect the error + // display is called from outside + break; + case E_ERROR: + case E_PARSE: + case E_CORE_ERROR: + case E_COMPILE_ERROR: + default: + // FATAL error, display it and exit + $this->dispFatalError($error); + exit; + } + } + + /** + * trigger a custom error + * + * @param string $errorInfo error message + * @param integer $errorNumber error number + * + * @return void + */ + public function triggerError(string $errorInfo, ?int $errorNumber = null): void + { + // we could also extract file and line from backtrace + // and call handleError() directly + trigger_error($errorInfo, $errorNumber); + } + + /** + * display fatal error and exit + * + * @param Error $error the error + * + * @return void + */ + protected function dispFatalError(Error $error): void + { + if (! headers_sent()) { + $this->dispPageStart($error); + } + $error->display(); + $this->dispPageEnd(); + exit; + } + + /** + * Displays user errors not displayed + * + * @return void + */ + public function dispUserErrors(): void + { + echo $this->getDispUserErrors(); + } + + /** + * Renders user errors not displayed + * + * @return string + */ + public function getDispUserErrors(): string + { + $retval = ''; + foreach ($this->getErrors() as $error) { + if ($error->isUserError() && ! $error->isDisplayed()) { + $retval .= $error->getDisplay(); + } + } + return $retval; + } + + /** + * display HTML header + * + * @param Error $error the error + * + * @return void + */ + protected function dispPageStart(?Error $error = null): void + { + Response::getInstance()->disable(); + echo ''; + if ($error) { + echo $error->getTitle(); + } else { + echo 'phpMyAdmin error reporting page'; + } + echo ''; + } + + /** + * display HTML footer + * + * @return void + */ + protected function dispPageEnd(): void + { + echo ''; + } + + /** + * renders errors not displayed + * + * @return string + */ + public function getDispErrors(): string + { + $retval = ''; + // display errors if SendErrorReports is set to 'ask'. + if ($GLOBALS['cfg']['SendErrorReports'] != 'never') { + foreach ($this->getErrors() as $error) { + if (! $error->isDisplayed()) { + $retval .= $error->getDisplay(); + } + } + } else { + $retval .= $this->getDispUserErrors(); + } + // if preference is not 'never' and + // there are 'actual' errors to be reported + if ($GLOBALS['cfg']['SendErrorReports'] != 'never' + && $this->countErrors() != $this->countUserErrors() + ) { + // add report button. + $retval .= '
'php', + 'send_error_report' => '1', + 'server' => $GLOBALS['server'], + ]); + $retval .= '' + . '' + . ''; + + if ($GLOBALS['cfg']['SendErrorReports'] == 'ask') { + // add ignore buttons + $retval .= ''; + } + $retval .= ''; + $retval .= '
'; + } + return $retval; + } + + /** + * displays errors not displayed + * + * @return void + */ + public function dispErrors(): void + { + echo $this->getDispErrors(); + } + + /** + * look in session for saved errors + * + * @return void + */ + protected function checkSavedErrors(): void + { + if (isset($_SESSION['errors'])) { + // restore saved errors + foreach ($_SESSION['errors'] as $hash => $error) { + if ($error instanceof Error && ! isset($this->errors[$hash])) { + $this->errors[$hash] = $error; + } + } + + // delete stored errors + $_SESSION['errors'] = []; + unset($_SESSION['errors']); + } + } + + /** + * return count of errors + * + * @param bool $check Whether to check for session errors + * + * @return integer number of errors occurred + */ + public function countErrors(bool $check = true): int + { + return count($this->getErrors($check)); + } + + /** + * return count of user errors + * + * @return integer number of user errors occurred + */ + public function countUserErrors(): int + { + $count = 0; + if ($this->countErrors()) { + foreach ($this->getErrors() as $error) { + if ($error->isUserError()) { + $count++; + } + } + } + + return $count; + } + + /** + * whether use errors occurred or not + * + * @return boolean + */ + public function hasUserErrors(): bool + { + return (bool) $this->countUserErrors(); + } + + /** + * whether errors occurred or not + * + * @return boolean + */ + public function hasErrors(): bool + { + return (bool) $this->countErrors(); + } + + /** + * number of errors to be displayed + * + * @return integer number of errors to be displayed + */ + public function countDisplayErrors(): int + { + if ($GLOBALS['cfg']['SendErrorReports'] != 'never') { + return $this->countErrors(); + } + + return $this->countUserErrors(); + } + + /** + * whether there are errors to display or not + * + * @return boolean + */ + public function hasDisplayErrors(): bool + { + return (bool) $this->countDisplayErrors(); + } + + /** + * Deletes previously stored errors in SESSION. + * Saves current errors in session as previous errors. + * Required to save current errors in case 'ask' + * + * @return void + */ + public function savePreviousErrors(): void + { + unset($_SESSION['prev_errors']); + $_SESSION['prev_errors'] = $GLOBALS['error_handler']->getCurrentErrors(); + } + + /** + * Function to check if there are any errors to be prompted. + * Needed because user warnings raised are + * also collected by global error handler. + * This distinguishes between the actual errors + * and user errors raised to warn user. + * + * @return boolean true if there are errors to be "prompted", false otherwise + */ + public function hasErrorsForPrompt(): bool + { + return ( + $GLOBALS['cfg']['SendErrorReports'] != 'never' + && $this->countErrors() != $this->countUserErrors() + ); + } + + /** + * Function to report all the collected php errors. + * Must be called at the end of each script + * by the $GLOBALS['error_handler'] only. + * + * @return void + */ + public function reportErrors(): void + { + // if there're no actual errors, + if (! $this->hasErrors() + || $this->countErrors() == $this->countUserErrors() + ) { + // then simply return. + return; + } + // Delete all the prev_errors in session & store new prev_errors in session + $this->savePreviousErrors(); + $response = Response::getInstance(); + $jsCode = ''; + if ($GLOBALS['cfg']['SendErrorReports'] == 'always') { + if ($response->isAjax()) { + // set flag for automatic report submission. + $response->addJSON('sendErrorAlways', '1'); + } else { + // send the error reports asynchronously & without asking user + $jsCode .= '$("#pma_report_errors_form").submit();' + . 'Functions.ajaxShowMessage( + Messages.phpErrorsBeingSubmitted, false + );'; + // js code to appropriate focusing, + $jsCode .= '$("html, body").animate({ + scrollTop:$(document).height() + }, "slow");'; + } + } elseif ($GLOBALS['cfg']['SendErrorReports'] == 'ask') { + //ask user whether to submit errors or not. + if (! $response->isAjax()) { + // js code to show appropriate msgs, event binding & focusing. + $jsCode = 'Functions.ajaxShowMessage(Messages.phpErrorsFound);' + . '$("#pma_ignore_errors_popup").on("click", function() { + Functions.ignorePhpErrors() + });' + . '$("#pma_ignore_all_errors_popup").on("click", + function() { + Functions.ignorePhpErrors(false) + });' + . '$("#pma_ignore_errors_bottom").on("click", function(e) { + e.preventDefault(); + Functions.ignorePhpErrors() + });' + . '$("#pma_ignore_all_errors_bottom").on("click", + function(e) { + e.preventDefault(); + Functions.ignorePhpErrors(false) + });' + . '$("html, body").animate({ + scrollTop:$(document).height() + }, "slow");'; + } + } + // The errors are already sent from the response. + // Just focus on errors division upon load event. + $response->getFooter()->getScripts()->addCode($jsCode); + } +} -- cgit