FusionDirectory
php_setup.inc
Go to the documentation of this file.
1 <?php
2 /*
3  This code is part of FusionDirectory (http://www.fusiondirectory.org/)
4  Copyright (C) 2003-2010 Cajus Pollmeier
5  Copyright (C) 2011-2020 FusionDirectory
6 
7  This program is free software; you can redistribute it and/or modify
8  it under the terms of the GNU General Public License as published by
9  the Free Software Foundation; either version 2 of the License, or
10  (at your option) any later version.
11 
12  This program is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  GNU General Public License for more details.
16 
17  You should have received a copy of the GNU General Public License
18  along with this program; if not, write to the Free Software
19  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
20 */
21 
26 require_once('variables.inc');
27 require_once('class_URL.inc');
28 
32 function htmlescape (string $str): string
33 {
34  return htmlspecialchars($str, ENT_QUOTES | ENT_HTML5, 'UTF-8');
35 }
36 
40 function htmlunescape (string $html): string
41 {
42  return html_entity_decode($html, ENT_QUOTES | ENT_HTML5, 'UTF-8');
43 }
44 
45 function html_trace ($errstr = "")
46 {
47  static $hideArgs = [
48  'LDAP/init' => [3],
49  'userinfo/loginUser' => [1],
50  'change_password' => [1],
51  'cred_decrypt' => [0, 1],
52  'LDAP/__construct' => [1],
53  ];
54  if (!function_exists('debug_backtrace')) {
55  return ['', ''];
56  }
57  $trace = array_slice(debug_backtrace(), 1);
58 
59  $loc = '';
60  if (isset($trace[0]['file'])) {
61  $loc = ' - ' . _('File') . ': ' . $trace[0]['file'];
62  if (isset($trace[0]['line'])) {
63  $loc .= ' (' . _('Line') . ' ' . $trace[0]['line'] . ')';
64  }
65  }
66 
67  $return_html = '<table width="100%" style="background-color:#402005;color:white;border:2px solid red;border-spacing:0;border-collapse:collapse;">' .
68  '<tr><td colspan="3">' .
69  '<h1 style="color:white">' . htmlescape(_('PHP error') . ' "' . $errstr . '"' . $loc) . '</h1>' .
70  '</td></tr>';
71  $return_mailto = rawurlencode('=== Trace ===');
72  /* Generate trace history */
73  for ($index = 1, $c = count($trace); $index < $c; $index++) {
74  $ct = $trace[$index];
75  $loc = '';
76  $func = '';
77  if (isset($ct['class'])) {
78  $loc .= _('class') . ' ' . $ct['class'];
79  $func .= $ct['class'];
80  if (isset($ct['function'])) {
81  $loc .= ' / ';
82  $func .= '/';
83  }
84  }
85  if (isset($ct['function'])) {
86  $loc .= _('function') . ' ' . $ct['function'];
87  $func .= $ct['function'];
88  }
89  if (isset($ct['type'])) {
90  switch ($ct['type']) {
91  case '::':
92  $type = _('static');
93  break;
94 
95  case '->':
96  $type = _('method');
97  break;
98 
99  default:
100  $type = 'unknown';
101  break;
102  }
103  } else {
104  $type = '-';
105  }
106  $args = '';
107  if (isset($ct['args'])) {
108  if (isset($hideArgs[$func])) {
109  $hideArgsIndexes = $hideArgs[$func];
110  } else {
111  $hideArgsIndexes = [];
112  }
113  $f = function ($index, $arg) use (&$f, $hideArgsIndexes) {
114  static $i = 0;
115  if (($i == 0) && in_array($index, $hideArgsIndexes)) {
116  return '***';
117  }
118  if ($i > 4) {
119  return '…';
120  }
121  if (is_object($arg)) {
122  return 'CLASS:&nbsp;' . get_class($arg);
123  } elseif (is_array($arg)) { /* Avoid converting array to string errors */
124  $i++;
125  $ret = 'array(' . implode(',', array_map($f, array_keys($arg), $arg)) . ')';
126  $i--;
127  return $ret;
128  } else {
129  if (strlen("$arg") > 512) {
130  $arg = substr("$arg", 0, 512) . "…";
131  }
132  return '"' . htmlescape("$arg") . '"';
133  }
134  };
135  $args = implode(',', array_map($f, array_keys($ct['args']), $ct['args']));
136  }
137  if (empty($args)) {
138  $args = '-';
139  }
140  if (isset($ct['file'])) {
141  $file = $ct['file'];
142  } else {
143  $file = '';
144  }
145  if (isset($ct['line'])) {
146  $line = $ct['line'];
147  } else {
148  $line = '';
149  }
150  $color = ($index & 1) ? '#404040' : '606060';
151  $return_html .= "<tr style='background-color:$color'><td style='padding-left:20px' width=\"30%\">" . htmlescape(_("Trace") . "[$index]: $loc") . '</td>';
152  $return_html .= "<td>" . htmlescape(_("File") . ": $file (" . _('Line') . " $line)") . '</td><td width="10%">' . htmlescape(_("Type") . ": $type") . '</td></tr>';
153  $return_html .= "<tr style='background-color:$color'><td colspan=3 style='padding-left:20px;'>" . htmlescape(_("Arguments") . ": $args") . '</td></tr>';
154 
155  /* Add trace part to mailto body */
156  $return_mailto .= rawurlencode(
157  "\nTrace[" . $index . "]:" . $loc .
158  "\nFile : " . $file .
159  "\nLine : " . $line .
160  "\nType : " . $type .
161  "\n " . $args .
162  "\n");
163  }
164 
165  $return_html .= "</table>";
166  $return_mailto .= rawurlencode("=== /Trace ===");
167 
168  return [$return_html, $return_mailto];
169 }
170 
182 function gosaRaiseError ($errno, $errstr, $errfile, $errline)
183 {
184  global $error_collector, $config, $error_collector_mailto;
185 
186  // To avoid recursion - restore original error handler.
187  restore_error_handler();
188 
189  /* Return if error reporting is set to zero */
190  if (error_reporting() == 0) {
191  set_error_handler('gosaRaiseError', E_WARNING | E_NOTICE | E_USER_ERROR | E_USER_WARNING | E_USER_NOTICE | E_STRICT);
192  return FALSE;
193  }
194 
195  /* Workaround for buggy imap_open error outputs */
196  if (preg_match('/imap_open/', $errstr)) {
197  set_error_handler('gosaRaiseError', E_WARNING | E_NOTICE | E_USER_ERROR | E_USER_WARNING | E_USER_NOTICE | E_STRICT);
198  return;
199  }
200 
201  /* Hide ldap size limit messages */
202  if (preg_match('/ldap_error/', $errstr) && preg_match('/sizelimit/', $errstr)) {
203  set_error_handler('gosaRaiseError', E_WARNING | E_NOTICE | E_USER_ERROR | E_USER_WARNING | E_USER_NOTICE | E_STRICT);
204  return;
205  }
206 
207  /* Send all errors to logging class, except "Ldap : No such object" messages*/
208  if (class_exists('logging') && !preg_match('/No such object/', $errstr)) {
209  logging::log('error', 'php', $errfile, [], 'Type:' . $errno . ', Message:' . $errstr . ', File:' . $errfile . ', Line: ' . $errline);
210  }
211 
212  /* Error messages are hidden in FusionDirectory, so we only send them to the logging class and abort here */
213  if (isset($config->data) && $config->get_cfg_value('displayerrors') != 'TRUE') {
214  set_error_handler('gosaRaiseError', E_WARNING | E_NOTICE | E_USER_ERROR | E_USER_WARNING | E_USER_NOTICE | E_STRICT);
215  return;
216  }
217 
218  /* Create header as needed */
219  if ($error_collector == "") {
220 
221  $error_collector = '
222  <div class="error">
223  <table width="100%">
224  <tr>
225  <td>
226  <img src="geticon.php?context=status&amp;icon=dialog-warning&amp;size=16" alt="" class="center"/>&nbsp;
227  <strong style="font-size:14px">' .
228  htmlescape(_('Generating this page caused the PHP interpreter to raise some errors!')) . '
229  </strong>
230  </td>
231  <td align="right">
232  <button onClick="$(\'errorbox\').toggle();">' .
233  htmlescape(_('Toggle information')) . '
234  </button>
235  </td>
236  </tr>
237  </table>
238  </div>
239  <div id="errorbox" style="position:absolute; z-index:150; display: none;">';
240  }
241 
242  list($html_trace, $mailto_trace) = html_trace($errstr);
243  $error_collector .= $html_trace;
244 
245  /* Flush in case of fatal errors */
246  if (preg_match('/^fatal/i', $errstr) || (PHP_ERROR_FATAL == 'TRUE')) {
247  trigger_error("Source error: " . $errstr . " in " . $errfile . " on line " . $errline);
248  session::destroy('Fatal error');
249  if (PHP_ERROR_FATAL == 'TRUE') {
250  $error_collector = str_replace('display: none;', '', $error_collector);
251  }
252  echo $error_collector . "</div>";
253  flush();
254  exit;
255  }
256 
257  set_error_handler('gosaRaiseError', E_WARNING | E_NOTICE | E_USER_ERROR | E_USER_WARNING | E_USER_NOTICE | E_STRICT);
258 }
259 
265 function fusiondirectoryExceptionHandler (Throwable $throwable)
266 {
267  try {
268  logging::log('error', 'fatal', '', [], 'Uncaught ' . get_class($throwable) . ': ' . $throwable->getMessage());
269  } catch (Throwable $t) {
270  /* Ignore exceptions/errors here */
271  }
272 
273  try {
274  if ($throwable instanceof FatalError) {
275  $throwable->display();
276  } else {
277  $error = new FatalError(htmlescape(sprintf(_('Uncaught %s: %s'), get_class($throwable), $throwable->getMessage())), 0, $throwable);
278  $error->display();
279  }
280  } catch (Throwable $t) {
281  /* Minimal display if exceptions happens when building the pretty one */
282  echo 'Uncaught ' . get_class($throwable) . ': ' . $throwable->getMessage();
283  }
284 
285  exit(255);
286 }
287 
292 {
293 }
294 
295 /* Bail out for incompatible/old PHP versions */
296 if (!version_compare(phpversion(), PHP_MIN_VERSION, ">=")) {
297  echo "PHP version needs to be " . PHP_MIN_VERSION . " or above to run FusionDirectory. Aborted.";
298  exit();
299 }
300 
301 /* Set timezone */
302 date_default_timezone_set("GMT");
303 
304 /* Get base dir for reference */
305 $BASE_DIR = dirname(dirname(__FILE__));
306 $ROOT_DIR = $BASE_DIR . "/html";
307 error_reporting(E_ALL | E_STRICT);
308 
309 /* Register error handler */
310 $error_collector = "";
311 $error_collector_mailto = "";
312 
313 set_error_handler('gosaRaiseError', E_WARNING | E_NOTICE | E_USER_ERROR | E_USER_WARNING | E_USER_NOTICE | E_STRICT);
314 set_exception_handler('fusiondirectoryExceptionHandler');
315 
316 $variables_order = 'ES';
317 ini_set('track_vars', '1');
318 ini_set('display_errors', '1');
319 ini_set('report_memleaks', '1');
320 ini_set('include_path', ".:$BASE_DIR/include:" . PHP_DIR . ':' . PEAR_DIR);
321 
322 /* Do smarty setup */
323 require(SMARTY);
324 
325 $smarty = new Smarty;
326 
327 $smarty->setTemplateDir($BASE_DIR . '/ihtml/');
328 $smarty->caching = Smarty::CACHING_OFF;
329 $smarty->assign('css_files', []);
330 $smarty->assign('js_files', []);
331 
332 $smarty->registerPlugin('modifier', 'base64_encode', 'base64_encode');
333 
334 $smarty->php_handling = Smarty::PHP_REMOVE;
335 
336 /* Check for SSL connection */
337 $ssl = '';
338 if (!URL::sslOn()) {
339  $ssl = URL::getSslUrl();
340 }
const PHP_DIR(isset($_SERVER['CONFIG_FILE']))
php library path
const SMARTY(!defined("CONFIG_FILE"))
Allow setting the config file in the apache configuration e.g. SetEnv CONFIG_FILE fusiondirectory...
Definition: variables.inc:45
fusiondirectoryExceptionHandler(Throwable $throwable)
Catches throwables that no one catched.
Definition: php_setup.inc:265
htmlescape(string $str)
Escape string for HTML output.
Definition: php_setup.inc:32
const PEAR_DIR
php pear path
static destroy(string $reason='')
Destroy a session.
gosaRaiseError($errno, $errstr, $errfile, $errline)
Raise an error.
Definition: php_setup.inc:182
static log(string $action, string $objecttype, string $object, array $changes=[], string $result='')
logging method
const PHP_MIN_VERSION
Minimum PHP version.
Fatal error class. Does not extend FusionDirectoryError.
static getSslUrl()
Returns SSL URL to redirect to.
Definition: class_URL.inc:73
static sslOn()
Returns TRUE if SSL was used to contact FD, whether directly or through a proxy.
Definition: class_URL.inc:31
dummy_error_handler()
Dummy error handler.
Definition: php_setup.inc:291
htmlunescape(string $html)
Unescape string for HTML output, reverse of htmlescape.
Definition: php_setup.inc:40
const PHP_ERROR_FATAL
Toggle crashing on PHP error, used for test suites.