Completed
Push — master ( 181b09...502d72 )
by Carlos
04:01
created

GuzzleMessageFormatter::headers()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 4
nc 2
nop 1
dl 0
loc 8
rs 9.4285
c 0
b 0
f 0
1
<?php
2
namespace EasyWeChat\Kernel\Support;
3
4
use Psr\Http\Message\MessageInterface;
5
use Psr\Http\Message\RequestInterface;
6
use Psr\Http\Message\ResponseInterface;
7
8
/**
9
 * Formats log messages using variable substitutions for requests, responses,
10
 * and other transactional data.
11
 *
12
 * The following variable substitutions are supported:
13
 *
14
 * - {request}:        Full HTTP request message
15
 * - {response}:       Full HTTP response message
16
 * - {ts}:             ISO 8601 date in GMT
17
 * - {date_iso_8601}   ISO 8601 date in GMT
18
 * - {date_common_log} Apache common log date using the configured timezone.
19
 * - {host}:           Host of the request
20
 * - {method}:         Method of the request
21
 * - {uri}:            URI of the request
22
 * - {host}:           Host of the request
23
 * - {version}:        Protocol version
24
 * - {target}:         Request target of the request (path + query + fragment)
25
 * - {hostname}:       Hostname of the machine that sent the request
26
 * - {code}:           Status code of the response (if available)
27
 * - {phrase}:         Reason phrase of the response  (if available)
28
 * - {error}:          Any error messages (if available)
29
 * - {req_header_*}:   Replace `*` with the lowercased name of a request header to add to the message
30
 * - {res_header_*}:   Replace `*` with the lowercased name of a response header to add to the message
31
 * - {req_headers}:    Request headers
32
 * - {res_headers}:    Response headers
33
 * - {req_body}:       Request body
34
 * - {res_body}:       Response body
35
 */
