PluginProbe
WPIDE – File Manager & Code Editor / 3.5.9
WPIDE – File Manager & Code Editor v3.5.9
3.5.9 3.5.8 3.5.7 2.0.14 2.0.15 2.0.16 2.0.2 2.0.4 2.0.5 2.0.6 2.0.7 2.0.8 2.0.9 2.1 2.2 2.3 2.3.1 2.3.2 2.4.0 2.5 2.6 3.0 3.1 3.2 3.3 All 55 releases
wpide / vendor / symfony / mime / Header / AbstractHeader.php

AbstractHeader.php in WPIDE – File Manager & Code Editor 3.5.9, at vendor/symfony/mime/Header/AbstractHeader.php

299 lines 10.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
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 Symfony\Component\Mime\Header;
13
14 use Symfony\Component\Mime\Encoder\QpMimeHeaderEncoder;
15
16 /**
17 * An abstract base MIME Header.
18 *
19 * @author Chris Corbyn
20 */
21 abstract class AbstractHeader implements HeaderInterface
22 {
23 public const PHRASE_PATTERN = '(?:(?:(?:(?:(?:(?:(?:[ \t]*(?:\r\n))?[ \t])?(\((?:(?:(?:[ \t]*(?:\r\n))?[ \t])|(?:(?:[\x01-\x08\x0B\x0C\x0E-\x19\x7F]|[\x21-\x27\x2A-\x5B\x5D-\x7E])|(?:\\[\x00-\x08\x0B\x0C\x0E-\x7F])|(?1)))*(?:(?:[ \t]*(?:\r\n))?[ \t])?\)))*(?:(?:(?:(?:[ \t]*(?:\r\n))?[ \t])?(\((?:(?:(?:[ \t]*(?:\r\n))?[ \t])|(?:(?:[\x01-\x08\x0B\x0C\x0E-\x19\x7F]|[\x21-\x27\x2A-\x5B\x5D-\x7E])|(?:\\[\x00-\x08\x0B\x0C\x0E-\x7F])|(?1)))*(?:(?:[ \t]*(?:\r\n))?[ \t])?\)))|(?:(?:[ \t]*(?:\r\n))?[ \t])))?[a-zA-Z0-9!#\$%&\'\*\+\-\/=\?\^_`\{\}\|~]+(?:(?:(?:(?:[ \t]*(?:\r\n))?[ \t])?(\((?:(?:(?:[ \t]*(?:\r\n))?[ \t])|(?:(?:[\x01-\x08\x0B\x0C\x0E-\x19\x7F]|[\x21-\x27\x2A-\x5B\x5D-\x7E])|(?:\\[\x00-\x08\x0B\x0C\x0E-\x7F])|(?1)))*(?:(?:[ \t]*(?:\r\n))?[ \t])?\)))*(?:(?:(?:(?:[ \t]*(?:\r\n))?[ \t])?(\((?:(?:(?:[ \t]*(?:\r\n))?[ \t])|(?:(?:[\x01-\x08\x0B\x0C\x0E-\x19\x7F]|[\x21-\x27\x2A-\x5B\x5D-\x7E])|(?:\\[\x00-\x08\x0B\x0C\x0E-\x7F])|(?1)))*(?:(?:[ \t]*(?:\r\n))?[ \t])?\)))|(?:(?:[ \t]*(?:\r\n))?[ \t])))?)|(?:(?:(?:(?:(?:[ \t]*(?:\r\n))?[ \t])?(\((?:(?:(?:[ \t]*(?:\r\n))?[ \t])|(?:(?:[\x01-\x08\x0B\x0C\x0E-\x19\x7F]|[\x21-\x27\x2A-\x5B\x5D-\x7E])|(?:\\[\x00-\x08\x0B\x0C\x0E-\x7F])|(?1)))*(?:(?:[ \t]*(?:\r\n))?[ \t])?\)))*(?:(?:(?:(?:[ \t]*(?:\r\n))?[ \t])?(\((?:(?:(?:[ \t]*(?:\r\n))?[ \t])|(?:(?:[\x01-\x08\x0B\x0C\x0E-\x19\x7F]|[\x21-\x27\x2A-\x5B\x5D-\x7E])|(?:\\[\x00-\x08\x0B\x0C\x0E-\x7F])|(?1)))*(?:(?:[ \t]*(?:\r\n))?[ \t])?\)))|(?:(?:[ \t]*(?:\r\n))?[ \t])))?"((?:(?:[ \t]*(?:\r\n))?[ \t])?(?:(?:[\x01-\x08\x0B\x0C\x0E-\x19\x7F]|[\x21\x23-\x5B\x5D-\x7E])|(?:\\[\x00-\x08\x0B\x0C\x0E-\x7F])))*(?:(?:[ \t]*(?:\r\n))?[ \t])?"(?:(?:(?:(?:[ \t]*(?:\r\n))?[ \t])?(\((?:(?:(?:[ \t]*(?:\r\n))?[ \t])|(?:(?:[\x01-\x08\x0B\x0C\x0E-\x19\x7F]|[\x21-\x27\x2A-\x5B\x5D-\x7E])|(?:\\[\x00-\x08\x0B\x0C\x0E-\x7F])|(?1)))*(?:(?:[ \t]*(?:\r\n))?[ \t])?\)))*(?:(?:(?:(?:[ \t]*(?:\r\n))?[ \t])?(\((?:(?:(?:[ \t]*(?:\r\n))?[ \t])|(?:(?:[\x01-\x08\x0B\x0C\x0E-\x19\x7F]|[\x21-\x27\x2A-\x5B\x5D-\x7E])|(?:\\[\x00-\x08\x0B\x0C\x0E-\x7F])|(?1)))*(?:(?:[ \t]*(?:\r\n))?[ \t])?\)))|(?:(?:[ \t]*(?:\r\n))?[ \t])))?))+?)';
24
25 private static $encoder;
26
27 private $name;
28 private $lineLength = 76;
29 private $lang;
30 private $charset = 'utf-8';
31
32 public function __construct(string $name)
33 {
34 $this->name = $name;
35 }
36
37 public function setCharset(string $charset)
38 {
39 $this->charset = $charset;
40 }
41
42 public function getCharset(): ?string
43 {
44 return $this->charset;
45 }
46
47 /**
48 * Set the language used in this Header.
49 *
50 * For example, for US English, 'en-us'.
51 */
52 public function setLanguage(string $lang)
53 {
54 $this->lang = $lang;
55 }
56
57 public function getLanguage(): ?string
58 {
59 return $this->lang;
60 }
61
62 public function getName(): string
63 {
64 return $this->name;
65 }
66
67 public function setMaxLineLength(int $lineLength)
68 {
69 $this->lineLength = $lineLength;
70 }
71
72 public function getMaxLineLength(): int
73 {
74 return $this->lineLength;
75 }
76
77 public function toString(): string
78 {
79 return $this->tokensToString($this->toTokens());
80 }
81
82 /**
83 * Produces a compliant, formatted RFC 2822 'phrase' based on the string given.
84 *
85 * @param string $string as displayed
86 * @param bool $shorten the first line to make remove for header name
87 */
88 protected function createPhrase(HeaderInterface $header, string $string, string $charset, bool $shorten = false): string
89 {
90 // Treat token as exactly what was given
91 $phraseStr = $string;
92
93 // If it's not valid
94 if (!preg_match('/^'.self::PHRASE_PATTERN.'$/D', $phraseStr)) {
95 // .. but it is just ascii text, try escaping some characters
96 // and make it a quoted-string
97 if (preg_match('/^[\x00-\x08\x0B\x0C\x0E-\x7F]*$/D', $phraseStr)) {
98 foreach (['\\', '"'] as $char) {
99 $phraseStr = str_replace($char, '\\'.$char, $phraseStr);
100 }
101 $phraseStr = '"'.$phraseStr.'"';
102 } else {
103 // ... otherwise it needs encoding
104 // Determine space remaining on line if first line
105 if ($shorten) {
106 $usedLength = \strlen($header->getName().': ');
107 } else {
108 $usedLength = 0;
109 }
110 $phraseStr = $this->encodeWords($header, $string, $usedLength);
111 }
112 } elseif (str_contains($phraseStr, '(')) {
113 foreach (['\\', '"'] as $char) {
114 $phraseStr = str_replace($char, '\\'.$char, $phraseStr);
115 }
116 $phraseStr = '"'.$phraseStr.'"';
117 }
118
119 return $phraseStr;
120 }
121
122 /**
123 * Encode needed word tokens within a string of input.
124 */
125 protected function encodeWords(HeaderInterface $header, string $input, int $usedLength = -1): string
126 {
127 $value = '';
128 $tokens = $this->getEncodableWordTokens($input);
129 foreach ($tokens as $token) {
130 // See RFC 2822, Sect 2.2 (really 2.2 ??)
131 if ($this->tokenNeedsEncoding($token)) {
132 // Don't encode starting WSP
133 $firstChar = substr($token, 0, 1);
134 switch ($firstChar) {
135 case ' ':
136 case "\t":
137 $value .= $firstChar;
138 $token = substr($token, 1);
139 }
140
141 if (-1 == $usedLength) {
142 $usedLength = \strlen($header->getName().': ') + \strlen($value);
143 }
144 $value .= $this->getTokenAsEncodedWord($token, $usedLength);
145 } else {
146 $value .= $token;
147 }
148 }
149
150 return $value;
151 }
152
153 protected function tokenNeedsEncoding(string $token): bool
154 {
155 return (bool) preg_match('~[\x00-\x08\x10-\x19\x7F-\xFF\r\n]~', $token);
156 }
157
158 /**
159 * Splits a string into tokens in blocks of words which can be encoded quickly.
160 *
161 * @return string[]
162 */
163 protected function getEncodableWordTokens(string $string): array
164 {
165 $tokens = [];
166 $encodedToken = '';
167 // Split at all whitespace boundaries
168 foreach (preg_split('~(?=[\t ])~', $string) as $token) {
169 if ($this->tokenNeedsEncoding($token)) {
170 $encodedToken .= $token;
171 } else {
172 if ('' !== $encodedToken) {
173 $tokens[] = $encodedToken;
174 $encodedToken = '';
175 }
176 $tokens[] = $token;
177 }
178 }
179 if ('' !== $encodedToken) {
180 $tokens[] = $encodedToken;
181 }
182
183 foreach ($tokens as $i => $token) {
184 // whitespace(s) between 2 encoded tokens
185 if (
186 0 < $i
187 && isset($tokens[$i + 1])
188 && preg_match('~^[\t ]+$~', $token)
189 && $this->tokenNeedsEncoding($tokens[$i - 1])
190 && $this->tokenNeedsEncoding($tokens[$i + 1])
191 ) {
192 $tokens[$i - 1] .= $token.$tokens[$i + 1];
193 array_splice($tokens, $i, 2);
194 }
195 }
196
197 return $tokens;
198 }
199
200 /**
201 * Get a token as an encoded word for safe insertion into headers.
202 */
203 protected function getTokenAsEncodedWord(string $token, int $firstLineOffset = 0): string
204 {
205 if (null === self::$encoder) {
206 self::$encoder = new QpMimeHeaderEncoder();
207 }
208
209 // Adjust $firstLineOffset to account for space needed for syntax
210 $charsetDecl = $this->charset;
211 if (null !== $this->lang) {
212 $charsetDecl .= '*'.$this->lang;
213 }
214 $encodingWrapperLength = \strlen('=?'.$charsetDecl.'?'.self::$encoder->getName().'??=');
215
216 if ($firstLineOffset >= 75) {
217 // Does this logic need to be here?
218 $firstLineOffset = 0;
219 }
220
221 $encodedTextLines = explode("\r\n",
222 self::$encoder->encodeString($token, $this->charset, $firstLineOffset, 75 - $encodingWrapperLength)
223 );
224
225 if ('iso-2022-jp' !== strtolower($this->charset)) {
226 // special encoding for iso-2022-jp using mb_encode_mimeheader
227 foreach ($encodedTextLines as $lineNum => $line) {
228 $encodedTextLines[$lineNum] = '=?'.$charsetDecl.'?'.self::$encoder->getName().'?'.$line.'?=';
229 }
230 }
231
232 return implode("\r\n ", $encodedTextLines);
233 }
234
235 /**
236 * Generates tokens from the given string which include CRLF as individual tokens.
237 *
238 * @return string[]
239 */
240 protected function generateTokenLines(string $token): array
241 {
242 return preg_split('~(\r\n)~', $token, -1, \PREG_SPLIT_DELIM_CAPTURE);
243 }
244
245 /**
246 * Generate a list of all tokens in the final header.
247 */
248 protected function toTokens(?string $string = null): array
249 {
250 if (null === $string) {
251 $string = $this->getBodyAsString();
252 }
253
254 $tokens = [];
255 // Generate atoms; split at all invisible boundaries followed by WSP
256 foreach (preg_split('~(?=[ \t])~', $string) as $token) {
257 $newTokens = $this->generateTokenLines($token);
258 foreach ($newTokens as $newToken) {
259 $tokens[] = $newToken;
260 }
261 }
262
263 return $tokens;
264 }
265
266 /**
267 * Takes an array of tokens which appear in the header and turns them into
268 * an RFC 2822 compliant string, adding FWSP where needed.
269 *
270 * @param string[] $tokens
271 */
272 private function tokensToString(array $tokens): string
273 {
274 $lineCount = 0;
275 $headerLines = [];
276 $headerLines[] = $this->name.': ';
277 $currentLine = &$headerLines[$lineCount++];
278
279 // Build all tokens back into compliant header
280 foreach ($tokens as $i => $token) {
281 // Line longer than specified maximum or token was just a new line
282 if (("\r\n" === $token) ||
283 ($i > 0 && \strlen($currentLine.$token) > $this->lineLength)
284 && '' !== $currentLine) {
285 $headerLines[] = '';
286 $currentLine = &$headerLines[$lineCount++];
287 }
288
289 // Append token to the line
290 if ("\r\n" !== $token) {
291 $currentLine .= $token;
292 }
293 }
294
295 // Implode with FWS (RFC 2822, 2.2.3)
296 return implode("\r\n", $headerLines);
297 }
298 }
299