Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commiteee2a20

Browse files
committed
[HttpFoundation] Add HeaderUtility class
1 parentb43bdf3 commiteee2a20

File tree

11 files changed

+332
-75
lines changed

11 files changed

+332
-75
lines changed

‎src/Symfony/Component/HttpFoundation/AcceptHeader.php‎

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,12 +52,17 @@ public static function fromString($headerValue)
5252
{
5353
$index =0;
5454

55-
returnnewself(array_map(function ($itemValue)use (&$index) {
56-
$item = AcceptHeaderItem::fromString($itemValue);
55+
$parts = HeaderUtils::split((string)$headerValue,',;=');
56+
57+
returnnewself(array_map(function ($subParts)use (&$index) {
58+
$part =array_shift($subParts);
59+
$attributes = HeaderUtils::combineParts($subParts);
60+
61+
$item =newAcceptHeaderItem($part[0],$attributes);
5762
$item->setIndex($index++);
5863

5964
return$item;
60-
},preg_split('/\s*(?:,*("[^"]+"),*|,*(\'[^\']+\'),*|,+)\s*/',$headerValue,0,PREG_SPLIT_NO_EMPTY |PREG_SPLIT_DELIM_CAPTURE)));
65+
},$parts));
6166
}
6267

6368
/**

‎src/Symfony/Component/HttpFoundation/AcceptHeaderItem.php‎

Lines changed: 6 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -59,24 +59,12 @@ public function __construct($value, array $attributes = array())
5959
*/
6060
publicstaticfunctionfromString($itemValue)
6161
{
62-
$bits =preg_split('/\s*(?:;*("[^"]+");*|;*(\'[^\']+\');*|;+)\s*/',$itemValue,0,PREG_SPLIT_NO_EMPTY |PREG_SPLIT_DELIM_CAPTURE);
63-
$value =array_shift($bits);
64-
$attributes =array();
65-
66-
$lastNullAttribute =null;
67-
foreach ($bitsas$bit) {
68-
if (($start =substr($bit,0,1)) === ($end =substr($bit, -1)) && ('"' ===$start ||'\'' ===$start)) {
69-
$attributes[$lastNullAttribute] =substr($bit,1, -1);
70-
}elseif ('=' ===$end) {
71-
$lastNullAttribute =$bit =substr($bit,0, -1);
72-
$attributes[$bit] =null;
73-
}else {
74-
$parts =explode('=',$bit);
75-
$attributes[$parts[0]] =isset($parts[1]) &&strlen($parts[1]) >0 ?$parts[1] :'';
76-
}
77-
}
62+
$parts = HeaderUtils::split($itemValue,';=');
63+
64+
$part =array_shift($parts);
65+
$attributes = HeaderUtils::combineParts($parts,1);
7866

79-
returnnewself(($start =substr($value,0,1)) === ($end =substr($value, -1)) && ('"' ===$start ||'\'' ===$start) ?substr($value,1, -1) :$value,$attributes);
67+
returnnewself($part[0],$attributes);
8068
}
8169

