websiteWebsite
codingteam CodingTeam
A free forge, lightweight and extensible.

 

Browse the code

Revision log Information on the revision
Revision: 243 (differences)
Author: xbright
Log message: * Updated the way to show sourcecode
Change revision:
<?php
#    This file is a part of CodingTeam. See <http://www.codingteam.net>.
#    Copyright (C) 2007-2009 CodingTeam (See AUTHORS and THANKS for details)
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU Affero General Public License as
#    published by the Free Software Foundation, version 3 only.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU Affero General Public License for more details.
#
#    You should have received a copy of the GNU Affero General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
/**
 * @file
 * This file contains the ErrorHandler class
 *
 * Handle both PHP and CodingTeam errors, show them in a human-way to
 * the user, log them and finally exit.
 */
 
 
/**
 * ErrorHandler class
 */
class ErrorHandler
{
    public $lang, $show_debug, $log_errors, $log_level, $show_notice;
 
    /*
    * Constructor
    *
    * Construct an instance of ErrorHandler.
    *  @param $lang
    * The spoken language of the user.
    *  @param $show_debug
    * A boolean to turn on or off the debug. This will show source code and
    * error context. It's only launched if the error status is 3.
    *  @param $log_errors
    * A boolean to turn on or off errors logging.
    *  @param $log_level
    * An int of the first level of error status to be logged.
    * If you want to log level 2 and 3 (critical and internal), set it to 2.
    *  @param $show_notice
    * A boolean to turn on or off notice catch and show.
    */
    function __construct($lang, $show_debug, $log_errors, $log_level,
                         $show_notice)
    {
        $this->lang = $lang;
        $this->show_debug = $show_debug;
        $this->log_errors = $log_errors;
        $this->log_level = $log_level;
        $this->show_notice = $show_notice;
    }
 
 
    /**
     * Load the view
     *
     * Generate a pretty textarea with optional Javascript content.
     * @param $error
     *   The error message.
     * @param $status
     *   The error status (int). Different levels are:
     *    - -1: Unlogged user, in login.tpl
     *         (only if the forge is not public, force login)
     *    - 0: Banal, in warning.tpl
     *         (eg. 404, 403, 401, non-existing resource…)
     *    - 1: Important,in error.tpl
     *         (eg. database request error…)
     *    - 2: Critical, in error.tpl
     *         (eg. database connection error…)
     *    - 3: Internal error, in error.tpl
     *         (only PHP errors, not trigged manually by displayError)
     * @param $http (optional)
     *   HTTP Headers to send.
     */
    function displayError($error, $status, $http='')
    {
        // If the configuration tell to ignore E_NOTICE, ignore them
        if (!$this->show_notice && $status == 3 && $error[0] == 8)
            return FALSE;
 
        /* In this file, if an external server (for OpenForge external search)
         * is not online, we get an ugly warning, just ignore it (that's not
         * so bad, that's just a work-around: WARNING shouldn't be blocking,
         * but our class make them so).
         */
        if (($error[0] == 2 || $error[0] == 8) && $error[2] == CT_BASEDIR.
            '/inc/modules/search/views/default.php')
            return FALSE;
 
        // Same work to prevent ugly errors when documenters are bad boys
        // FIXME: this is bug in textview.php, that sort of "fix" are ugly!
        if ($error[0] == 2 && $error[2] == CT_BASEDIR.
            '/inc/classes/textview.php')
            return FALSE;
 
        // Don't show E_STRICT and E_NOTICE for libs used by CodingTeam
        $libs = CT_BASEDIR.'/inc/libs';
        $nlibs = mb_strlen($libs);
        if (($error[0] == 2048 || $error[0] == 8)
            && mb_substr($error[2], 0, $nlibs) == $libs)
            return FALSE;
 
        /* Error logging.
         *
         * If you enable error logging, don't forget to create a error.log file
         * in the CodingTeam root directory and allow Apache HTTPD to write in
         * this file.
         */
        if ($status == 3)
        {
            switch ($error[0])
            {
                case 1:
                    $errmsg = 'E_ERROR';
                    break;
 
                case 2:
                    $errmsg = 'E_WARNING';
                    break;
 
                case 4:
                    $errmsg = 'E_PARSE';
                    break;
 
                case 8:
                    $errmsg = 'E_NOTICE';
                    break;
 
                case 2048:
                    $errmsg = 'E_STRICT';
                    break;
 
                default:
                    $errmsg = 'E_UNKNOWN';
            }
 
            $errinfos = ' (file: '.$error[2].'@'.$error[3].')';
            $errdesc = $error[1];
        }
        elseif ($status == -1)
        {
            $errmsg = 'E_CODINGTEAM';
            $errinfos = '';
            $errdesc = $error[0];
        }
        else
        {
            $errmsg = 'E_CODINGTEAM';
            $errinfos = '';
            $errdesc = $error;
        }
 
        // Log the error into a file (use log_errors/log_level).
        if ($status >= $this->log_level && $this->log_errors)
        {
            $file = CT_BASEDIR.'/error.log';
            $data = '['.date('Y-m-d H:i:s').'] ['.$errmsg.'] [client '.
                     $_SERVER['REMOTE_ADDR'].'] '.$errdesc. ' '.
                     "'".$_SERVER['REQUEST_URI']."'".$errinfos."\n";
 
            file_put_contents($file, $data, FILE_APPEND | LOCK_EX);
        }
 
        // If a HTTP header is specified, send it
        if (!empty($http))
            Header('HTTP/1.0 '.$http);
 
        // Error status
        if ($status == -1)
            $errstat = i18n('Unlogged user');
        elseif ($status == 0)
            $erstat = i18n('Banal');
        elseif ($status == 1)
            $erstat = i18n('Important');
        elseif ($status == 2)
            $erstat = i18n('Critical');
        elseif ($status == 3)
            $erstat = i18n('Internal error');
        else
            exit('Error.');
 
        // Globals
        $temp['tpl:lang'] = $this->lang;
        $temp['tpl:baseurl'] = CT_BASEURL;
        $temp['tpl:cssdir'] = 'inc/templates/';
        $temp['tpl:logosimages'] = 'public/images/logos/';
        $temp['erstat'] = $status;
 
        // Error
        if ($status < 3)
            $temp['error'] = $error;
        else
        {
            $temp['error'] = i18n('An error occured.').'<br />'.$error[1].
                             ' ('.$error[0].' - '.$errmsg.')<br />'.
                             i18n('In: %(file)s at line %(line)d',
                                  array('file' => $error[2],
                                        'line' => $error[3]));
 
            if ($this->show_debug)
            {
                ob_start();
                print_r($error[4]);
                $datas = htmlspecialchars(ob_get_clean());
 
                if (empty($datas))
                    $datas = i18n('No context available for this error.');
 
                if (is_file($error[2]) && is_readable($error[2]))
                {
                    $output = '';
                    $lines = array();
                    $content = explode("\n", file_get_contents($error[2]));
                    $line = $error[3];
 
                    for ($i=($line-5); $i<($line+4); $i++)
                        if (array_key_exists($i, $content))
                        {
                            $output .= $content[$i]."\n";
                            array_push($lines, ($i+1));
                        }
 
                    $hlline = array($lines, $error[3]);
                    $code = HTMLSourceView($output, 'php', $hlline);
                }
 
                $dbimg = 'public/images/icons/emblems/emblem-important.png';
                $debug_output = '<table style="width: 100%;">
  <tr>
    <td style="vertical-align:top;width: 70%;">
      <h4>'.i18n('Code').'</h4>
      <strong>'.$error[2].'</strong>
      <div class="errdebug">'.$code.'</div>
    </td>
    <td style="vertical-align:top;width: 30%;">
      <h4>'.i18n('Memory dump').'</h4>
      <textarea cols="48" rows="12" readonly="readonly">'.$datas.'</textarea>
    </td>
  </tr>
</table>
 
<p style="clear: both;">&nbsp;</p>
 
<div style="background-image: url(\''.$dbimg.'\');background-repeat: '.
  'no-repeat;padding-left: 20px;height: 18px;">
  '.i18n('You can see a memory dump and the source code because '.
         '<strong>show_debug</strong> is activated in the configuration.').'
</div>';
            }
        }
 
