From a10e2b0b96bcf2ff8657a1a729aee8d25b17df3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maur=C3=ADcio=20Meneghini=20Fauth?= Date: Wed, 13 Sep 2017 20:51:08 -0300 Subject: [PATCH] Refactor error_report functions to static methods MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: MaurĂ­cio Meneghini Fauth --- error_report.php | 8 +- libraries/classes/ErrorReport.php | 331 ++++++++++++++++++++++++++++++ libraries/error_report.lib.php | 323 ----------------------------- 3 files changed, 335 insertions(+), 327 deletions(-) create mode 100644 libraries/classes/ErrorReport.php delete mode 100644 libraries/error_report.lib.php diff --git a/error_report.php b/error_report.php index 722277a1d5..3ac3c9ed80 100644 --- a/error_report.php +++ b/error_report.php @@ -5,11 +5,11 @@ * * @package PhpMyAdmin */ +use PhpMyAdmin\ErrorReport; use PhpMyAdmin\Response; use PhpMyAdmin\UserPreferences; require_once 'libraries/common.inc.php'; -require_once 'libraries/error_report.lib.php'; if (!isset($_REQUEST['exception_type']) ||!in_array($_REQUEST['exception_type'], array('js', 'php')) @@ -47,10 +47,10 @@ if (isset($_REQUEST['send_error_report']) ); } } - $reportData = PMA_getReportData($_REQUEST['exception_type']); + $reportData = ErrorReport::getReportData($_REQUEST['exception_type']); // report if and only if there were 'actual' errors. if (count($reportData) > 0) { - $server_response = PMA_sendErrorReport($reportData); + $server_response = ErrorReport::send($reportData); if ($server_response === false) { $success = false; } else { @@ -122,7 +122,7 @@ if (isset($_REQUEST['send_error_report']) $response->addJSON('report_setting', $GLOBALS['cfg']['SendErrorReports']); } else { if ($_REQUEST['exception_type'] == 'js') { - $response->addHTML(PMA_getErrorReportForm()); + $response->addHTML(ErrorReport::getForm()); } else { // clear previous errors & save new ones. $GLOBALS['error_handler']->savePreviousErrors(); diff --git a/libraries/classes/ErrorReport.php b/libraries/classes/ErrorReport.php new file mode 100644 index 0000000000..df1bcfd5b8 --- /dev/null +++ b/libraries/classes/ErrorReport.php @@ -0,0 +1,331 @@ + PMA_VERSION, + "browser_name" => PMA_USR_BROWSER_AGENT, + "browser_version" => PMA_USR_BROWSER_VER, + "user_os" => PMA_USR_OS, + "server_software" => $_SERVER['SERVER_SOFTWARE'], + "user_agent_string" => $_SERVER['HTTP_USER_AGENT'], + "locale" => $_COOKIE['pma_lang'], + "configuration_storage" => + is_null($relParams['db']) ? "disabled" : + "enabled", + "php_version" => phpversion() + ); + + if ($exception_type == 'js') { + if (empty($_REQUEST['exception'])) { + return array(); + } + $exception = $_REQUEST['exception']; + $exception["stack"] = self::translateStacktrace($exception["stack"]); + List($uri, $script_name) = self::sanitizeUrl($exception["url"]); + $exception["uri"] = $uri; + unset($exception["url"]); + + $report ["exception_type"] = 'js'; + $report ["exception"] = $exception; + $report ["script_name"] = $script_name; + $report ["microhistory"] = $_REQUEST['microhistory']; + + if (! empty($_REQUEST['description'])) { + $report['steps'] = $_REQUEST['description']; + } + } elseif ($exception_type == 'php') { + $errors = array(); + // create php error report + $i = 0; + if (!isset($_SESSION['prev_errors']) + || $_SESSION['prev_errors'] == '' + ) { + return array(); + } + foreach ($_SESSION['prev_errors'] as $errorObj) { + /* @var $errorObj PhpMyAdmin\Error */ + if ($errorObj->getLine() + && $errorObj->getType() + && $errorObj->getNumber() != E_USER_WARNING + ) { + $errors[$i++] = array( + "lineNum" => $errorObj->getLine(), + "file" => $errorObj->getFile(), + "type" => $errorObj->getType(), + "msg" => $errorObj->getOnlyMessage(), + "stackTrace" => $errorObj->getBacktrace(5), + "stackhash" => $errorObj->getHash() + ); + + } + } + + // if there were no 'actual' errors to be submitted. + if ($i==0) { + return array(); // then return empty array + } + $report ["exception_type"] = 'php'; + $report["errors"] = $errors; + } else { + return array(); + } + + return $report; + } + + /** + * Sanitize a url to remove the identifiable host name and extract the + * current script name from the url fragment + * + * It returns two things in an array. The first is the uri without the + * hostname and identifying query params. The second is the name of the + * php script in the url + * + * @param String $url the url to sanitize + * + * @return array the uri and script name + */ + public static function sanitizeUrl($url) + { + $components = parse_url($url); + if (isset($components["fragment"]) + && preg_match("", $components["fragment"], $matches) + ) { + $uri = str_replace($matches[0], "", $components["fragment"]); + $url = "https://example.com/" . $uri; + $components = parse_url($url); + } + + // get script name + preg_match("<([a-zA-Z\-_\d]*\.php)$>", $components["path"], $matches); + if (count($matches) < 2) { + $script_name = 'index.php'; + } else { + $script_name = $matches[1]; + } + + // remove deployment specific details to make uri more generic + if (isset($components["query"])) { + parse_str($components["query"], $query_array); + unset($query_array["db"]); + unset($query_array["table"]); + unset($query_array["token"]); + unset($query_array["server"]); + $query = http_build_query($query_array); + } else { + $query = ''; + } + + $uri = $script_name . "?" . $query; + return array($uri, $script_name); + } + + /** + * Sends report data to the error reporting server + * + * @param array $report the report info to be sent + * + * @return String the reply of the server + */ + public static function send($report) + { + $response = Util::httpRequest( + self::SUBMISSION_URL, + "POST", + false, + json_encode($report), + "Content-Type: application/json" + ); + return $response; + } + + /** + * Returns number of lines in given javascript file. + * + * @param string $filename javascript filename + * + * @return Number of lines + * + * @todo Should gracefully handle non existing files + */ + public static function countLines($filename) + { + /** + * The generated file that contains the line numbers for the js files + * If you change any of the js files you can run the scripts/line-counts.sh + */ + if (is_readable('js/line_counts.php')) { + include_once 'js/line_counts.php'; + } + + global $LINE_COUNT; + if (defined('LINE_COUNTS')) { + return $LINE_COUNT[$filename]; + } + + // ensure that the file is inside the phpMyAdmin folder + $depath = 1; + foreach (explode('/', $filename) as $part) { + if ($part == '..') { + $depath--; + } elseif ($part != '.' || $part === '') { + $depath++; + } + if ($depath < 0) { + return 0; + } + } + + $linecount = 0; + $handle = fopen('./js/' . $filename, 'r'); + while (!feof($handle)) { + $line = fgets($handle); + if ($line === false) { + break; + } + $linecount++; + } + fclose($handle); + return $linecount; + } + + /** + * returns the translated line number and the file name from the cumulative line + * number and an array of files + * + * uses the $LINE_COUNT global array of file names and line numbers + * + * @param array $filenames list of files in order of concatenation + * @param Integer $cumulative_number the cumulative line number in the + * concatenated files + * + * @return array the filename and line number + * Returns two variables in an array: + * - A String $filename the filename where the requested cumulative number + * exists + * - Integer $linenumber the translated line number in the returned file + */ + public static function getLineNumber($filenames, $cumulative_number) + { + $cumulative_sum = 0; + foreach ($filenames as $filename) { + $filecount = self::countLines($filename); + if ($cumulative_number <= $cumulative_sum + $filecount + 2) { + $linenumber = $cumulative_number - $cumulative_sum; + break; + } + $cumulative_sum += $filecount + 2; + } + if (! isset($filename)) { + $filename = ''; + } + return array($filename, $linenumber); + } + + /** + * translates the cumulative line numbers in the stack trace as well as sanitize + * urls and trim long lines in the context + * + * @param array $stack the stack trace + * + * @return array $stack the modified stack trace + */ + public static function translateStacktrace($stack) + { + foreach ($stack as &$level) { + foreach ($level["context"] as &$line) { + if (mb_strlen($line) > 80) { + $line = mb_substr($line, 0, 75) . "//..."; + } + } + if (preg_match("", $level["url"], $matches)) { + parse_str($matches[1], $vars); + List($file_name, $line_number) = self::getLineNumber( + $vars["scripts"], $level["line"] + ); + $level["filename"] = $file_name; + $level["line"] = $line_number; + } else { + unset($level["context"]); + List($uri, $script_name) = self::sanitizeUrl($level["url"]); + $level["uri"] = $uri; + $level["scriptname"] = $script_name; + } + unset($level["url"]); + } + unset($level); + return $stack; + } + + /** + * generates the error report form to collect user description and preview the + * report before being sent + * + * @return String the form + */ + public static function getForm() + { + $datas = array( + 'report_data' => self::getPrettyReportData(), + 'hidden_inputs' => Url::getHiddenInputs(), + 'hidden_fields' => null, + ); + + $reportData = self::getReportData(); + if (!empty($reportData)) { + $datas['hidden_fields'] = Url::getHiddenFields($reportData); + } + + return Template::get('error/report_form') + ->render($datas); + } +} diff --git a/libraries/error_report.lib.php b/libraries/error_report.lib.php deleted file mode 100644 index 569651e798..0000000000 --- a/libraries/error_report.lib.php +++ /dev/null @@ -1,323 +0,0 @@ - PMA_VERSION, - "browser_name" => PMA_USR_BROWSER_AGENT, - "browser_version" => PMA_USR_BROWSER_VER, - "user_os" => PMA_USR_OS, - "server_software" => $_SERVER['SERVER_SOFTWARE'], - "user_agent_string" => $_SERVER['HTTP_USER_AGENT'], - "locale" => $_COOKIE['pma_lang'], - "configuration_storage" => - is_null($relParams['db']) ? "disabled" : - "enabled", - "php_version" => phpversion() - ); - - if ($exception_type == 'js') { - if (empty($_REQUEST['exception'])) { - return array(); - } - $exception = $_REQUEST['exception']; - $exception["stack"] = PMA_translateStacktrace($exception["stack"]); - List($uri, $script_name) = PMA_sanitizeUrl($exception["url"]); - $exception["uri"] = $uri; - unset($exception["url"]); - - $report ["exception_type"] = 'js'; - $report ["exception"] = $exception; - $report ["script_name"] = $script_name; - $report ["microhistory"] = $_REQUEST['microhistory']; - - if (! empty($_REQUEST['description'])) { - $report['steps'] = $_REQUEST['description']; - } - } elseif ($exception_type == 'php') { - $errors = array(); - // create php error report - $i = 0; - if (!isset($_SESSION['prev_errors']) - || $_SESSION['prev_errors'] == '' - ) { - return array(); - } - foreach ($_SESSION['prev_errors'] as $errorObj) { - /* @var $errorObj PhpMyAdmin\Error */ - if ($errorObj->getLine() - && $errorObj->getType() - && $errorObj->getNumber() != E_USER_WARNING - ) { - $errors[$i++] = array( - "lineNum" => $errorObj->getLine(), - "file" => $errorObj->getFile(), - "type" => $errorObj->getType(), - "msg" => $errorObj->getOnlyMessage(), - "stackTrace" => $errorObj->getBacktrace(5), - "stackhash" => $errorObj->getHash() - ); - - } - } - - // if there were no 'actual' errors to be submitted. - if ($i==0) { - return array(); // then return empty array - } - $report ["exception_type"] = 'php'; - $report["errors"] = $errors; - } else { - return array(); - } - - return $report; -} - -/** - * Sanitize a url to remove the identifiable host name and extract the - * current script name from the url fragment - * - * It returns two things in an array. The first is the uri without the - * hostname and identifying query params. The second is the name of the - * php script in the url - * - * @param String $url the url to sanitize - * - * @return array the uri and script name - */ -function PMA_sanitizeUrl($url) -{ - $components = parse_url($url); - if (isset($components["fragment"]) - && preg_match("", $components["fragment"], $matches) - ) { - $uri = str_replace($matches[0], "", $components["fragment"]); - $url = "https://example.com/" . $uri; - $components = parse_url($url); - } - - // get script name - preg_match("<([a-zA-Z\-_\d]*\.php)$>", $components["path"], $matches); - if (count($matches) < 2) { - $script_name = 'index.php'; - } else { - $script_name = $matches[1]; - } - - // remove deployment specific details to make uri more generic - if (isset($components["query"])) { - parse_str($components["query"], $query_array); - unset($query_array["db"]); - unset($query_array["table"]); - unset($query_array["token"]); - unset($query_array["server"]); - $query = http_build_query($query_array); - } else { - $query = ''; - } - - $uri = $script_name . "?" . $query; - return array($uri, $script_name); -} - -/** - * Sends report data to the error reporting server - * - * @param array $report the report info to be sent - * - * @return String the reply of the server - */ -function PMA_sendErrorReport($report) -{ - $response = PhpMyAdmin\Util::httpRequest( - SUBMISSION_URL, - "POST", - false, - json_encode($report), - "Content-Type: application/json" - ); - return $response; -} - -/** - * Returns number of lines in given javascript file. - * - * @param string $filename javascript filename - * - * @return Number of lines - * - * @todo Should gracefully handle non existing files - */ -function PMA_countLines($filename) -{ - global $LINE_COUNT; - if (defined('LINE_COUNTS')) { - return $LINE_COUNT[$filename]; - } - - // ensure that the file is inside the phpMyAdmin folder - $depath = 1; - foreach (explode('/', $filename) as $part) { - if ($part == '..') { - $depath--; - } elseif ($part != '.' || $part === '') { - $depath++; - } - if ($depath < 0) { - return 0; - } - } - - $linecount = 0; - $handle = fopen('./js/' . $filename, 'r'); - while (!feof($handle)) { - $line = fgets($handle); - if ($line === false) { - break; - } - $linecount++; - } - fclose($handle); - return $linecount; -} - -/** - * returns the translated line number and the file name from the cumulative line - * number and an array of files - * - * uses the $LINE_COUNT global array of file names and line numbers - * - * @param array $filenames list of files in order of concatenation - * @param Integer $cumulative_number the cumulative line number in the - * concatenated files - * - * @return array the filename and line number - * Returns two variables in an array: - * - A String $filename the filename where the requested cumulative number - * exists - * - Integer $linenumber the translated line number in the returned file - */ -function PMA_getLineNumber($filenames, $cumulative_number) -{ - $cumulative_sum = 0; - foreach ($filenames as $filename) { - $filecount = PMA_countLines($filename); - if ($cumulative_number <= $cumulative_sum + $filecount + 2) { - $linenumber = $cumulative_number - $cumulative_sum; - break; - } - $cumulative_sum += $filecount + 2; - } - if (! isset($filename)) { - $filename = ''; - } - return array($filename, $linenumber); -} - -/** - * translates the cumulative line numbers in the stack trace as well as sanitize - * urls and trim long lines in the context - * - * @param array $stack the stack trace - * - * @return array $stack the modified stack trace - */ -function PMA_translateStacktrace($stack) -{ - foreach ($stack as &$level) { - foreach ($level["context"] as &$line) { - if (mb_strlen($line) > 80) { - $line = mb_substr($line, 0, 75) . "//..."; - } - } - if (preg_match("", $level["url"], $matches)) { - parse_str($matches[1], $vars); - List($file_name, $line_number) = PMA_getLineNumber( - $vars["scripts"], $level["line"] - ); - $level["filename"] = $file_name; - $level["line"] = $line_number; - } else { - unset($level["context"]); - List($uri, $script_name) = PMA_sanitizeUrl($level["url"]); - $level["uri"] = $uri; - $level["scriptname"] = $script_name; - } - unset($level["url"]); - } - unset($level); - return $stack; -} - -/** - * generates the error report form to collect user description and preview the - * report before being sent - * - * @return String the form - */ -function PMA_getErrorReportForm() -{ - $datas = array( - 'report_data' => PMA_getPrettyReportData(), - 'hidden_inputs' => Url::getHiddenInputs(), - 'hidden_fields' => null, - ); - - $reportData = PMA_getReportData(); - if (!empty($reportData)) { - $datas['hidden_fields'] = Url::getHiddenFields($reportData); - } - - return PhpMyAdmin\Template::get('error/report_form') - ->render($datas); -}