8270
/**
@@ -88,9 +76,7 @@ public function __toString()
8876
{
8977
$string =$this->value.($this->quality <1 ?';q='.$this->quality :'');
9078
if (count($this->attributes) >0) {
91-
$string .=';'.implode(';',array_map(function ($name,$value) {
92-
returnsprintf(preg_match('/[,;=]/',$value) ?'%s="%s"' :'%s=%s',$name,$value);
93-
},array_keys($this->attributes),$this->attributes));
79+
$string .=';'.HeaderUtils::joinAssoc($this->attributes,';');
9480
}
9581

9682
return$string;

‎src/Symfony/Component/HttpFoundation/CHANGELOG.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ CHANGELOG
99
* deprecated setting session save handlers that do not implement`\SessionHandlerInterface` in`NativeSessionStorage::setSaveHandler()`
1010
* deprecated using`MongoDbSessionHandler` with the legacy mongo extension; use it with the mongodb/mongodb package and ext-mongodb instead
1111
* deprecated`MemcacheSessionHandler`; use`MemcachedSessionHandler` instead
12+
* added`HeaderUtility`
1213

1314
3.3.0
1415
-----

‎src/Symfony/Component/HttpFoundation/Cookie.php‎

Lines changed: 12 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -50,34 +50,20 @@ public static function fromString($cookie, $decode = false)
5050
'raw' => !$decode,
5151
'samesite' =>null,
5252
);
53-
foreach (explode(';',$cookie)as$part) {
54-
if (false ===strpos($part,'=')) {
55-
$key =trim($part);
56-
$value =true;
57-
}else {
58-
list($key,$value) =explode('=',trim($part),2);
59-
$key =trim($key);
60-
$value =trim($value);
61-
}
62-
if (!isset($data['name'])) {
63-
$data['name'] =$decode ?urldecode($key) :$key;
64-
$data['value'] =true ===$value ?null : ($decode ?urldecode($value) :$value);
65-
continue;
66-
}
67-
switch ($key =strtolower($key)) {
68-
case'name':
69-
case'value':
70-
break;
71-
case'max-age':
72-
$data['expires'] =time() + (int)$value;
73-
break;
74-
default:
75-
$data[$key] =$value;
76-
break;
77-
}
53+
54+
$parts = HeaderUtils::split($cookie,';=');
55+
$part =array_shift($parts);
56+
57+
$name =$decode ?urldecode($part[0]) :$part[0];
58+
$value =isset($part[1]) ? ($decode ?urldecode($part[1]) :$part[1]) :null;
59+
60+
$data = HeaderUtils::combineParts($parts) +$data;
61+
62+
if (isset($data['max-age'])) {
63+
$data['expires'] =time() + (int)$data['max-age'];
7864
}
7965

80-
returnnewstatic($data['name'],$data['value'],$data['expires'],$data['path'],$data['domain'],$data['secure'],$data['httponly'],$data['raw'],$data['samesite']);
66+
returnnewstatic($name,$value,$data['expires'],$data['path'],$data['domain'],$data['secure'],$data['httponly'],$data['raw'],$data['samesite']);
8167
}
8268

8369
/**

‎src/Symfony/Component/HttpFoundation/HeaderBag.php‎

Lines changed: 3 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -286,21 +286,9 @@ public function count()
286286

287287
protectedfunctiongetCacheControlHeader()
288288
{
289-
$parts =array();
290289
ksort($this->cacheControl);
291-
foreach ($this->cacheControlas$key =>$value) {
292-
if (true ===$value) {
293-
$parts[] =$key;
294-
}else {
295-
if (preg_match('#[^a-zA-Z0-9._-]#',$value)) {
296-
$value ='"'.$value.'"';
297-
}
298-
299-
$parts[] ="$key=$value";
300-
}
301-
}
302290

303-
returnimplode(',',$parts);
291+
returnHeaderUtils::joinAssoc($this->cacheControl,',');
304292
}
305293

306294
/**
@@ -312,12 +300,8 @@ protected function getCacheControlHeader()
312300
*/
313301
protectedfunctionparseCacheControl($header)
314302
{
315-
$cacheControl =array();
316-
preg_match_all('#([a-zA-Z][a-zA-Z_-]*)\s*(?:=(?:"([^"]*)"|([^ \t",;]*)))?#',$header,$matches,PREG_SET_ORDER);
317-
foreach ($matchesas$match) {
318-
$cacheControl[strtolower($match[1])] =isset($match[3]) ?$match[3] : (isset($match[2]) ?$match[2] :true);
319-
}
303+
$parts = HeaderUtils::split($header,',=');
320304

321-
return$cacheControl;
305+
returnHeaderUtils::combineParts($parts);
322306
}
323307
}
Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
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+
namespaceSymfony\Component\HttpFoundation;
13+
14+
/**
15+
* HTTP header utility functions.
16+
*
17+
* @author Christian Schmidt <github@chsc.dk>
18+
*/
19+
class HeaderUtils
20+
{
21+
/**
22+
* This class should not be instantiated.
23+
*/
24+
privatefunction__construct()
25+
{
26+
}
27+
28+
/**
29+
* Splits an HTTP header by one or more separators.
30+
*
31+
* Example:
32+
*
33+
* HeaderUtils::split("da, en-gb;q=0.8", ",;")
34+
* // => array(array("da"), array("en-gb"), array("q", "0.8"))
35+
*
36+
* @param string $header HTTP header value
37+
* @param string $separators List of characters to split on, ordered by
38+
* precedence, e.g. ",", ";=", or ",;="
39+
*
40+
* @return array Nested array with as many levels as there are characters in
41+
* $separators
42+
*/
43+
publicstaticfunctionsplit(string$header,$separators)
44+
{
45+
$quotedSeparators =preg_quote($separators);
46+
47+
preg_match_all('
48+
/
49+
(?!\s)
50+
(?:
51+
# quoted-string
52+
"(?:[^"\\\\]|\\\\.)*(?:"|\\\\|$)
53+
|
54+
# token
55+
[^"'.$quotedSeparators.']+
56+
)+
57+
(?<!\s)
58+
|
59+
# separator
60+
\s*
61+
(?<separator>['.$quotedSeparators.'])
62+
\s*
63+
/x',trim($header),$matches,PREG_SET_ORDER);
64+
65+
returnself::groupParts($matches,$separators);
66+
}
67+
68+
privatestaticfunctiongroupParts(array$matches,$separators)
69+
{
70+
$separator =$separators[0];
71+
$partSeparators =substr($separators,1);
72+
73+
$i =0;
74+
$partMatches =array();
75+
foreach ($matchesas$match) {
76+
if (isset($match['separator']) &&$match['separator'] ===$separator) {
77+
++$i;
78+
}else {
79+
$partMatches[$i][] =$match;
80+
}
81+
}
82+
83+
$parts =array();
84+
if ($partSeparators) {
85+
foreach ($partMatchesas$matches) {
86+
$parts[] =self::groupParts($matches,$partSeparators);
87+
}
88+
}else {
89+
foreach ($partMatchesas$matches) {
90+
$parts[] =self::unquote($matches[0][0]);
91+
}
92+
}
93+
94+
return$parts;
95+
}
96+
97+
/**
98+
* Combines an array of arrays into one associative array.
99+
*
100+
* Each of the nested arrays should have one or two elements. The first
101+
* value will be used as the keys in the associative array, and the second
102+
* will be used as the values, or true if the nested array only contains one
103+
* element.
104+
*
105+
* Example:
106+
*
107+
* HeaderUtils::combineParts(array(array("foo", "abc"), array("bar")))
108+
* // => array("foo" => "abc", "bar" => true)
109+
*
110+
* @param array $parts Array of arrays
111+
*
112+
* @return array Associative array
113+
*/
114+
publicstaticfunctioncombineParts(array$parts)
115+
{
116+
$assoc =array();
117+
foreach ($partsas$part) {
118+
$name =strtolower($part[0]);
119+
$value =isset($part[1]) ?$part[1] :true;
120+
$assoc[$name] =$value;
121+
}
122+
123+
return$assoc;
124+
}
125+
126+
/**
127+
* Joins an associative array into a string.
128+
*
129+
* The key and value of each entry are joined with "=", and all entries
130+
* is joined with the specified separator and an additional space (for
131+
* readability). Values are quoted if necessary.
132+
*
133+
* Example:
134+
*
135+
* HeaderUtils::joinAssoc(array("foo" => "abc", "bar" => true, "baz" => "a b c"), ",")
136+
* // => 'foo=bar, baz, baz="a b c"'
137+
*
138+
* @param array $assoc The associative array
139+
* @param string $separator Separator between each array entry
140+
*
141+
* @return string A string formatted for use in an HTTP header
142+
*/
143+
publicstaticfunctionjoinAssoc(array$assoc,$separator)
144+
{
145+
$parts =array();
146+
foreach ($assocas$name =>$value) {
147+
if (true ===$value) {
148+
$parts[] =$name;
149+
}else {
150+
$parts[] =$name.'='.self::quote($value);
151+
}
152+
}
153+
154+
returnimplode($separator.'',$parts);
155+
}
156+
157+
/**
158+
* Encodes a string as a quoted string, if necessary.
159+
*
160+
* If a string contains characters not allowed by the "token" construct in
161+
* the HTTP specification, it is backslash-escaped and enclosed in quotes
162+
* to match the "quoted-string" construct.
163+
*
164+
* @param string $s The raw string
165+
*
166+
* @return return The quoted string
167+
*/
168+
publicstaticfunctionquote($s)
169+
{
170+
if (preg_match('/^[a-z0-9!#$%&\'*.^_`|~-]+$/i',$s)) {
171+
return$s;
172+
}
173+
174+
return'"'.addcslashes($s,'"\\"').'"';
175+
}
176+
177+
/**
178+
* Decodes a quoted string.
179+
*
180+
* If passed an unquoted string that matches the "token" construct (as
181+
* defined in the HTTP specification), it is passed through verbatimly.
182+
*
183+
* @param string $s The quoted string
184+
*
185+
* @return string The raw string
186+
*/
187+
publicstaticfunctionunquote($s)
188+
{
189+
returnpreg_replace('/\\\\(.)|"/','$1',$s);
190+
}
191+
}

‎src/Symfony/Component/HttpFoundation/Request.php‎

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2075,8 +2075,16 @@ private function getTrustedValues($type, $ip = null)
20752075
}
20762076