36
class GuzzleMessageFormatter
37
{
38
    /**
39
     * Apache Common Log Format.
40
     * @link http://httpd.apache.org/docs/2.4/logs.html#common
41
     * @var string
42
     */
43
    const CLF = "{hostname} {req_header_User-Agent} - [{date_common_log}] \"{method} {target} HTTP/{version}\" {code} {res_header_Content-Length}";
0 ignored issues
show
Coding Style Comprehensibility introduced by
The string literal {hostname} {req_header_U..._header_Content-Length} does not require double quotes, as per coding-style, please use single quotes.

PHP provides two ways to mark string literals. Either with single quotes 'literal' or with double quotes "literal". The difference between these is that string literals in double quotes may contain variables with are evaluated at run-time as well as escape sequences.

String literals in single quotes on the other hand are evaluated very literally and the only two characters that needs escaping in the literal are the single quote itself (\') and the backslash (\\). Every other character is displayed as is.

Double quoted string literals may contain other variables or more complex escape sequences.

<?php

$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";

print $doubleQuoted;

will print an indented: Single is Value

If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear.

For more information on PHP string literals and available escape sequences see the PHP core documentation.

Loading history...
Coding Style introduced by
This line exceeds maximum limit of 140 characters; contains 147 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
44
    const DEBUG = ">>>>>>>>\n{request}\n<<<<<<<<\n{response}\n--------\n{error}";
45
    const SHORT = '[{ts}] "{method} {target} HTTP/{version}" {code}';
46
47
    /** @var string Template used to format log messages */
48
    private $template;
49
50
    /**
51
     * @param string $template Log message template
52
     */
53
    public function __construct($template = self::CLF)
54
    {
55
        $this->template = $template ?: self::CLF;
56
    }
57
58
    /**
59
     * Returns a formatted message string.
60
     *
61
     * @param RequestInterface  $request  Request that was sent
62
     * @param ResponseInterface $response Response that was received
63
     * @param \Exception        $error    Exception that was received
64
     *
65
     * @return string
66
     */
67
    public function format(
68
        RequestInterface $request,
69
        ResponseInterface $response = null,
70
        \Exception $error = null
71
    ) {
72
        $cache = [];
73
74
        return preg_replace_callback(
75
            '/{\s*([A-Za-z_\-\.0-9]+)\s*}/',
76
            function (array $matches) use ($request, $response, $error, &$cache) {
77
78
                if (isset($cache[$matches[1]])) {
79
                    return $cache[$matches[1]];
80
                }
81
82
                $result = '';
83
                switch ($matches[1]) {
84
                    case 'request':
85
                        $result = Psr7\str($request);
0 ignored issues
show
Bug introduced by
The function str was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

85
                        $result = /** @scrutinizer ignore-call */ Psr7\str($request);
Loading history...
86
                        break;
87
                    case 'response':
88
                        $result = $response ? Psr7\str($response) : '';
89
                        break;
90
                    case 'req_headers':
91
                        $result = trim($request->getMethod()
92
                                . ' ' . $request->getRequestTarget())
93
                            . ' HTTP/' . $request->getProtocolVersion() . "\r\n"
94
                            . $this->headers($request);
95
                        break;
96
                    case 'res_headers':
97
                        $result = $response ?
98
                            sprintf(
99
                                'HTTP/%s %d %s',
100
                                $response->getProtocolVersion(),
101
                                $response->getStatusCode(),
102
                                $response->getReasonPhrase()
103
                            ) . "\r\n" . $this->headers($response)
104
                            : 'NULL';
105
                        break;
106
                    case 'req_body':
107
                        $result = $request->getBody();
108
                        break;
109
                    case 'res_body':
110
                        $result = $response ? $response->getHeaderLine('Content-disposition') ? '<file-content>' : $response->getBody() : 'NULL';
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 140 characters; contains 145 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
111
                        break;
112
                    case 'ts':
113
                    case 'date_iso_8601':
114
                        $result = gmdate('c');
115
                        break;
116
                    case 'date_common_log':
117
                        $result = date('d/M/Y:H:i:s O');
118
                        break;
119
                    case 'method':
120
                        $result = $request->getMethod();
121
                        break;
122
                    case 'version':
123
                        $result = $request->getProtocolVersion();
124
                        break;
125
                    case 'uri':
126
                    case 'url':
127
                        $result = $request->getUri();
128
                        break;
129
                    case 'target':
130
                        $result = $request->getRequestTarget();
131
                        break;
132
                    case 'req_version':
133
                        $result = $request->getProtocolVersion();
134
                        break;
135
                    case 'res_version':
136
                        $result = $response
137
                            ? $response->getProtocolVersion()
138
                            : 'NULL';
139
                        break;
140
                    case 'host':
141
                        $result = $request->getHeaderLine('Host');
142
                        break;
143
                    case 'hostname':
144
                        $result = gethostname();
145
                        break;
146
                    case 'code':
147
                        $result = $response ? $response->getStatusCode() : 'NULL';
148
                        break;
149
                    case 'phrase':
150
                        $result = $response ? $response->getReasonPhrase() : 'NULL';
151
                        break;
152
                    case 'error':
153
                        $result = $error ? $error->getMessage() : 'NULL';
154
                        break;
155
                    default:
156
                        // handle prefixed dynamic headers
157
                        if (strpos($matches[1], 'req_header_') === 0) {
158
                            $result = $request->getHeaderLine(substr($matches[1], 11));
159
                        } elseif (strpos($matches[1], 'res_header_') === 0) {
160
                            $result = $response
161
                                ? $response->getHeaderLine(substr($matches[1], 11))
162
                                : 'NULL';
163
                        }
164
                }
165
166
                $cache[$matches[1]] = $result;
167
                return $result;
168
            },
169
            $this->template
170
        );
171
    }
172
173
    private function headers(MessageInterface $message)
174
    {
175
        $result = '';
176
        foreach ($message->getHeaders() as $name => $values) {
177
            $result .= $name . ': ' . implode(', ', $values) . "\r\n";
178
        }
179
180
        return trim($result);
181
    }
182
}
183