PageRenderTime 46ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/test/classes/ErrorReportTest.php

http://github.com/phpmyadmin/phpmyadmin
PHP | 364 lines | 314 code | 31 blank | 19 comment | 0 complexity | 846f3c2e1db25b94470486fa33a33fc9 MD5 | raw file
Possible License(s): GPL-2.0, MIT, LGPL-3.0
  1. <?php
  2. declare(strict_types=1);
  3. namespace PhpMyAdmin\Tests;
  4. use PhpMyAdmin\Error;
  5. use PhpMyAdmin\ErrorReport;
  6. use PhpMyAdmin\Relation;
  7. use PhpMyAdmin\Template;
  8. use PhpMyAdmin\Utils\HttpRequest;
  9. use PhpMyAdmin\Version;
  10. use function htmlspecialchars;
  11. use function json_encode;
  12. use function phpversion;
  13. use const ENT_QUOTES;
  14. use const JSON_PRETTY_PRINT;
  15. use const JSON_UNESCAPED_SLASHES;
  16. /**
  17. * @covers \PhpMyAdmin\ErrorReport
  18. */
  19. class ErrorReportTest extends AbstractTestCase
  20. {
  21. /** @var ErrorReport $errorReport */
  22. private $errorReport;
  23. protected function setUp(): void
  24. {
  25. parent::setUp();
  26. $GLOBALS['server'] = 1;
  27. $GLOBALS['cfg']['ServerDefault'] = 1;
  28. $GLOBALS['cfg']['ProxyUrl'] = '';
  29. $GLOBALS['cfg']['ProxyUser'] = '';
  30. $GLOBALS['cfg']['ProxyPass'] = '';
  31. $_SERVER['SERVER_SOFTWARE'] = 'SERVER_SOFTWARE';
  32. $_SERVER['HTTP_USER_AGENT'] = 'HTTP_USER_AGENT';
  33. $_COOKIE['pma_lang'] = 'en';
  34. $GLOBALS['config']->set('is_https', false);
  35. $template = new Template();
  36. $this->errorReport = new ErrorReport(
  37. new HttpRequest(),
  38. new Relation(null, $template),
  39. $template,
  40. $GLOBALS['config']
  41. );
  42. $this->errorReport->setSubmissionUrl('http://localhost');
  43. }
  44. public function testGetData(): void
  45. {
  46. $actual = $this->errorReport->getData('unknown');
  47. $this->assertEquals([], $actual);
  48. $actual = $this->errorReport->getData('php');
  49. $this->assertEquals([], $actual);
  50. $_SESSION['prev_errors'] = [];
  51. $actual = $this->errorReport->getData('php');
  52. $this->assertEquals([], $actual);
  53. $_SESSION['prev_errors'] = [
  54. new Error(0, 'error 0', 'file', 1),
  55. new Error(1, 'error 1', 'file', 2),
  56. ];
  57. $report = [
  58. 'pma_version' => Version::VERSION,
  59. 'browser_name' => $GLOBALS['config']->get('PMA_USR_BROWSER_AGENT'),
  60. 'browser_version' => $GLOBALS['config']->get('PMA_USR_BROWSER_VER'),
  61. 'user_os' => $GLOBALS['config']->get('PMA_USR_OS'),
  62. 'server_software' => $_SERVER['SERVER_SOFTWARE'],
  63. 'user_agent_string' => $_SERVER['HTTP_USER_AGENT'],
  64. 'locale' => $_COOKIE['pma_lang'],
  65. 'configuration_storage' => 'disabled',
  66. 'php_version' => phpversion(),
  67. 'exception_type' => 'php',
  68. 'errors' => [
  69. 0 => [
  70. 'lineNum' => $_SESSION['prev_errors'][0]->getLine(),
  71. 'file' => $_SESSION['prev_errors'][0]->getFile(),
  72. 'type' => $_SESSION['prev_errors'][0]->getType(),
  73. 'msg' => $_SESSION['prev_errors'][0]->getOnlyMessage(),
  74. 'stackTrace' => $_SESSION['prev_errors'][0]->getBacktrace(5),
  75. 'stackhash' => $_SESSION['prev_errors'][0]->getHash(),
  76. ],
  77. 1 => [
  78. 'lineNum' => $_SESSION['prev_errors'][1]->getLine(),
  79. 'file' => $_SESSION['prev_errors'][1]->getFile(),
  80. 'type' => $_SESSION['prev_errors'][1]->getType(),
  81. 'msg' => $_SESSION['prev_errors'][1]->getOnlyMessage(),
  82. 'stackTrace' => $_SESSION['prev_errors'][1]->getBacktrace(5),
  83. 'stackhash' => $_SESSION['prev_errors'][1]->getHash(),
  84. ],
  85. ],
  86. ];
  87. $actual = $this->errorReport->getData('php');
  88. $this->assertEquals($report, $actual);
  89. }
  90. public function testSend(): void
  91. {
  92. $submissionUrl = 'http://localhost';
  93. $report = [];
  94. $return = 'return';
  95. $httpRequest = $this->getMockBuilder(HttpRequest::class)
  96. ->onlyMethods(['create'])
  97. ->getMock();
  98. $httpRequest->expects($this->once())
  99. ->method('create')
  100. ->with(
  101. $submissionUrl,
  102. 'POST',
  103. false,
  104. json_encode($report),
  105. 'Content-Type: application/json'
  106. )
  107. ->willReturn($return);
  108. $template = new Template();
  109. $this->errorReport = new ErrorReport(
  110. $httpRequest,
  111. new Relation(null, $template),
  112. $template,
  113. $GLOBALS['config']
  114. );
  115. $this->errorReport->setSubmissionUrl($submissionUrl);
  116. $this->assertEquals($return, $this->errorReport->send($report));
  117. }
  118. public function testGetForm(): void
  119. {
  120. $_POST['exception'] = [];
  121. $form = $this->errorReport->getForm();
  122. $this->assertStringContainsString('<pre class="pre-scrollable">[]</pre>', $form);
  123. $context = [
  124. 'Widget.prototype = {',
  125. ' close: function() {',
  126. ' if (this.completion.widget != this) return;',
  127. ' this.completion.widget = null;',
  128. ' this.hints.parentNode.removeChild(this.hints);',
  129. ' this.completion.cm.removeKeyMap(this.keyMap);',
  130. '',
  131. ' var cm = this.completion.cm;',
  132. ' if (this.completion.options.closeOnUnfocus) {',
  133. ' cm.off("blur", this.onBlur);',
  134. ];
  135. $_POST['exception'] = [
  136. 'mode' => 'stack',
  137. 'name' => 'TypeError',
  138. 'message' => 'Cannot read property \'removeChild\' of null',
  139. 'stack' => [
  140. [
  141. 'url' => 'http://pma.7.3.local/js/vendor/codemirror/addon/hint/show-hint.js?v=4.8.6-dev',
  142. 'func' => 'Widget.close',
  143. 'line' => 307,
  144. 'column' => 29,
  145. 'context' => $context,
  146. ],
  147. ],
  148. 'url' => 'http://pma.7.3.local/index.php?route=/table/sql&db=aaaaa&table=a&server=14',
  149. ];
  150. $_POST['description'] = 'description';
  151. $report = [
  152. 'pma_version' => Version::VERSION,
  153. 'browser_name' => $GLOBALS['config']->get('PMA_USR_BROWSER_AGENT'),
  154. 'browser_version' => $GLOBALS['config']->get('PMA_USR_BROWSER_VER'),
  155. 'user_os' => $GLOBALS['config']->get('PMA_USR_OS'),
  156. 'server_software' => $_SERVER['SERVER_SOFTWARE'],
  157. 'user_agent_string' => $_SERVER['HTTP_USER_AGENT'],
  158. 'locale' => $_COOKIE['pma_lang'],
  159. 'configuration_storage' => 'disabled',
  160. 'php_version' => phpversion(),
  161. 'script_name' => 'index.php',
  162. 'exception_type' => 'js',
  163. 'exception' => [
  164. 'mode' => 'stack',
  165. 'name' => 'TypeError',
  166. 'message' => 'Cannot read property \'removeChild\' of null',
  167. 'stack' => [
  168. [
  169. 'func' => 'Widget.close',
  170. 'line' => 307,
  171. 'column' => 29,
  172. 'context' => $context,
  173. 'uri' => 'js/vendor/codemirror/addon/hint/show-hint.js?v=4.8.6-dev',
  174. 'scriptname' => 'js/vendor/codemirror/addon/hint/show-hint.js',
  175. ],
  176. ],
  177. 'uri' => 'index.php?route=%2Ftable%2Fsql',
  178. ],
  179. 'steps' => $_POST['description'],
  180. ];
  181. $expectedData = json_encode($report, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
  182. $form = $this->errorReport->getForm();
  183. $this->assertStringContainsString(
  184. '<pre class="pre-scrollable">' . htmlspecialchars((string) $expectedData, ENT_QUOTES) . '</pre>',
  185. $form
  186. );
  187. }
  188. public function testTruncateJsTrace(): void
  189. {
  190. $context = [
  191. ' success: function (response) {',
  192. ' Functions.ajaxRemoveMessage($msgbox);',
  193. ' if (response.success) {',
  194. ' // Get the column min value.',
  195. ' var min = response.column_data.min',
  196. ' ? \'(\' + Messages.strColumnMin +',
  197. ' this.completion.cm.removeKeyMap(this.keyMap);',
  198. ' \' \' + response.column_data.min + \')\'',
  199. ' : \'\';',
  200. ' if (this.completion.options.closeOnUnfocus) {',
  201. ' cm.off("blur", this.onBlur);',
  202. ];
  203. $data = [
  204. 'mode' => 'stack',
  205. 'name' => 'TypeError',
  206. 'message' => 'Cannot read property \'removeChild\' of null',
  207. 'stack' => [
  208. [
  209. 'url' => 'http://pma.7.3.local/js/vendor/codemirror/addon/hint/show-hint.js?v=4.8.6-dev',
  210. 'func' => 'Widget.close',
  211. 'line' => 307,
  212. 'column' => 29,
  213. 'context' => $context,
  214. ],
  215. [
  216. 'func' => 'Object.fireWith [as resolveWith]',
  217. 'line' => '2',
  218. 'column' => '29039',
  219. 'context' => [
  220. '/*! jQuery v3.5.1 | (c) JS Foundation and other contributors | jquery.org/license */',
  221. '!function(e,t){"use strict";"object"==typeof module&&'
  222. . '"object"==typeof module.exports?module.exports=e.document?t',
  223. ],
  224. 'url' => 'js/vendor/jquery/jquery.min.js?v=5.1.0-rc2',
  225. 'scriptname' => 'js/vendor/jquery/jquery.min.js',
  226. ],
  227. ],
  228. 'url' => 'http://pma.7.3.local/index.php?route=/table/sql&db=aaaaa&table=a&server=14',
  229. ];
  230. $_POST['exception'] = $data;
  231. $actual = $this->errorReport->getData('js');
  232. // Adjust the data
  233. unset($data['stack'][0]['url']);
  234. $data['stack'][0]['uri'] = 'js/vendor/codemirror/addon/hint/show-hint.js?v=4.8.6-dev';
  235. $data['stack'][0]['scriptname'] = 'js/vendor/codemirror/addon/hint/show-hint.js';
  236. unset($data['stack'][1]['url']);
  237. $data['stack'][1]['uri'] = 'js/vendor/jquery/jquery.min.js?v=5.1.0-rc2';
  238. unset($data['url']);
  239. $data['uri'] = 'index.php?route=%2Ftable%2Fsql';
  240. $data['stack'][1]['context'][0] = '/*! jQuery v3.5.1 | (c) JS Foundation'
  241. . ' and other contributors | jquery.org/l//...';
  242. $data['stack'][1]['context'][1] = '!function(e,t){"use strict";"object"='
  243. . '=typeof module&&"object"==typeof modul//...';
  244. $this->assertEquals($data, $actual['exception']);
  245. }
  246. /**
  247. * The urls to be tested for sanitization
  248. *
  249. * @return array[]
  250. */
  251. public function urlsToSanitize(): array
  252. {
  253. return [
  254. [
  255. '',
  256. [
  257. 'index.php?',
  258. 'index.php',
  259. ],
  260. ],
  261. [
  262. 'http://localhost/js/vendor/codemirror/addon/hint/show-hint.js?v=4.8.6-dev',
  263. [
  264. 'js/vendor/codemirror/addon/hint/show-hint.js?v=4.8.6-dev',
  265. 'js/vendor/codemirror/addon/hint/show-hint.js',
  266. ],
  267. ],
  268. [
  269. 'http://pma.7.3.local/tbl_sql.php?db=aaaaa&table=a&server=14',
  270. [
  271. 'tbl_sql.php?',
  272. 'tbl_sql.php',
  273. ],
  274. ],
  275. [
  276. 'http://pma.7.3.local/tbl_sql.php?db=aaaaa;table=a;server=14',
  277. [
  278. 'tbl_sql.php?',
  279. 'tbl_sql.php',
  280. ],
  281. ],
  282. [
  283. 'https://pma.7.3.local/tbl_sql.php?db=aaaaa;table=a;server=14',
  284. [
  285. 'tbl_sql.php?',
  286. 'tbl_sql.php',
  287. ],
  288. ],
  289. [
  290. 'https://pma.7.3.local/fileDotPhp.php?db=aaaaa;table=a;server=14',
  291. [
  292. 'fileDotPhp.php?',
  293. 'fileDotPhp.php',
  294. ],
  295. ],
  296. [
  297. 'https://pma.7.3.local/secretFolder/fileDotPhp.php?db=aaaaa;table=a;server=14',
  298. [
  299. 'fileDotPhp.php?',
  300. 'fileDotPhp.php',
  301. ],
  302. ],
  303. [
  304. 'http://7.2.local/@williamdes/theREALphpMyAdminREPO/js/vendor/jquery/jquery-ui.min.js?v=5.0.0-dev',
  305. [
  306. 'js/vendor/jquery/jquery-ui.min.js?v=5.0.0-dev',
  307. 'js/vendor/jquery/jquery-ui.min.js',
  308. ],
  309. ],
  310. ];
  311. }
  312. /**
  313. * Test the url sanitization
  314. *
  315. * @param string $url The url to test
  316. * @param array $result The result
  317. *
  318. * @dataProvider urlsToSanitize
  319. */
  320. public function testSanitizeUrl(string $url, array $result): void
  321. {
  322. // $this->errorReport->sanitizeUrl
  323. $this->assertSame(
  324. $result,
  325. $this->callFunction(
  326. $this->errorReport,
  327. ErrorReport::class,
  328. 'sanitizeUrl',
  329. [$url]
  330. )
  331. );
  332. }
  333. }