r4259 process.php: suppress extra text in soft error message
[racktables] / wwwroot / inc / exceptions.php
1 <?php
2
3 // The default approach is to treat an error as fatal, in which case
4 // some message is output and the user is left there. Inheriting classes
5 // represent more specific cases, some of which can be handled in a
6 // "softer" way (see below).
7 class RackTablesError extends Exception
8 {
9 const INTERNAL = 2;
10 const DB_WRITE_FAILED = 3;
11 const NOT_AUTHENTICATED = 4;
12 const NOT_AUTHORIZED = 5;
13 const MISCONFIGURED = 6;
14 protected final function genHTMLPage ($title, $text)
15 {
16 header ('Content-Type: text/html; charset=UTF-8');
17 echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">'."\n";
18 echo '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">'."\n";
19 echo "<head><title>${title}</title>";
20 echo "</head><body>${text}</body></html>";
21 }
22 public function dispatch()
23 {
24 $msgheader = array
25 (
26 self::NOT_AUTHENTICATED => 'Not authenticated',
27 self::MISCONFIGURED => 'Configuration error',
28 self::INTERNAL => 'Internal error',
29 self::DB_WRITE_FAILED => 'Database write failed',
30 self::NOT_AUTHORIZED => 'Permission denied',
31 );
32 $msgbody = array
33 (
34 self::NOT_AUTHENTICATED => '<h2>This system requires authentication. You should use a username and a password.</h2>',
35 self::MISCONFIGURED => '<h2>Configuration error</h2><br>' . $this->message,
36 self::INTERNAL => '<h2>Internal error</h2><br>' . $this->message,
37 self::DB_WRITE_FAILED => '<h2>Database write failed</h2><br>' . $this->message,
38 self::NOT_AUTHORIZED => '<h2>Permission denied</h2><br>' . $this->message,
39 );
40 switch ($this->code)
41 {
42 case self::NOT_AUTHENTICATED:
43 header ('WWW-Authenticate: Basic realm="' . getConfigVar ('enterprise') . ' RackTables access"');
44 header ("HTTP/1.1 401 Unauthorized");
45 case self::MISCONFIGURED:
46 case self::INTERNAL:
47 case self::DB_WRITE_FAILED:
48 case self::NOT_AUTHORIZED:
49 $this->genHTMLPage ($msgheader[$this->code], $msgbody[$this->code]);
50 break;
51 default:
52 throw new RackTablesError ('Dispatching error, unknown code ' . $this->code, RackTablesError::INTERNAL);
53 }
54 }
55 }
56
57 // this simplifies construction of RackTablesError, but is never caught
58 class EntityNotFoundException extends RackTablesError
59 {
60 function __construct($entity, $id)
61 {
62 parent::__construct ("Object '$entity'#'$id' does not exist");
63 }
64 public function dispatch()
65 {
66 RackTablesError::genHTMLPage ('Missing record', "<h2>Missing record</h2><br>" . $this->message);
67 }
68 }
69
70 // this simplifies construction of RackTablesError, but is never caught
71 class InvalidArgException extends RackTablesError
72 {
73 function __construct ($name, $value, $reason=NULL)
74 {
75 $message = "Argument '${name}' of value '".var_export($value,true)."' is invalid.";
76 if (!is_null($reason))
77 $message .= ' ('.$reason.')';
78 parent::__construct ($message, parent::INTERNAL);
79 }
80 }
81
82 // this simplifies construction and helps in catching "soft"
83 // errors (invalid input from the user)
84 class InvalidRequestArgException extends RackTablesError
85 {
86 function __construct ($name, $value, $reason=NULL)
87 {
88 $message = "Argument '${name}' of value " . var_export ($value, TRUE) . " is invalid";
89 if (!is_null($reason))
90 $message .= ' ('.$reason.')';
91 $message .= '.';
92 parent::__construct ($message);
93 }
94 public function dispatch()
95 {
96 RackTablesError::genHTMLPage ('Assertion failed', '<h2>Assertion failed</h2><br>' . $this->message);
97 }
98 }
99
100 // this wraps certain known PDO errors and is caught in process.php
101 // as a "soft" error
102 class RTDatabaseError extends RackTablesError
103 {
104 public function dispatch()
105 {
106 RackTablesError::genHTMLPage ('Database soft error', '<h2>Database soft error</h2><br>' . $this->message);
107 }
108 }
109
110 // gateway failure is a common case of a "soft" error, some functions do catch this
111 class RTGatewayError extends RackTablesError
112 {
113 public function dispatch()
114 {
115 RackTablesError::genHTMLPage ('Gateway error', '<h2>Gateway error</h2><br>' . $this->message);
116 }
117 }
118
119 class RTBuildLVSConfigError extends RackTablesError
120 {
121 public $message_list;
122 public $config_to_display;
123 public $balancer_id;
124 function __construct($message_list, $config_to_display, $object_id) {
125 $this->code = parent::INTERNAL;
126 $this->message_list = $message_list;
127 $this->config_to_display = $config_to_display;
128 $this->balancer_id = $object_id;
129 parent::__construct("LVS config build error for balancer $object_id: " . implode("\n", $message_list));
130 }
131 public function dispatch()
132 {
133 // redirect user to a page with config errors highlighted
134 header ("Location: index.php?page=object&tab=lvsconfig&object_id=" . urlencode ($this->balancer_id));
135 die;
136 }
137 }
138
139 function dumpArray($arr)
140 {
141 echo '<table class="exceptionParametersDump">';
142 foreach($arr as $key=>$value)
143 {
144 echo "<tr><th>$key</th><td>$value</td></tr>";
145 }
146 echo '</table>';
147 }
148
149 function stringTrace($trace)
150 {
151 $ret = '';
152 foreach($trace as $line) {
153 $ret .= $line['file'].':'.$line['line'].' '.$line['function'].'(';
154 $f = true;
155 if (isset($line['args']) and is_array($line['args'])) foreach ($line['args'] as $arg) {
156 if (!$f) $ret .= ', ';
157 if (is_string($arg))
158 $printarg = "'".$arg."'";
159 elseif (is_null($arg))
160 $printarg = 'NULL';
161 elseif (is_array($arg))
162 $printarg = print_r($arg, 1);
163 else
164 $printarg = $arg;
165 $ret .= $printarg;
166 $f = false;
167 }
168 $ret .= ")\n";
169 }
170 return $ret;
171 }
172
173 function printPDOException($e)
174 {
175 header("HTTP/1.1 500 Internal Server Error");
176 header ('Content-Type: text/html; charset=UTF-8');
177 echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">'."\n";
178 echo '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">'."\n";
179 echo "<head><title> PDO Exception </title>\n";
180 echo '</head> <body>';
181 echo '<h2>Pdo exception: '.get_class($e).'</h2><code>'.$e->getMessage().'</code> (<code>'.$e->getCode().'</code>)';
182 echo '<p>at file <code>'.$e->getFile().'</code>, line <code>'.$e->getLine().'</code></p><pre>';
183 echo stringTrace($e->getTrace());
184 echo '</pre>';
185 echo '<h2>Error info:</h2>';
186 echo '<pre>';
187 print_r($e->errorInfo);
188 echo '</pre>';
189 echo '<h2>Parameters:</h2>';
190 echo '<h3>GET</h3>';
191 dumpArray($_GET);
192 echo '<h3>POST</h3>';
193 dumpArray($_POST);
194 echo '<h3>COOKIE</h3>';
195 dumpArray($_COOKIE);
196 echo '</body></html>';
197
198 }
199
200 function printGenericException($e)
201 {
202 header("HTTP/1.1 500 Internal Server Error");
203 header ('Content-Type: text/html; charset=UTF-8');
204 echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">'."\n";
205 echo '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">'."\n";
206 echo "<head><title> Exception </title>\n";
207 echo "<link rel=stylesheet type='text/css' href=pi.css />\n";
208 echo "<link rel=icon href='favicon.ico' type='image/x-icon' />";
209 echo '</head> <body>';
210 echo '<h2>Uncaught exception: '.get_class($e).'</h2><code>'.$e->getMessage().'</code> (<code>'.$e->getCode().'</code>)';
211 echo '<p>at file <code>'.$e->getFile().'</code>, line <code>'.$e->getLine().'</code></p><pre>';
212 echo stringTrace($e->getTrace());
213 echo '</pre>';
214 echo '<h2>Parameters:</h2>';
215 echo '<h3>GET</h3>';
216 dumpArray($_GET);
217 echo '<h3>POST</h3>';
218 dumpArray($_POST);
219 echo '<h3>COOKIE</h3>';
220 dumpArray($_COOKIE);
221 echo '</body></html>';
222
223 }
224
225 function printException($e)
226 {
227 if ($e instanceof RackTablesError)
228 $e->dispatch();
229 elseif (get_class($e) == 'PDOException')
230 printPDOException($e);
231 else
232 printGenericException($e);
233 }
234
235 ?>