1<?php
2/*
3 * This file is part of PHPUnit.
4 *
5 * (c) Sebastian Bergmann <sebastian@phpunit.de>
6 *
7 * For the full copyright and license information, please view the LICENSE
8 * file that was distributed with this source code.
9 */
10
11/**
12 * Utility class for code filtering.
13 */
14class PHPUnit_Util_Filter
15{
16    /**
17     * Filters stack frames from PHPUnit classes.
18     *
19     * @param Exception $e
20     * @param bool      $asString
21     *
22     * @return string
23     */
24    public static function getFilteredStacktrace($e, $asString = true)
25    {
26        $prefix = false;
27        $script = realpath($GLOBALS['_SERVER']['SCRIPT_NAME']);
28
29        if (defined('__PHPUNIT_PHAR_ROOT__')) {
30            $prefix = __PHPUNIT_PHAR_ROOT__;
31        }
32
33        if ($asString === true) {
34            $filteredStacktrace = '';
35        } else {
36            $filteredStacktrace = [];
37        }
38
39        if ($e instanceof PHPUnit_Framework_SyntheticError) {
40            $eTrace = $e->getSyntheticTrace();
41            $eFile  = $e->getSyntheticFile();
42            $eLine  = $e->getSyntheticLine();
43        } elseif ($e instanceof PHPUnit_Framework_Exception) {
44            $eTrace = $e->getSerializableTrace();
45            $eFile  = $e->getFile();
46            $eLine  = $e->getLine();
47        } else {
48            if ($e->getPrevious()) {
49                $e = $e->getPrevious();
50            }
51            $eTrace = $e->getTrace();
52            $eFile  = $e->getFile();
53            $eLine  = $e->getLine();
54        }
55
56        if (!self::frameExists($eTrace, $eFile, $eLine)) {
57            array_unshift(
58                $eTrace,
59                ['file' => $eFile, 'line' => $eLine]
60            );
61        }
62
63        $blacklist = new PHPUnit_Util_Blacklist;
64
65        foreach ($eTrace as $frame) {
66            if (isset($frame['file']) && is_file($frame['file']) &&
67                !$blacklist->isBlacklisted($frame['file']) &&
68                ($prefix === false || strpos($frame['file'], $prefix) !== 0) &&
69                $frame['file'] !== $script) {
70                if ($asString === true) {
71                    $filteredStacktrace .= sprintf(
72                        "%s:%s\n",
73                        $frame['file'],
74                        isset($frame['line']) ? $frame['line'] : '?'
75                    );
76                } else {
77                    $filteredStacktrace[] = $frame;
78                }
79            }
80        }
81
82        return $filteredStacktrace;
83    }
84
85    /**
86     * @param array  $trace
87     * @param string $file
88     * @param int    $line
89     *
90     * @return bool
91     */
92    private static function frameExists(array $trace, $file, $line)
93    {
94        foreach ($trace as $frame) {
95            if (isset($frame['file']) && $frame['file'] == $file &&
96                isset($frame['line']) && $frame['line'] == $line) {
97                return true;
98            }
99        }
100
101        return false;
102    }
103}
104