Subversion-Projekte lars-tiefland.laravel_shop

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
148 lars 1
<?php declare(strict_types=1);
2
 
3
/*
4
 * This file is part of the Monolog package.
5
 *
6
 * (c) Jordi Boggiano <j.boggiano@seld.be>
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
namespace Monolog\Handler;
13
 
14
use Monolog\Formatter\WildfireFormatter;
15
use Monolog\Formatter\FormatterInterface;
16
 
17
/**
18
 * Simple FirePHP Handler (http://www.firephp.org/), which uses the Wildfire protocol.
19
 *
20
 * @author Eric Clemmons (@ericclemmons) <eric@uxdriven.com>
21
 *
22
 * @phpstan-import-type FormattedRecord from AbstractProcessingHandler
23
 */
24
class FirePHPHandler extends AbstractProcessingHandler
25
{
26
    use WebRequestRecognizerTrait;
27
 
28
    /**
29
     * WildFire JSON header message format
30
     */
31
    protected const PROTOCOL_URI = 'http://meta.wildfirehq.org/Protocol/JsonStream/0.2';
32
 
33
    /**
34
     * FirePHP structure for parsing messages & their presentation
35
     */
36
    protected const STRUCTURE_URI = 'http://meta.firephp.org/Wildfire/Structure/FirePHP/FirebugConsole/0.1';
37
 
38
    /**
39
     * Must reference a "known" plugin, otherwise headers won't display in FirePHP
40
     */
41
    protected const PLUGIN_URI = 'http://meta.firephp.org/Wildfire/Plugin/FirePHP/Library-FirePHPCore/0.3';
42
 
43
    /**
44
     * Header prefix for Wildfire to recognize & parse headers
45
     */
46
    protected const HEADER_PREFIX = 'X-Wf';
47
 
48
    /**
49
     * Whether or not Wildfire vendor-specific headers have been generated & sent yet
50
     * @var bool
51
     */
52
    protected static $initialized = false;
53
 
54
    /**
55
     * Shared static message index between potentially multiple handlers
56
     * @var int
57
     */
58
    protected static $messageIndex = 1;
59
 
60
    /** @var bool */
61
    protected static $sendHeaders = true;
62
 
63
    /**
64
     * Base header creation function used by init headers & record headers
65
     *
66
     * @param array<int|string> $meta    Wildfire Plugin, Protocol & Structure Indexes
67
     * @param string            $message Log message
68
     *
69
     * @return array<string, string> Complete header string ready for the client as key and message as value
70
     *
71
     * @phpstan-return non-empty-array<string, string>
72
     */
73
    protected function createHeader(array $meta, string $message): array
74
    {
75
        $header = sprintf('%s-%s', static::HEADER_PREFIX, join('-', $meta));
76
 
77
        return [$header => $message];
78
    }
79
 
80
    /**
81
     * Creates message header from record
82
     *
83
     * @return array<string, string>
84
     *
85
     * @phpstan-return non-empty-array<string, string>
86
     *
87
     * @see createHeader()
88
     *
89
     * @phpstan-param FormattedRecord $record
90
     */
91
    protected function createRecordHeader(array $record): array
92
    {
93
        // Wildfire is extensible to support multiple protocols & plugins in a single request,
94
        // but we're not taking advantage of that (yet), so we're using "1" for simplicity's sake.
95
        return $this->createHeader(
96
            [1, 1, 1, self::$messageIndex++],
97
            $record['formatted']
98
        );
99
    }
100
 
101
    /**
102
     * {@inheritDoc}
103
     */
104
    protected function getDefaultFormatter(): FormatterInterface
105
    {
106
        return new WildfireFormatter();
107
    }
108
 
109
    /**
110
     * Wildfire initialization headers to enable message parsing
111
     *
112
     * @see createHeader()
113
     * @see sendHeader()
114
     *
115
     * @return array<string, string>
116
     */
117
    protected function getInitHeaders(): array
118
    {
119
        // Initial payload consists of required headers for Wildfire
120
        return array_merge(
121
            $this->createHeader(['Protocol', 1], static::PROTOCOL_URI),
122
            $this->createHeader([1, 'Structure', 1], static::STRUCTURE_URI),
123
            $this->createHeader([1, 'Plugin', 1], static::PLUGIN_URI)
124
        );
125
    }
126
 
127
    /**
128
     * Send header string to the client
129
     */
130
    protected function sendHeader(string $header, string $content): void
131
    {
132
        if (!headers_sent() && self::$sendHeaders) {
133
            header(sprintf('%s: %s', $header, $content));
134
        }
135
    }
136
 
137
    /**
138
     * Creates & sends header for a record, ensuring init headers have been sent prior
139
     *
140
     * @see sendHeader()
141
     * @see sendInitHeaders()
142
     */
143
    protected function write(array $record): void
144
    {
145
        if (!self::$sendHeaders || !$this->isWebRequest()) {
146
            return;
147
        }
148
 
149
        // WildFire-specific headers must be sent prior to any messages
150
        if (!self::$initialized) {
151
            self::$initialized = true;
152
 
153
            self::$sendHeaders = $this->headersAccepted();
154
            if (!self::$sendHeaders) {
155
                return;
156
            }
157
 
158
            foreach ($this->getInitHeaders() as $header => $content) {
159
                $this->sendHeader($header, $content);
160
            }
161
        }
162
 
163
        $header = $this->createRecordHeader($record);
164
        if (trim(current($header)) !== '') {
165
            $this->sendHeader(key($header), current($header));
166
        }
167
    }
168
 
169
    /**
170
     * Verifies if the headers are accepted by the current user agent
171
     */
172
    protected function headersAccepted(): bool
173
    {
174
        if (!empty($_SERVER['HTTP_USER_AGENT']) && preg_match('{\bFirePHP/\d+\.\d+\b}', $_SERVER['HTTP_USER_AGENT'])) {
175
            return true;
176
        }
177
 
178
        return isset($_SERVER['HTTP_X_FIREPHP_VERSION']);
179
    }
180
}