1<?php
2/**
3 * PSI_Error class
4 *
5 * PHP version 5
6 *
7 * @category  PHP
8 * @package   PSI_Error
9 * @author    Michael Cramer <BigMichi1@users.sourceforge.net>
10 * @copyright 2009 phpSysInfo
11 * @license   http://opensource.org/licenses/gpl-2.0.php GNU General Public License version 2, or (at your option) any later version
12 * @version   SVN: $Id: class.Error.inc.php 569 2012-04-16 06:08:18Z namiltd $
13 * @link      http://phpsysinfo.sourceforge.net
14 */
15 /**
16 * class for the error handling in phpsysinfo
17 *
18 * @category  PHP
19 * @package   PSI_Error
20 * @author    Michael Cramer <BigMichi1@users.sourceforge.net>
21 * @copyright 2009 phpSysInfo
22 * @license   http://opensource.org/licenses/gpl-2.0.php GNU General Public License version 2, or (at your option) any later version
23 * @version   Release: 3.0
24 * @link      http://phpsysinfo.sourceforge.net
25 */
26class PSI_Error
27{
28    /**
29     * holds the instance of this class
30     *
31     * @static
32     * @var PSI_Error
33     */
34    private static $_instance;
35
36    /**
37     * holds the error messages
38     *
39     * @var array
40     */
41    private $_arrErrorList = array();
42
43    /**
44     * current number ob errors
45     *
46     * @var integer
47     */
48    private $_errors = 0;
49
50    /**
51     * initalize some used vars
52     */
53    private function __construct()
54    {
55        $this->_errors = 0;
56        $this->_arrErrorList = array();
57    }
58
59    /**
60     * Singleton function
61     *
62     * @return PSI_Error instance of the class
63     */
64    public static function singleton()
65    {
66        if (!isset(self::$_instance)) {
67            $c = __CLASS__;
68            self::$_instance = new $c;
69        }
70
71        return self::$_instance;
72    }
73
74    /**
75     * triggers an error when somebody tries to clone the object
76     *
77     * @return void
78     */
79    public function __clone()
80    {
81        trigger_error("Can't be cloned", E_USER_ERROR);
82    }
83
84    /**
85     * adds an phpsysinfo error to the internal list
86     *
87     * @param string $strCommand Command, which cause the Error
88     * @param string $strMessage additional Message, to describe the Error
89     *
90     * @return void
91     */
92    public function addError($strCommand, $strMessage)
93    {
94        $this->_addError($strCommand, $this->_trace($strMessage));
95    }
96
97    /**
98     * adds an error to the internal list
99     *
100     * @param string $strCommand Command, which cause the Error
101     * @param string $strMessage message, that describe the Error
102     *
103     * @return void
104     */
105    private function _addError($strCommand, $strMessage)
106    {
107        $index = count($this->_arrErrorList) + 1;
108        $this->_arrErrorList[$index]['command'] = $strCommand;
109        $this->_arrErrorList[$index]['message'] = $strMessage;
110        $this->_errors++;
111    }
112
113    /**
114     * add a config error to the internal list
115     *
116     * @param string $strCommand Command, which cause the Error
117     * @param string $strMessage additional Message, to describe the Error
118     *
119     * @return void
120     */
121    public function addConfigError($strCommand, $strMessage)
122    {
123        $this->_addError($strCommand, "Wrong Value in phpsysinfo.ini for ".$strMessage);
124    }
125
126    /**
127     * add a php error to the internal list
128     *
129     * @param string $strCommand Command, which cause the Error
130     * @param string $strMessage additional Message, to describe the Error
131     *
132     * @return void
133     */
134    public function addPhpError($strCommand, $strMessage)
135    {
136        $this->_addError($strCommand, "PHP throws a error\n".$strMessage);
137    }
138
139    /**
140     * adds a waraning to the internal list
141     *
142     * @param string $strMessage Warning message to display
143     *
144     * @return void
145     */
146    public function addWarning($strMessage)
147    {
148        $index = count($this->_arrErrorList) + 1;
149        $this->_arrErrorList[$index]['command'] = "WARN";
150        $this->_arrErrorList[$index]['message'] = $strMessage;
151    }
152
153    /**
154     * converts the internal error and warning list to a XML file
155     *
156     * @return void
157     */
158    public function errorsAsXML()
159    {
160        $dom = new DOMDocument('1.0', 'UTF-8');
161        $root = $dom->createElement("phpsysinfo");
162        $dom->appendChild($root);
163        $xml = new SimpleXMLExtended(simplexml_import_dom($dom), 'UTF-8');
164        $generation = $xml->addChild('Generation');
165        $generation->addAttribute('version', PSI_VERSION_STRING);
166        $generation->addAttribute('timestamp', time());
167        $xmlerr = $xml->addChild("Errors");
168        foreach ($this->_arrErrorList as $arrLine) {
169//            $error = $xmlerr->addCData('Error', $arrLine['message']);
170            $error = $xmlerr->addChild('Error');
171            $error->addAttribute('Message', $arrLine['message']);
172            $error->addAttribute('Function', $arrLine['command']);
173        }
174        header("Cache-Control: no-cache, must-revalidate\n");
175        header("Content-Type: text/xml\n\n");
176        echo $xml->getSimpleXmlElement()->asXML();
177        exit();
178    }
179    /**
180     * add the errors to an existing xml document
181     *
182     * @param String $encoding encoding
183     *
184     * @return SimpleXmlElement
185     */
186    public function errorsAddToXML($encoding)
187    {
188        $dom = new DOMDocument('1.0', 'UTF-8');
189        $root = $dom->createElement("Errors");
190        $dom->appendChild($root);
191        $xml = simplexml_import_dom($dom);
192        $xmlerr = new SimpleXMLExtended($xml, $encoding);
193        foreach ($this->_arrErrorList as $arrLine) {
194//            $error = $xmlerr->addCData('Error', $arrLine['message']);
195            $error = $xmlerr->addChild('Error');
196            $error->addAttribute('Message', $arrLine['message']);
197            $error->addAttribute('Function', $arrLine['command']);
198        }
199
200        return $xmlerr->getSimpleXmlElement();
201    }
202    /**
203     * check if errors exists
204     *
205     * @return boolean true if are errors logged, false if not
206     */
207    public function errorsExist()
208    {
209        if ($this->_errors > 0) {
210            return true;
211        } else {
212            return false;
213        }
214    }
215    /**
216     * generate a function backtrace for error diagnostic, function is genearally based on code submitted in the php reference page
217     *
218     * @param string $strMessage additional message to display
219     *
220     * @return string formatted string of the backtrace
221     */
222    private function _trace($strMessage)
223    {
224        $arrTrace = array_reverse(debug_backtrace());
225        $strFunc = '';
226        $strBacktrace = htmlspecialchars($strMessage)."\n\n";
227        foreach ($arrTrace as $val) {
228            // avoid the last line, which says the error is from the error class
229            if ($val == $arrTrace[count($arrTrace) - 1]) {
230                break;
231            }
232            if (isset($val['file'])) {
233                $strBacktrace .= str_replace(PSI_APP_ROOT, ".", $val['file']).' on line '.$val['line'];
234            }
235            if ($strFunc) {
236                $strBacktrace .= ' in function '.$strFunc;
237            }
238            if ($val['function'] == 'include' || $val['function'] == 'require' || $val['function'] == 'include_once' || $val['function'] == 'require_once') {
239                $strFunc = '';
240            } else {
241                $strFunc = $val['function'].'(';
242                if (isset($val['args'][0])) {
243                    $strFunc .= ' ';
244                    $strComma = '';
245                    foreach ($val['args'] as $valArgs) {
246                        $strFunc .= $strComma.$this->_printVar($valArgs);
247                        $strComma = ', ';
248                    }
249                    $strFunc .= ' ';
250                }
251                $strFunc .= ')';
252            }
253            $strBacktrace .= "\n";
254        }
255
256        return $strBacktrace;
257    }
258    /**
259     * convert some special vars into better readable output
260     *
261     * @param mixed $var value, which should be formatted
262     *
263     * @return string formatted string
264     */
265    private function _printVar($var)
266    {
267        if (is_string($var)) {
268            $search = array("\x00", "\x0a", "\x0d", "\x1a", "\x09");
269            $replace = array('\0', '\n', '\r', '\Z', '\t');
270
271            return ('"'.str_replace($search, $replace, $var).'"');
272        } elseif (is_bool($var)) {
273            if ($var) {
274                return ('true');
275            } else {
276                return ('false');
277            }
278        } elseif (is_array($var)) {
279            $strResult = 'array( ';
280            $strComma = '';
281            foreach ($var as $key=>$val) {
282                $strResult .= $strComma.$this->_printVar($key).' => '.$this->_printVar($val);
283                $strComma = ', ';
284            }
285            $strResult .= ' )';
286
287            return ($strResult);
288        }
289        // anything else, just let php try to print it
290        return (var_export($var, true));
291    }
292}
293