20772077
if (self::$trustedHeaders[self::HEADER_FORWARDED] &&$this->headers->has(self::$trustedHeaders[self::HEADER_FORWARDED])) {
2078-
$forwardedValues =$this->headers->get(self::$trustedHeaders[self::HEADER_FORWARDED]);
2079-
$forwardedValues =preg_match_all(sprintf('{(?:%s)=(?:"?\[?)([a-zA-Z0-9\.:_\-/]*+)}',self::$forwardedParams[$type]),$forwardedValues,$matches) ?$matches[1] :array();
2078+
$forwarded =$this->headers->get(self::$trustedHeaders[self::HEADER_FORWARDED]);
2079+
$parts = HeaderUtils::split($forwarded,',;=');
2080+
$forwardedValues =array();
2081+
$param =self::$forwardedParams[$type];
2082+
foreach ($partsas$subParts) {
2083+
$assoc = HeaderUtils::combineParts($subParts);
2084+
if (isset($assoc[$param])) {
2085+
$forwardedValues[] =$assoc[$param];
2086+
}
2087+
}
20802088
}
20812089

20822090
if (null !==$ip) {
@@ -2109,9 +2117,17 @@ private function normalizeAndFilterClientIps(array $clientIps, $ip)
21092117
$firstTrustedIp =null;
21102118

21112119
foreach ($clientIpsas$key =>$clientIp) {
2112-
// Remove port (unfortunately, it does happen)
2113-
if (preg_match('{((?:\d+\.){3}\d+)\:\d+}',$clientIp,$match)) {
2114-
$clientIps[$key] =$clientIp =$match[1];
2120+
if (strpos($clientIp,'.')) {
2121+
// Strip :port from IPv4 addresses. This is allowed in Forwarded
2122+
// and may occur in X-Forwarded-For.
2123+
$i =strpos($clientIp,':');
2124+
if ($i) {
2125+
$clientIps[$key] =$clientIp =substr($clientIp,0,$i);
2126+
}
2127+
}elseif ('[' ==$clientIp[0]) {
2128+
// Strip brackets and :port from IPv6 addresses.
2129+
$i =strpos($clientIp,']',1);
2130+
$clientIps[$key] =$clientIp =substr($clientIp,1,$i -1);
21152131
}
21162132

21172133
if (!filter_var($clientIp,FILTER_VALIDATE_IP)) {

‎src/Symfony/Component/HttpFoundation/Tests/AcceptHeaderItemTest.php‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ public function provideToStringData()
6666
),
6767
array(
6868
'text/plain',array('charset' =>'utf-8','param' =>'this;should,not=matter','footnotes' =>'true'),
69-
'text/plain;charset=utf-8;param="this;should,not=matter";footnotes=true',
69+
'text/plain;charset=utf-8;param="this;should,not=matter";footnotes=true',
7070
),
7171
);
7272
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp