PageRenderTime 33ms CodeModel.GetById 14ms app.highlight 15ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/vendor/symfony/lib/exception/sfException.class.php

https://bitbucket.org/morskoi/zakvaska
PHP | 449 lines | 281 code | 57 blank | 111 comment | 56 complexity | d162b6b04444c5469b2cd1b5a56eb980 MD5 | raw file
  1<?php
  2
  3/*
  4 * This file is part of the symfony package.
  5 * (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
  6 * (c) 2004-2006 Sean Kerr <sean@code-box.org>
  7 * 
  8 * For the full copyright and license information, please view the LICENSE
  9 * file that was distributed with this source code.
 10 */
 11
 12/**
 13 * sfException is the base class for all symfony related exceptions and
 14 * provides an additional method for printing up a detailed view of an
 15 * exception.
 16 *
 17 * @package    symfony
 18 * @subpackage exception
 19 * @author     Fabien Potencier <fabien.potencier@symfony-project.com>
 20 * @author     Sean Kerr <sean@code-box.org>
 21 * @version    SVN: $Id: sfException.class.php 33539 2012-09-19 05:36:02Z fabien $
 22 */
 23class sfException extends Exception
 24{
 25  protected
 26    $wrappedException = null;
 27
 28  static protected
 29    $lastException = null;
 30
 31  /**
 32   * Wraps an Exception.
 33   *
 34   * @param Exception $e An Exception instance
 35   *
 36   * @return sfException An sfException instance that wraps the given Exception object
 37   */
 38  static public function createFromException(Exception $e)
 39  {
 40    $exception = new sfException(sprintf('Wrapped %s: %s', get_class($e), $e->getMessage()));
 41    $exception->setWrappedException($e);
 42    self::$lastException = $e;
 43
 44    return $exception;
 45  }
 46
 47  /**
 48   * Sets the wrapped exception.
 49   *
 50   * @param Exception $e An Exception instance
 51   */
 52  public function setWrappedException(Exception $e)
 53  {
 54    $this->wrappedException = $e;
 55
 56    self::$lastException = $e;
 57  }
 58
 59  /**
 60   * Gets the last wrapped exception.
 61   *
 62   * @return Exception An Exception instance
 63   */
 64  static public function getLastException()
 65  {
 66    return self::$lastException;
 67  }
 68
 69  /**
 70   * Clears the $lastException property (added for #6342)
 71   */
 72  static public function clearLastException()
 73  {
 74  	self::$lastException = null;
 75  }
 76  
 77  /**
 78   * Prints the stack trace for this exception.
 79   */
 80  public function printStackTrace()
 81  {
 82    if (null === $this->wrappedException)
 83    {
 84      $this->setWrappedException($this);
 85    }
 86
 87    $exception = $this->wrappedException;
 88
 89    if (!sfConfig::get('sf_test'))
 90    {
 91      // log all exceptions in php log
 92      error_log($exception->getMessage());
 93
 94      // clean current output buffer
 95      while (ob_get_level())
 96      {
 97        if (!ob_end_clean())
 98        {
 99          break;
100        }
101      }
102
103      if (sfConfig::get('sf_compressed')) {
104          ob_start('ob_gzhandler');
105      }
106
107      header('HTTP/1.0 500 Internal Server Error');
108    }
109
110    try
111    {
112      $this->outputStackTrace($exception);
113    }
114    catch (Exception $e)
115    {
116    }
117
118    if (!sfConfig::get('sf_test'))
119    {
120      exit(1);
121    }
122  }
123
124  /**
125   * Gets the stack trace for this exception.
126   */
127  static protected function outputStackTrace(Exception $exception)
128  {
129    $format = 'html';
130    $code   = '500';
131    $text   = 'Internal Server Error';
132
133    $response = null;
134    if (class_exists('sfContext', false) && sfContext::hasInstance() && is_object($request = sfContext::getInstance()->getRequest()) && is_object($response = sfContext::getInstance()->getResponse()))
135    {
136      $dispatcher = sfContext::getInstance()->getEventDispatcher();
137
138      if (sfConfig::get('sf_logging_enabled'))
139      {
140        $dispatcher->notify(new sfEvent($exception, 'application.log', array($exception->getMessage(), 'priority' => sfLogger::ERR)));
141      }
142
143      $event = $dispatcher->notifyUntil(new sfEvent($exception, 'application.throw_exception'));
144      if ($event->isProcessed())
145      {
146        return;
147      }
148
149      if ($response->getStatusCode() < 300)
150      {
151        // status code has already been sent, but is included here for the purpose of testing
152        $response->setStatusCode(500);
153      }
154
155      $response->setContentType('text/html');
156
157      if (!sfConfig::get('sf_test'))
158      {
159        foreach ($response->getHttpHeaders() as $name => $value)
160        {
161          header($name.': '.$value);
162        }
163      }
164
165      $code = $response->getStatusCode();
166      $text = $response->getStatusText();
167
168      $format = $request->getRequestFormat();
169      if (!$format)
170      {
171        $format = 'html';
172      }
173
174      if ($mimeType = $request->getMimeType($format))
175      {
176        $response->setContentType($mimeType);
177      }
178    }
179    else
180    {
181      // a backward compatible default
182      if (!sfConfig::get('sf_test'))
183      {
184        header('Content-Type: text/html; charset='.sfConfig::get('sf_charset', 'utf-8'));
185      }
186    }
187
188    // send an error 500 if not in debug mode
189    if (!sfConfig::get('sf_debug'))
190    {
191      if ($template = self::getTemplatePathForError($format, false))
192      {
193        include $template;
194        return;
195      }
196    }
197
198    // when using CLI, we force the format to be TXT. Compare exactly to 
199    // the string 'cli' because the php 5.4 server is identified by 'cli-server'
200    if ('cli' == PHP_SAPI)
201    {
202      $format = 'txt';
203    }
204
205    $message = null === $exception->getMessage() ? 'n/a' : $exception->getMessage();
206    $name    = get_class($exception);
207    $traces  = self::getTraces($exception, $format);
208
209    // dump main objects values
210    $sf_settings = '';
211    $settingsTable = $requestTable = $responseTable = $globalsTable = $userTable = '';
212    if (class_exists('sfContext', false) && sfContext::hasInstance())
213    {
214      $context = sfContext::getInstance();
215      $settingsTable = self::formatArrayAsHtml(sfDebug::settingsAsArray());
216      $requestTable  = self::formatArrayAsHtml(sfDebug::requestAsArray($context->getRequest()));
217      $responseTable = self::formatArrayAsHtml(sfDebug::responseAsArray($context->getResponse()));
218      $userTable     = self::formatArrayAsHtml(sfDebug::userAsArray($context->getUser()));
219      $globalsTable  = self::formatArrayAsHtml(sfDebug::globalsAsArray());
220    }
221
222    if (isset($response) && $response)
223    {
224      $response->sendHttpHeaders();
225    }
226
227    if ($template = self::getTemplatePathForError($format, true))
228    {
229      if (isset($dispatcher))
230      {
231        ob_start();
232        include $template;
233        $content = ob_get_clean();
234
235        $event = $dispatcher->filter(new sfEvent($response, 'response.filter_content'), $content);
236
237        echo $event->getReturnValue();
238      }
239      else
240      {
241        include $template;
242      }
243
244      return;
245    }
246  }
247
248  /**
249   * Returns the path for the template error message.
250   *
251   * @param  string  $format The request format
252   * @param  Boolean $debug  Whether to return a template for the debug mode or not
253   *
254   * @return string|Boolean  false if the template cannot be found for the given format,
255   *                         the absolute path to the template otherwise
256   */
257  static public function getTemplatePathForError($format, $debug)
258  {
259    $templatePaths = array(
260      sfConfig::get('sf_app_config_dir').'/error',
261      sfConfig::get('sf_config_dir').'/error',
262      dirname(__FILE__).'/data',
263    );
264
265    $template = sprintf('%s.%s.php', $debug ? 'exception' : 'error', $format);
266    foreach ($templatePaths as $path)
267    {
268      if (null !== $path && is_readable($file = $path.'/'.$template))
269      {
270        return $file;
271      }
272    }
273
274    return false;
275  }
276
277  /**
278   * Returns an array of exception traces.
279   *
280   * @param Exception $exception  An Exception implementation instance
281   * @param string    $format     The trace format (txt or html)
282   *
283   * @return array An array of traces
284   */
285  static protected function getTraces($exception, $format = 'txt')
286  {
287    $traceData = $exception->getTrace();
288    array_unshift($traceData, array(
289      'function' => '',
290      'file'     => $exception->getFile() != null ? $exception->getFile() : null,
291      'line'     => $exception->getLine() != null ? $exception->getLine() : null,
292      'args'     => array(),
293    ));
294
295    $traces = array();
296    if ($format == 'html')
297    {
298      $lineFormat = 'at <strong>%s%s%s</strong>(%s)<br />in <em>%s</em> line %s <a href="#" onclick="toggle(\'%s\'); return false;">...</a><br /><ul class="code" id="%s" style="display: %s">%s</ul>';
299    }
300    else
301    {
302      $lineFormat = 'at %s%s%s(%s) in %s line %s';
303    }
304
305    for ($i = 0, $count = count($traceData); $i < $count; $i++)
306    {
307      $line = isset($traceData[$i]['line']) ? $traceData[$i]['line'] : null;
308      $file = isset($traceData[$i]['file']) ? $traceData[$i]['file'] : null;
309      $args = isset($traceData[$i]['args']) ? $traceData[$i]['args'] : array();
310      $traces[] = sprintf($lineFormat,
311        (isset($traceData[$i]['class']) ? $traceData[$i]['class'] : ''),
312        (isset($traceData[$i]['type']) ? $traceData[$i]['type'] : ''),
313        $traceData[$i]['function'],
314        self::formatArgs($args, false, $format),
315        self::formatFile($file, $line, $format, null === $file ? 'n/a' : sfDebug::shortenFilePath($file)),
316        null === $line ? 'n/a' : $line,
317        'trace_'.$i,
318        'trace_'.$i,
319        $i == 0 ? 'block' : 'none',
320        self::fileExcerpt($file, $line)
321      );
322    }
323
324    return $traces;
325  }
326
327  /**
328   * Returns an HTML version of an array as YAML.
329   *
330   * @param array $values The values array
331   *
332   * @return string An HTML string
333   */
334  static protected function formatArrayAsHtml($values)
335  {
336    return '<pre>'.self::escape(@sfYaml::dump($values)).'</pre>';
337  }
338
339  /**
340   * Returns an excerpt of a code file around the given line number.
341   *
342   * @param string $file  A file path
343   * @param int    $line  The selected line number
344   *
345   * @return string An HTML string
346   */
347  static protected function fileExcerpt($file, $line)
348  {
349    if (is_readable($file))
350    {
351      $content = preg_split('#<br />#', preg_replace('/^<code>(.*)<\/code>$/s', '$1', highlight_file($file, true)));
352
353      $lines = array();
354      for ($i = max($line - 3, 1), $max = min($line + 3, count($content)); $i <= $max; $i++)
355      {
356        $lines[] = '<li'.($i == $line ? ' class="selected"' : '').'>'.$content[$i - 1].'</li>';
357      }
358
359      return '<ol start="'.max($line - 3, 1).'">'.implode("\n", $lines).'</ol>';
360    }
361  }
362
363  /**
364   * Formats an array as a string.
365   *
366   * @param array   $args     The argument array
367   * @param boolean $single
368   * @param string  $format   The format string (html or txt)
369   *
370   * @return string
371   */
372  static protected function formatArgs($args, $single = false, $format = 'html')
373  {
374    $result = array();
375
376    $single and $args = array($args);
377
378    foreach ($args as $key => $value)
379    {
380      if (is_object($value))
381      {
382        $formattedValue = ($format == 'html' ? '<em>object</em>' : 'object').sprintf("('%s')", get_class($value));
383      }
384      else if (is_array($value))
385      {
386        $formattedValue = ($format == 'html' ? '<em>array</em>' : 'array').sprintf("(%s)", self::formatArgs($value));
387      }
388      else if (is_string($value))
389      {
390        $formattedValue = ($format == 'html' ? sprintf("'%s'", self::escape($value)) : "'$value'");
391      }
392      else if (null === $value)
393      {
394        $formattedValue = ($format == 'html' ? '<em>null</em>' : 'null');
395      }
396      else
397      {
398        $formattedValue = $value;
399      }
400      
401      $result[] = is_int($key) ? $formattedValue : sprintf("'%s' => %s", self::escape($key), $formattedValue);
402    }
403
404    return implode(', ', $result);
405  }
406
407  /**
408   * Formats a file path.
409   * 
410   * @param  string  $file   An absolute file path
411   * @param  integer $line   The line number
412   * @param  string  $format The output format (txt or html)
413   * @param  string  $text   Use this text for the link rather than the file path
414   * 
415   * @return string
416   */
417  static protected function formatFile($file, $line, $format = 'html', $text = null)
418  {
419    if (null === $text)
420    {
421      $text = $file;
422    }
423
424    if ('html' == $format && $file && $line && $linkFormat = sfConfig::get('sf_file_link_format', ini_get('xdebug.file_link_format')))
425    {
426      $link = strtr($linkFormat, array('%f' => $file, '%l' => $line));
427      $text = sprintf('<a href="%s" title="Click to open this file" class="file_link">%s</a>', $link, $text);
428    }
429
430    return $text;
431  }
432
433  /**
434   * Escapes a string value with html entities
435   *
436   * @param  string  $value
437   *
438   * @return string
439   */
440  static protected function escape($value)
441  {
442    if (!is_string($value))
443    {
444      return $value;
445    }
446    
447    return htmlspecialchars($value, ENT_QUOTES, sfConfig::get('sf_charset', 'UTF-8'));
448  }
449}