@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.)
hq.recaptime.dev/wiki/Phorge
phorge
phabricator
1<?php
2
3final class PhabricatorDefaultRequestExceptionHandler
4 extends PhabricatorRequestExceptionHandler {
5
6 public function getRequestExceptionHandlerPriority() {
7 return 900000;
8 }
9
10 public function getRequestExceptionHandlerDescription() {
11 return pht('Handles all other exceptions.');
12 }
13
14 public function canHandleRequestThrowable(
15 AphrontRequest $request,
16 $throwable) {
17
18 if (!$this->isPhabricatorSite($request)) {
19 return false;
20 }
21
22 return true;
23 }
24
25 public function handleRequestThrowable(
26 AphrontRequest $request,
27 $throwable) {
28
29 $viewer = $this->getViewer($request);
30
31 // Some types of uninteresting request exceptions don't get logged, usually
32 // because they are caused by the background radiation of bot traffic on
33 // the internet. These include requests with bad CSRF tokens and
34 // questionable "Host" headers.
35 $should_log = true;
36 if ($throwable instanceof AphrontMalformedRequestException) {
37 $should_log = !$throwable->getIsUnlogged();
38 }
39
40 if ($should_log) {
41 phlog($throwable);
42 }
43
44 $class = get_class($throwable);
45
46 if (PhabricatorEnv::getEnvConfig('phabricator.developer-mode')) {
47 // Include last location in error message
48 $message = '"'.$throwable->getMessage().'" at '.
49 PhutilErrorHandler::adjustFilePath($throwable->getFile()).
50 ':'.$throwable->getLine();
51 } else {
52 $message = $throwable->getMessage();
53 }
54
55 if ($throwable instanceof AphrontSchemaQueryException) {
56 $message .= "\n\n".pht(
57 "NOTE: This usually indicates that the MySQL schema has not been ".
58 "properly upgraded. Run '%s' to ensure your schema is up to date.",
59 'bin/storage upgrade');
60 }
61
62 if (PhabricatorEnv::getEnvConfig('phabricator.developer-mode')) {
63 $trace = id(new AphrontStackTraceView())
64 ->setViewer($viewer)
65 ->setTrace($throwable->getTrace());
66 } else {
67 $trace = null;
68 }
69
70 $content = phutil_tag(
71 'div',
72 array('class' => 'aphront-unhandled-exception'),
73 array(
74 phutil_tag('div', array('class' => 'exception-message'), $message),
75 $trace,
76 ));
77
78 $dialog = new AphrontDialogView();
79 $dialog
80 ->setTitle(pht('Unhandled Exception ("%s")', $class))
81 ->setClass('aphront-exception-dialog')
82 ->setViewer($viewer)
83 ->appendChild($content);
84
85 if ($request->isAjax()) {
86 $dialog->addCancelButton('/', pht('Close'));
87 }
88
89 return id(new AphrontDialogResponse())
90 ->setDialog($dialog)
91 ->setHTTPResponseCode(500);
92 }
93
94}