Subversion-Projekte lars-tiefland.laravel_shop

Revision

Zur aktuellen Revision | Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
148 lars 1
<?php
2
/**
3
 * Whoops - php errors for cool kids
4
 * @author Filipe Dobreira <http://github.com/filp>
5
 */
6
 
7
namespace Whoops\Exception;
8
 
9
use InvalidArgumentException;
10
use Serializable;
11
 
12
class Frame implements Serializable
13
{
14
    /**
15
     * @var array
16
     */
17
    protected $frame;
18
 
19
    /**
20
     * @var string
21
     */
22
    protected $fileContentsCache;
23
 
24
    /**
25
     * @var array[]
26
     */
27
    protected $comments = [];
28
 
29
    /**
30
     * @var bool
31
     */
32
    protected $application;
33
 
34
    /**
35
     * @param array[]
36
     */
37
    public function __construct(array $frame)
38
    {
39
        $this->frame = $frame;
40
    }
41
 
42
    /**
43
     * @param  bool        $shortened
44
     * @return string|null
45
     */
46
    public function getFile($shortened = false)
47
    {
48
        if (empty($this->frame['file'])) {
49
            return null;
50
        }
51
 
52
        $file = $this->frame['file'];
53
 
54
        // Check if this frame occurred within an eval().
55
        // @todo: This can be made more reliable by checking if we've entered
56
        // eval() in a previous trace, but will need some more work on the upper
57
        // trace collector(s).
58
        if (preg_match('/^(.*)\((\d+)\) : (?:eval\(\)\'d|assert) code$/', $file, $matches)) {
59
            $file = $this->frame['file'] = $matches[1];
60
            $this->frame['line'] = (int) $matches[2];
61
        }
62
 
63
        if ($shortened && is_string($file)) {
64
            // Replace the part of the path that all frames have in common, and add 'soft hyphens' for smoother line-breaks.
65
            $dirname = dirname(dirname(dirname(dirname(dirname(dirname(__DIR__))))));
66
            if ($dirname !== '/') {
67
                $file = str_replace($dirname, "&hellip;", $file);
68
            }
69
            $file = str_replace("/", "/&shy;", $file);
70
        }
71
 
72
        return $file;
73
    }
74
 
75
    /**
76
     * @return int|null
77
     */
78
    public function getLine()
79
    {
80
        return isset($this->frame['line']) ? $this->frame['line'] : null;
81
    }
82
 
83
    /**
84
     * @return string|null
85
     */
86
    public function getClass()
87
    {
88
        return isset($this->frame['class']) ? $this->frame['class'] : null;
89
    }
90
 
91
    /**
92
     * @return string|null
93
     */
94
    public function getFunction()
95
    {
96
        return isset($this->frame['function']) ? $this->frame['function'] : null;
97
    }
98
 
99
    /**
100
     * @return array
101
     */
102
    public function getArgs()
103
    {
104
        return isset($this->frame['args']) ? (array) $this->frame['args'] : [];
105
    }
106
 
107
    /**
108
     * Returns the full contents of the file for this frame,
109
     * if it's known.
110
     * @return string|null
111
     */
112
    public function getFileContents()
113
    {
114
        if ($this->fileContentsCache === null && $filePath = $this->getFile()) {
115
            // Leave the stage early when 'Unknown' or '[internal]' is passed
116
            // this would otherwise raise an exception when
117
            // open_basedir is enabled.
118
            if ($filePath === "Unknown" || $filePath === '[internal]') {
119
                return null;
120
            }
121
 
122
            try {
123
                $this->fileContentsCache = file_get_contents($filePath);
124
            } catch (ErrorException $exception) {
125
                // Internal file paths of PHP extensions cannot be opened
126
            }
127
        }
128
 
129
        return $this->fileContentsCache;
130
    }
131
 
132
    /**
133
     * Adds a comment to this frame, that can be received and
134
     * used by other handlers. For example, the PrettyPage handler
135
     * can attach these comments under the code for each frame.
136
     *
137
     * An interesting use for this would be, for example, code analysis
138
     * & annotations.
139
     *
140
     * @param string $comment
141
     * @param string $context Optional string identifying the origin of the comment
142
     */
143
    public function addComment($comment, $context = 'global')
144
    {
145
        $this->comments[] = [
146
            'comment' => $comment,
147
            'context' => $context,
148
        ];
149
    }
150
 
151
    /**
152
     * Returns all comments for this frame. Optionally allows
153
     * a filter to only retrieve comments from a specific
154
     * context.
155
     *
156
     * @param  string  $filter
157
     * @return array[]
158
     */
159
    public function getComments($filter = null)
160
    {
161
        $comments = $this->comments;
162
 
163
        if ($filter !== null) {
164
            $comments = array_filter($comments, function ($c) use ($filter) {
165
                return $c['context'] == $filter;
166
            });
167
        }
168
 
169
        return $comments;
170
    }
171
 
172
    /**
173
     * Returns the array containing the raw frame data from which
174
     * this Frame object was built
175
     *
176
     * @return array
177
     */
178
    public function getRawFrame()
179
    {
180
        return $this->frame;
181
    }
182
 
183
    /**
184
     * Returns the contents of the file for this frame as an
185
     * array of lines, and optionally as a clamped range of lines.
186
     *
187
     * NOTE: lines are 0-indexed
188
     *
189
     * @example
190
     *     Get all lines for this file
191
     *     $frame->getFileLines(); // => array( 0 => '<?php', 1 => '...', ...)
192
     * @example
193
     *     Get one line for this file, starting at line 10 (zero-indexed, remember!)
194
     *     $frame->getFileLines(9, 1); // array( 9 => '...' )
195
     *
196
     * @throws InvalidArgumentException if $length is less than or equal to 0
197
     * @param  int                      $start
198
     * @param  int                      $length
199
     * @return string[]|null
200
     */
201
    public function getFileLines($start = 0, $length = null)
202
    {
203
        if (null !== ($contents = $this->getFileContents())) {
204
            $lines = explode("\n", $contents);
205
 
206
            // Get a subset of lines from $start to $end
207
            if ($length !== null) {
208
                $start  = (int) $start;
209
                $length = (int) $length;
210
                if ($start < 0) {
211
                    $start = 0;
212
                }
213
 
214
                if ($length <= 0) {
215
                    throw new InvalidArgumentException(
216
                        "\$length($length) cannot be lower or equal to 0"
217
                    );
218
                }
219
 
220
                $lines = array_slice($lines, $start, $length, true);
221
            }
222
 
223
            return $lines;
224
        }
225
    }
226
 
227
    /**
228
     * Implements the Serializable interface, with special
229
     * steps to also save the existing comments.
230
     *
231
     * @see Serializable::serialize
232
     * @return string
233
     */
234
    public function serialize()
235
    {
236
        $frame = $this->frame;
237
        if (!empty($this->comments)) {
238
            $frame['_comments'] = $this->comments;
239
        }
240
 
241
        return serialize($frame);
242
    }
243
 
244
    public function __serialize()
245
    {
246
        $frame = $this->frame;
247
        if (!empty($this->comments)) {
248
            $frame['_comments'] = $this->comments;
249
        }
250
        return $frame;
251
    }
252
 
253
    /**
254
     * Unserializes the frame data, while also preserving
255
     * any existing comment data.
256
     *
257
     * @see Serializable::unserialize
258
     * @param string $serializedFrame
259
     */
260
    public function unserialize($serializedFrame)
261
    {
262
        $frame = unserialize($serializedFrame);
263
 
264
        if (!empty($frame['_comments'])) {
265
            $this->comments = $frame['_comments'];
266
            unset($frame['_comments']);
267
        }
268
 
269
        $this->frame = $frame;
270
    }
271
 
272
    public function __unserialize($frame)
273
    {
274
        if (!empty($frame['_comments'])) {
275
            $this->comments = $frame['_comments'];
276
            unset($frame['_comments']);
277
        }
278
 
279
        $this->frame = $frame;
280
    }
281
 
282
    /**
283
     * Compares Frame against one another
284
     * @param  Frame $frame
285
     * @return bool
286
     */
287
    public function equals(Frame $frame)
288
    {
289
        if (!$this->getFile() || $this->getFile() === 'Unknown' || !$this->getLine()) {
290
            return false;
291
        }
292
        return $frame->getFile() === $this->getFile() && $frame->getLine() === $this->getLine();
293
    }
294
 
295
    /**
296
     * Returns whether this frame belongs to the application or not.
297
     *
298
     * @return boolean
299
     */
300
    public function isApplication()
301
    {
302
        return $this->application;
303
    }
304
 
305
    /**
306
     * Mark as an frame belonging to the application.
307
     *
308
     * @param boolean $application
309
     */
310
    public function setApplication($application)
311
    {
312
        $this->application = $application;
313
    }
314
}