        /* Load the template
         *
         * Load login.tpl, warning.tpl or error.tpl and fill it.
         */
        if ($status == 0)
        {
            $html = file_get_contents(CT_BASEDIR.'/inc/templates/warning.tpl');
 
            $temp['title'] = i18n('Something goes wrong');
            $temp['header'] = i18n('Warning! Something goes wrong…');
 
            $temp['error'] = $error;
 
            $temp['link-index'] = i18n('Go to the index');
            $temp['link-precedent'] = i18n('Go back');
 
            $temp['url'] = $_SERVER['REQUEST_URI'];
 
            $in_array = array('projects'       => i18n('Projects'),
                              'projects-bugs'  => i18n('Bugs'),
                              'projects-doc'   => i18n('Documentation'),
                              'projects-forum' => i18n('Forum'),
                              'projects-news'  => i18n('News'),
                              'notepad'        => i18n('Notepad'),
                              'users'          => i18n('Users'));
 
            $str = '';
            foreach ($in_array as $key => $value)
            {
            $explode = explode('-', $key);
            if (isset($explode[1]))
                $value = '&nbsp;&nbsp;'.$value;
 
                $str .= '<option value="'.$key.'">'.$value.'</option>';
            }
 
            $temp['header-search'] = i18n('Search');
            $temp['select-search'] = $str;
            $temp['button-search'] = i18n('Search');
 
            $temp['text-search'] = i18n('If you were trying to find something'.
                                ' on the forge, you should try to search it.');
        }
        elseif ($status == -1)
        {
            $html = file_get_contents(CT_BASEDIR.'/inc/templates/login.tpl');
 
            require(CT_BASEDIR.'/inc/modules/head_member/head_member.php');
            $hmember = new head_member($error[1], $error[2], array('index'));
            $hmember->treatForms();
 
            $temp['header-login'] = $error[0];
            ob_start();
            $hmember->getPageContent();
            $temp['form'] = ob_get_clean();
 
            $temp['error'] = $errstat;
            $temp['title'] = i18n('Access denied');
            $temp['header'] = i18n('This forge is not public!');
        }
        else
        {
            $html = file_get_contents(CT_BASEDIR.'/inc/templates/error.tpl');
 
            $temp['title'] = i18n('An error has occured');
            $temp['header'] = i18n('An error has occured.');
 
            $temp['header-report'] = i18n('Report');
 
            $version = file_get_contents(CT_BASEDIR.'/VERSION');
            $server = str_replace('address', 'strong',
                                  $_SERVER['SERVER_SIGNATURE']);
 
            $temp['table-bugstatus-key'] = i18n('Bug status:');
            $temp['table-bugstatus-value'] = $erstat;
            $temp['table-affects-key'] = i18n('Affects:');
            $temp['table-affects-value'] = $_SERVER['SERVER_NAME'];
            $temp['table-version-key'] = i18n('CodingTeam version:');
            $temp['table-version-value'] = $version;
            $temp['table-server-key'] = i18n('Server identification:');
            $temp['table-server-value'] = $server;
            $temp['table-date-key'] = i18n('Date/time:');
            $temp['table-date-value'] = date('Y-m-d H:i:s');
 
            $temp['header-reproduce'] = i18n('What to do if you can reproduce'.
                                             ' this bug');
 
            $temp['contact-srvadmin'] = i18n('Contact your server admin');
            $temp['contact-srvadmin-more'] = i18n('It is the first thing to '.
                                                  'do when you see a bug on '.
                                                  'your forge.');
 
            $temp['report-upstream'] = i18n('Report this bug to upstream');
            $temp['report-upstream-more'] = i18n('You can send all datas on '.
            'this page to the CodingTeam bug tracker at this page: %(url)s.',
            array('url' => '<a href="http://codingteam.net/project/codingteam/'.
                  'bugs">http://codingteam.net/project/codingteam/bugs</a>')).
            '<br />'.
            i18n('Be careful not to transmit private data! Also, be sure that'.
                 ' this bug concerns only the CodingTeam development team.');
 
            if ($status < 3)
                $temp['debug'] = '';
            else
                $temp['debug'] = $debug_output;
        }
 
        // Parse the template
        foreach ($temp as $key => $value)
        {
            $search[] = '{'.$key.'}';
            $replace[] = $value;
        }
        $output = str_replace($search, $replace, $html);
 
        echo $output;
        exit();
    }
}
?>