r3887 copy most recent commits from maintenance into trunk
[racktables] / inc / exceptions.php
CommitLineData
b135a49d
DY
1<?php
2
3a089a44
DO
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).
7class 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)
b135a49d 15 {
3a089a44
DO
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>";
b135a49d 21 }
3a089a44 22 public function dispatch()
b135a49d 23 {
3a089a44
DO
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 }
b135a49d
DY
54 }
55}
e0c09e31 56
3a089a44
DO
57// this simplifies construction of RackTablesError, but is never caught
58class EntityNotFoundException extends RackTablesError
59{
60 function __construct($entity, $id)
c5f84f48 61 {
3a089a44 62 parent::__construct ("Object '$entity'#'$id' does not exist");
c5f84f48 63 }
3a089a44 64 public function dispatch()
c5f84f48 65 {
3a089a44 66 RackTablesError::genHTMLPage ('Missing record', "<h2>Missing record</h2><br>" . $this->message);
c5f84f48
DY
67 }
68}
69
3a089a44
DO
70// this simplifies construction of RackTablesError, but is never caught
71class InvalidArgException extends RackTablesError
94fe6370 72{
0cc24e9a
DY
73 function __construct ($name, $value, $reason=NULL)
74 {
75 $message = "Argument '${name}' of value '".var_export($value,true)."' is invalid.";
3a089a44 76 if (!is_null($reason))
0cc24e9a 77 $message .= ' ('.$reason.')';
3a089a44 78 parent::__construct ($message, parent::INTERNAL);
0cc24e9a
DY
79 }
80}
81
3a089a44
DO
82// this simplifies construction and helps in catching "soft"
83// errors (invalid input from the user)
84class InvalidRequestArgException extends RackTablesError
0cc24e9a 85{
0cc24e9a 86 function __construct ($name, $value, $reason=NULL)
c5f84f48 87 {
0cc24e9a 88 $message = "Request parameter '${name}' of value '".var_export($value,true)."' is invalid.";
3a089a44 89 if (!is_null($reason))
0cc24e9a 90 $message .= ' ('.$reason.')';
0cc24e9a 91 parent::__construct ($message);
c5f84f48 92 }
3a089a44 93 public function dispatch()
94fe6370 94 {
3a089a44 95 RackTablesError::genHTMLPage ('Assertion failed', '<h2>Assertion failed</h2><br>' . $this->message);
94fe6370 96 }
3a089a44
DO
97}
98
99// this wraps certain known PDO errors and is caught in process.php
100// as a "soft" error
ec523868 101class RTDatabaseError extends RackTablesError
3a089a44
DO
102{
103 public function dispatch()
104 {
ec523868 105 RackTablesError::genHTMLPage ('Database soft error', '<h2>Database soft error</h2><br>' . $this->message);
3a089a44
DO
106 }
107}
108
109// gateway failure is a common case of a "soft" error, some functions do catch this
110class RTGatewayError extends RackTablesError
111{
112 public function dispatch()
94fe6370 113 {
3a089a44 114 RackTablesError::genHTMLPage ('Gateway error', '<h2>Gateway error</h2><br>' . $this->message);
94fe6370
DO
115 }
116}
117
f77323f1
DO
118function dumpArray($arr)
119{
120 echo '<table class="exceptionParametersDump">';
121 foreach($arr as $key=>$value)
122 {
123 echo "<tr><th>$key</th><td>$value</td></tr>";
124 }
125 echo '</table>';
126}
127
e7aa0333
DY
128function stringTrace($trace)
129{
130 $ret = '';
131 foreach($trace as $line) {
132 $ret .= $line['file'].':'.$line['line'].' '.$line['function'].'(';
133 $f = true;
0cc24e9a 134 if (isset($line['args']) and is_array($line['args'])) foreach ($line['args'] as $arg) {
e7aa0333
DY
135 if (!$f) $ret .= ', ';
136 if (is_string($arg))
137 $printarg = "'".$arg."'";
138 elseif (is_null($arg))
139 $printarg = 'NULL';
140 elseif (is_array($arg))
141 $printarg = print_r($arg, 1);
142 else
143 $printarg = $arg;
144 $ret .= $printarg;
145 $f = false;
146 }
147 $ret .= ")\n";
148 }
149 return $ret;
150}
151
e7aa0333
DY
152function printPDOException($e)
153{
154 header("HTTP/1.1 500 Internal Server Error");
878512c6 155 header ('Content-Type: text/html; charset=UTF-8');
e7aa0333
DY
156 echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">'."\n";
157 echo '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">'."\n";
158 echo "<head><title> PDO Exception </title>\n";
e7aa0333
DY
159 echo '</head> <body>';
160 echo '<h2>Pdo exception: '.get_class($e).'</h2><code>'.$e->getMessage().'</code> (<code>'.$e->getCode().'</code>)';
161 echo '<p>at file <code>'.$e->getFile().'</code>, line <code>'.$e->getLine().'</code></p><pre>';
162 echo stringTrace($e->getTrace());
163 echo '</pre>';
164 echo '<h2>Error info:</h2>';
165 echo '<pre>';
166 print_r($e->errorInfo);
167 echo '</pre>';
168 echo '<h2>Parameters:</h2>';
169 echo '<h3>GET</h3>';
170 dumpArray($_GET);
171 echo '<h3>POST</h3>';
172 dumpArray($_POST);
173 echo '<h3>COOKIE</h3>';
174 dumpArray($_COOKIE);
175 echo '</body></html>';
176
177}
178
f77323f1
DO
179function printGenericException($e)
180{
181 header("HTTP/1.1 500 Internal Server Error");
878512c6 182 header ('Content-Type: text/html; charset=UTF-8');
f77323f1
DO
183 echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">'."\n";
184 echo '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">'."\n";
185 echo "<head><title> Exception </title>\n";
fffc0727 186 echo "<link rel=stylesheet type='text/css' href=pi.css />\n";
3540d15c 187 echo "<link rel=icon href='pix/racktables.ico' type='image/x-icon' />";
f77323f1
DO
188 echo '</head> <body>';
189 echo '<h2>Uncaught exception: '.get_class($e).'</h2><code>'.$e->getMessage().'</code> (<code>'.$e->getCode().'</code>)';
190 echo '<p>at file <code>'.$e->getFile().'</code>, line <code>'.$e->getLine().'</code></p><pre>';
e7aa0333 191 echo stringTrace($e->getTrace());
f77323f1
DO
192 echo '</pre>';
193 echo '<h2>Parameters:</h2>';
194 echo '<h3>GET</h3>';
195 dumpArray($_GET);
196 echo '<h3>POST</h3>';
197 dumpArray($_POST);
198 echo '<h3>COOKIE</h3>';
199 dumpArray($_COOKIE);
200 echo '</body></html>';
201
202}
203
204function printException($e)
205{
3a089a44
DO
206 if ($e instanceof RackTablesError)
207 $e->dispatch();
e7aa0333
DY
208 elseif (get_class($e) == 'PDOException')
209 printPDOException($e);
f77323f1
DO
210 else
211 printGenericException($e);
212}
213
e0c09e31 214?>