PluginProbe
WPFunnels – Funnel Builder for WooCommerce with Checkout & One Click Upsell / 2.8.16
WPFunnels – Funnel Builder for WooCommerce with Checkout & One Click Upsell v2.8.16
3.13.3 3.13.2 3.13.1 3.13.0 3.12.13 3.12.12 3.12.11 3.12.10 3.12.9 3.12.8 3.12.7 3.12.6 3.12.5 3.12.4 3.12.3 3.12.1 3.12.2 3.12.0 3.11.1 3.11.0 3.10.9 3.10.8 3.10.7 3.10.6 2.8.16 All 261 releases
wpfunnels / vendor / symfony / mime / Header / AbstractHeader.php

AbstractHeader.php in WPFunnels – Funnel Builder for WooCommerce with Checkout & One Click Upsell 2.8.16, at vendor/symfony/mime/Header/AbstractHeader.php

285 lines 10.6 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 <[email protected]>
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 return $tokens;
184 }
185
186 /**
187 * Get a token as an encoded word for safe insertion into headers.
188 */
189 protected function getTokenAsEncodedWord(string $token, int $firstLineOffset = 0): string
190 {
191 if (null === self::$encoder) {
192 self::$encoder = new QpMimeHeaderEncoder();
193 }
194
195 // Adjust $firstLineOffset to account for space needed for syntax
196 $charsetDecl = $this->charset;
197 if (null !== $this->lang) {
198 $charsetDecl .= '*'.$this->lang;
199 }
200 $encodingWrapperLength = \strlen('=?'.$charsetDecl.'?'.self::$encoder->getName().'??=');
201
202 if ($firstLineOffset >= 75) {
203 // Does this logic need to be here?
204 $firstLineOffset = 0;
205 }
206
207 $encodedTextLines = explode("\r\n",
208 self::$encoder->encodeString($token, $this->charset, $firstLineOffset, 75 - $encodingWrapperLength)
209 );
210
211 if ('iso-2022-jp' !== strtolower($this->charset)) {
212 // special encoding for iso-2022-jp using mb_encode_mimeheader
213 foreach ($encodedTextLines as $lineNum => $line) {
214 $encodedTextLines[$lineNum] = '=?'.$charsetDecl.'?'.self::$encoder->getName().'?'.$line.'?=';
215 }
216 }
217
218 return implode("\r\n ", $encodedTextLines);
219 }
220
221 /**
222 * Generates tokens from the given string which include CRLF as individual tokens.
223 *
224 * @return string[]
225 */
226 protected function generateTokenLines(string $token): array
227 {
228 return preg_split('~(\r\n)~', $token, -1, \PREG_SPLIT_DELIM_CAPTURE);
229 }
230
231 /**
232 * Generate a list of all tokens in the final header.
233 */
234 protected function toTokens(string $string = null): array
235 {
236 if (null === $string) {
237 $string = $this->getBodyAsString();
238 }
239
240 $tokens = [];
241 // Generate atoms; split at all invisible boundaries followed by WSP
242 foreach (preg_split('~(?=[ \t])~', $string) as $token) {
243 $newTokens = $this->generateTokenLines($token);
244 foreach ($newTokens as $newToken) {
245 $tokens[] = $newToken;
246 }
247 }
248
249 return $tokens;
250 }
251
252 /**
253 * Takes an array of tokens which appear in the header and turns them into
254 * an RFC 2822 compliant string, adding FWSP where needed.
255 *
256 * @param string[] $tokens
257 */
258 private function tokensToString(array $tokens): string
259 {
260 $lineCount = 0;
261 $headerLines = [];
262 $headerLines[] = $this->name.': ';
263 $currentLine = &$headerLines[$lineCount++];
264
265 // Build all tokens back into compliant header
266 foreach ($tokens as $i => $token) {
267 // Line longer than specified maximum or token was just a new line
268 if (("\r\n" === $token) ||
269 ($i > 0 && \strlen($currentLine.$token) > $this->lineLength)
270 && '' !== $currentLine) {
271 $headerLines[] = '';
272 $currentLine = &$headerLines[$lineCount++];
273 }
274
275 // Append token to the line
276 if ("\r\n" !== $token) {
277 $currentLine .= $token;
278 }
279 }
280
281 // Implode with FWS (RFC 2822, 2.2.3)
282 return implode("\r\n", $headerLines);
283 }
284 }
285