Translated using Weblate (Estonian)
[phpmyadmin.git] / libraries / error_report.lib.php
blob569651e798dae1ad225a5e163ccc90b4b074ad43
1 <?php
2 /* vim: set expandtab sw=4 ts=4 sts=4: */
3 /**
4 * Error reporting functions used to generate and submit error reports
6 * @package PhpMyAdmin
7 */
8 use PhpMyAdmin\Relation;
9 use PhpMyAdmin\Url;
11 if (! defined('PHPMYADMIN')) {
12 exit;
15 /**
16 * The generated file that contains the line numbers for the js files
17 * If you change any of the js files you can run the scripts/line-counts.sh
19 if (is_readable('js/line_counts.php')) {
20 include_once 'js/line_counts.php';
23 /**
24 * the url where to submit reports to
26 define('SUBMISSION_URL', "https://reports.phpmyadmin.net/incidents/create");
28 /**
29 * returns the pretty printed error report data collected from the
30 * current configuration or from the request parameters sent by the
31 * error reporting js code.
33 * @return String the report
35 function PMA_getPrettyReportData()
37 $report = PMA_getReportData();
39 return json_encode($report, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
42 /**
43 * returns the error report data collected from the current configuration or
44 * from the request parameters sent by the error reporting js code.
46 * @param string $exception_type whether exception is 'js' or 'php'
48 * @return array error report if success, Empty Array otherwise
50 function PMA_getReportData($exception_type = 'js')
52 $relParams = Relation::getRelationsParam();
53 // common params for both, php & js exceptions
54 $report = array(
55 "pma_version" => PMA_VERSION,
56 "browser_name" => PMA_USR_BROWSER_AGENT,
57 "browser_version" => PMA_USR_BROWSER_VER,
58 "user_os" => PMA_USR_OS,
59 "server_software" => $_SERVER['SERVER_SOFTWARE'],
60 "user_agent_string" => $_SERVER['HTTP_USER_AGENT'],
61 "locale" => $_COOKIE['pma_lang'],
62 "configuration_storage" =>
63 is_null($relParams['db']) ? "disabled" :
64 "enabled",
65 "php_version" => phpversion()
68 if ($exception_type == 'js') {
69 if (empty($_REQUEST['exception'])) {
70 return array();
72 $exception = $_REQUEST['exception'];
73 $exception["stack"] = PMA_translateStacktrace($exception["stack"]);
74 List($uri, $script_name) = PMA_sanitizeUrl($exception["url"]);
75 $exception["uri"] = $uri;
76 unset($exception["url"]);
78 $report ["exception_type"] = 'js';
79 $report ["exception"] = $exception;
80 $report ["script_name"] = $script_name;
81 $report ["microhistory"] = $_REQUEST['microhistory'];
83 if (! empty($_REQUEST['description'])) {
84 $report['steps'] = $_REQUEST['description'];
86 } elseif ($exception_type == 'php') {
87 $errors = array();
88 // create php error report
89 $i = 0;
90 if (!isset($_SESSION['prev_errors'])
91 || $_SESSION['prev_errors'] == ''
92 ) {
93 return array();
95 foreach ($_SESSION['prev_errors'] as $errorObj) {
96 /* @var $errorObj PhpMyAdmin\Error */
97 if ($errorObj->getLine()
98 && $errorObj->getType()
99 && $errorObj->getNumber() != E_USER_WARNING
101 $errors[$i++] = array(
102 "lineNum" => $errorObj->getLine(),
103 "file" => $errorObj->getFile(),
104 "type" => $errorObj->getType(),
105 "msg" => $errorObj->getOnlyMessage(),
106 "stackTrace" => $errorObj->getBacktrace(5),
107 "stackhash" => $errorObj->getHash()
113 // if there were no 'actual' errors to be submitted.
114 if ($i==0) {
115 return array(); // then return empty array
117 $report ["exception_type"] = 'php';
118 $report["errors"] = $errors;
119 } else {
120 return array();
123 return $report;
127 * Sanitize a url to remove the identifiable host name and extract the
128 * current script name from the url fragment
130 * It returns two things in an array. The first is the uri without the
131 * hostname and identifying query params. The second is the name of the
132 * php script in the url
134 * @param String $url the url to sanitize
136 * @return array the uri and script name
138 function PMA_sanitizeUrl($url)
140 $components = parse_url($url);
141 if (isset($components["fragment"])
142 && preg_match("<PMAURL-\d+:>", $components["fragment"], $matches)
144 $uri = str_replace($matches[0], "", $components["fragment"]);
145 $url = "https://example.com/" . $uri;
146 $components = parse_url($url);
149 // get script name
150 preg_match("<([a-zA-Z\-_\d]*\.php)$>", $components["path"], $matches);
151 if (count($matches) < 2) {
152 $script_name = 'index.php';
153 } else {
154 $script_name = $matches[1];
157 // remove deployment specific details to make uri more generic
158 if (isset($components["query"])) {
159 parse_str($components["query"], $query_array);
160 unset($query_array["db"]);
161 unset($query_array["table"]);
162 unset($query_array["token"]);
163 unset($query_array["server"]);
164 $query = http_build_query($query_array);
165 } else {
166 $query = '';
169 $uri = $script_name . "?" . $query;
170 return array($uri, $script_name);
174 * Sends report data to the error reporting server
176 * @param array $report the report info to be sent
178 * @return String the reply of the server
180 function PMA_sendErrorReport($report)
182 $response = PhpMyAdmin\Util::httpRequest(
183 SUBMISSION_URL,
184 "POST",
185 false,
186 json_encode($report),
187 "Content-Type: application/json"
189 return $response;
193 * Returns number of lines in given javascript file.
195 * @param string $filename javascript filename
197 * @return Number of lines
199 * @todo Should gracefully handle non existing files
201 function PMA_countLines($filename)
203 global $LINE_COUNT;
204 if (defined('LINE_COUNTS')) {
205 return $LINE_COUNT[$filename];
208 // ensure that the file is inside the phpMyAdmin folder
209 $depath = 1;
210 foreach (explode('/', $filename) as $part) {
211 if ($part == '..') {
212 $depath--;
213 } elseif ($part != '.' || $part === '') {
214 $depath++;
216 if ($depath < 0) {
217 return 0;
221 $linecount = 0;
222 $handle = fopen('./js/' . $filename, 'r');
223 while (!feof($handle)) {
224 $line = fgets($handle);
225 if ($line === false) {
226 break;
228 $linecount++;
230 fclose($handle);
231 return $linecount;
235 * returns the translated line number and the file name from the cumulative line
236 * number and an array of files
238 * uses the $LINE_COUNT global array of file names and line numbers
240 * @param array $filenames list of files in order of concatenation
241 * @param Integer $cumulative_number the cumulative line number in the
242 * concatenated files
244 * @return array the filename and line number
245 * Returns two variables in an array:
246 * - A String $filename the filename where the requested cumulative number
247 * exists
248 * - Integer $linenumber the translated line number in the returned file
250 function PMA_getLineNumber($filenames, $cumulative_number)
252 $cumulative_sum = 0;
253 foreach ($filenames as $filename) {
254 $filecount = PMA_countLines($filename);
255 if ($cumulative_number <= $cumulative_sum + $filecount + 2) {
256 $linenumber = $cumulative_number - $cumulative_sum;
257 break;
259 $cumulative_sum += $filecount + 2;
261 if (! isset($filename)) {
262 $filename = '';
264 return array($filename, $linenumber);
268 * translates the cumulative line numbers in the stack trace as well as sanitize
269 * urls and trim long lines in the context
271 * @param array $stack the stack trace
273 * @return array $stack the modified stack trace
275 function PMA_translateStacktrace($stack)
277 foreach ($stack as &$level) {
278 foreach ($level["context"] as &$line) {
279 if (mb_strlen($line) > 80) {
280 $line = mb_substr($line, 0, 75) . "//...";
283 if (preg_match("<js/get_scripts.js.php\?(.*)>", $level["url"], $matches)) {
284 parse_str($matches[1], $vars);
285 List($file_name, $line_number) = PMA_getLineNumber(
286 $vars["scripts"], $level["line"]
288 $level["filename"] = $file_name;
289 $level["line"] = $line_number;
290 } else {
291 unset($level["context"]);
292 List($uri, $script_name) = PMA_sanitizeUrl($level["url"]);
293 $level["uri"] = $uri;
294 $level["scriptname"] = $script_name;
296 unset($level["url"]);
298 unset($level);
299 return $stack;
303 * generates the error report form to collect user description and preview the
304 * report before being sent
306 * @return String the form
308 function PMA_getErrorReportForm()
310 $datas = array(
311 'report_data' => PMA_getPrettyReportData(),
312 'hidden_inputs' => Url::getHiddenInputs(),
313 'hidden_fields' => null,
316 $reportData = PMA_getReportData();
317 if (!empty($reportData)) {
318 $datas['hidden_fields'] = Url::getHiddenFields($reportData);
321 return PhpMyAdmin\Template::get('error/report_form')
322 ->render($datas);