1<?php
2
3/**
4 * Smarty error handler
5 *
6 * @package    Smarty
7 * @subpackage PluginsInternal
8 * @author     Uwe Tews
9 *
10 * @deprecated
11Smarty does no longer use @filemtime()
12 */
13class Smarty_Internal_ErrorHandler
14{
15    /**
16     * contains directories outside of SMARTY_DIR that are to be muted by muteExpectedErrors()
17     */
18    public static $mutedDirectories = array();
19
20    /**
21     * error handler returned by set_error_handler() in self::muteExpectedErrors()
22     */
23    private static $previousErrorHandler = null;
24
25    /**
26     * Enable error handler to mute expected messages
27     *
28     */
29    public static function muteExpectedErrors()
30    {
31        /*
32            error muting is done because some people implemented custom error_handlers using
33            http://php.net/set_error_handler and for some reason did not understand the following paragraph:
34
35                It is important to remember that the standard PHP error handler is completely bypassed for the
36                error types specified by error_types unless the callback function returns FALSE.
37                error_reporting() settings will have no effect and your error handler will be called regardless -
38                however you are still able to read the current value of error_reporting and act appropriately.
39                Of particular note is that this value will be 0 if the statement that caused the error was
40                prepended by the @ error-control operator.
41
42            Smarty deliberately uses @filemtime() over file_exists() and filemtime() in some places. Reasons include
43                - @filemtime() is almost twice as fast as using an additional file_exists()
44                - between file_exists() and filemtime() a possible race condition is opened,
45                  which does not exist using the simple @filemtime() approach.
46        */
47        $error_handler = array('Smarty_Internal_ErrorHandler', 'mutingErrorHandler');
48        $previous = set_error_handler($error_handler);
49        // avoid dead loops
50        if ($previous !== $error_handler) {
51            self::$previousErrorHandler = $previous;
52        }
53    }
54
55    /**
56     * Error Handler to mute expected messages
57     *
58     * @link http://php.net/set_error_handler
59     *
60     * @param integer $errno Error level
61     * @param         $errstr
62     * @param         $errfile
63     * @param         $errline
64     * @param         $errcontext
65     *
66     * @return bool
67     */
68    public static function mutingErrorHandler($errno, $errstr, $errfile, $errline, $errcontext)
69    {
70        $_is_muted_directory = false;
71        // add the SMARTY_DIR to the list of muted directories
72        if (!isset(self::$mutedDirectories[ SMARTY_DIR ])) {
73            $smarty_dir = realpath(SMARTY_DIR);
74            if ($smarty_dir !== false) {
75                self::$mutedDirectories[ SMARTY_DIR ] =
76                    array('file' => $smarty_dir, 'length' => strlen($smarty_dir),);
77            }
78        }
79        // walk the muted directories and test against $errfile
80        foreach (self::$mutedDirectories as $key => &$dir) {
81            if (!$dir) {
82                // resolve directory and length for speedy comparisons
83                $file = realpath($key);
84                if ($file === false) {
85                    // this directory does not exist, remove and skip it
86                    unset(self::$mutedDirectories[ $key ]);
87                    continue;
88                }
89                $dir = array('file' => $file, 'length' => strlen($file),);
90            }
91            if (!strncmp($errfile, $dir[ 'file' ], $dir[ 'length' ])) {
92                $_is_muted_directory = true;
93                break;
94            }
95        }
96        // pass to next error handler if this error did not occur inside SMARTY_DIR
97        // or the error was within smarty but masked to be ignored
98        if (!$_is_muted_directory || ($errno && $errno & error_reporting())) {
99            if (self::$previousErrorHandler) {
100                return call_user_func(
101                    self::$previousErrorHandler,
102                    $errno,
103                    $errstr,
104                    $errfile,
105                    $errline,
106                    $errcontext
107                );
108            } else {
109                return false;
110            }
111        }
112    }
113}
114