Skip to content
This repository was archived by the owner on Jan 29, 2020. It is now read-only.

Commit cdc3fd9

Browse files
authored
Merge branch 'develop' into add-csv-response-class
2 parents 8b5f22b + 1047073 commit cdc3fd9

17 files changed

+387
-55
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@
22
doc/html/
33
vendor/
44
zf-mkdoc-theme/
5+
/test/TestAsset/.cache/
56
phpunit.xml

.travis.yml

+3
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@ language: php
33
cache:
44
directories:
55
- $HOME/.composer/cache
6+
- test/TestAsset/.cache # Cache archives are currently set to expire after 28 days by default
67

78
env:
89
global:
910
- COMPOSER_ARGS="--no-interaction"
11+
- COVERAGE_DEPS="php-coveralls/php-coveralls"
1012

1113
matrix:
1214
include:
@@ -47,6 +49,7 @@ install:
4749
- travis_retry composer install $COMPOSER_ARGS
4850
- if [[ $DEPS == 'latest' ]]; then travis_retry composer update $COMPOSER_ARGS ; fi
4951
- if [[ $DEPS == 'lowest' ]]; then travis_retry composer update --prefer-lowest --prefer-stable $COMPOSER_ARGS ; fi
52+
- if [[ $TEST_COVERAGE == 'true' ]]; then travis_retry composer require --dev $COMPOSER_ARGS $COVERAGE_DEPS ; fi
5053
- stty cols 120 && composer show
5154

5255
script:

CHANGELOG.md

+95-3
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
All notable changes to this project will be documented in this file, in reverse chronological order by release.
44

5-
## 2.2.2
5+
## 2.2.0 - TBD
66

77
### Added
88

@@ -22,7 +22,99 @@ All notable changes to this project will be documented in this file, in reverse
2222

2323
### Fixed
2424

25-
- [#361](https://github.com/zendframework/zend-diactoros/pull/361) adds `CsvResponse` to the list of available Response classes. It supports sending CSV content with a `plain/csv` content-type response header, either as plain text or as a downloadable file. Adds `DownloadResponseTrait` which provides functionality for sending a response as a downloadable file.
25+
- Nothing.
26+
27+
## 2.1.6 - TBD
28+
29+
### Added
30+
31+
- Nothing.
32+
33+
### Changed
34+
35+
- Nothing.
36+
37+
### Deprecated
38+
39+
- Nothing.
40+
41+
### Removed
42+
43+
- Nothing.
44+
45+
### Fixed
46+
47+
- Nothing.
48+
49+
## 2.1.5 - 2019-10-10
50+
51+
### Added
52+
53+
- Nothing.
54+
55+
### Changed
56+
57+
- Nothing.
58+
59+
### Deprecated
60+
61+
- Nothing.
62+
63+
### Removed
64+
65+
- Nothing.
66+
67+
### Fixed
68+
69+
- [#372](https://github.com/zendframework/zend-diactoros/pull/372) fixes issues that occur in the `Zend\Diactoros\Uri` class when invalid UTF-8 characters are present the user-info, path, or query string, ensuring they are URL-encoded before being consumed. Previously, such characters could result in a fatal error, which was particularly problematic when marshaling the request URI for an application request cycle.
70+
71+
## 2.1.4 - 2019-10-08
72+
73+
### Added
74+
75+
- Nothing.
76+
77+
### Changed
78+
79+
- Nothing.
80+
81+
### Deprecated
82+
83+
- Nothing.
84+
85+
### Removed
86+
87+
- Nothing.
88+
89+
### Fixed
90+
91+
- [#370](https://github.com/zendframework/zend-diactoros/pull/370) updates `Zend\Diactoros\marshalHeadersFromSapi()` to ensure all underscores in header name keys are converted to dashes (fixing issues with header names such as `CONTENT_SECURITY_POLICY`, which would previously resolve improperly to `content-security_policy`).
92+
93+
- [#370](https://github.com/zendframework/zend-diactoros/pull/370) updates `Zend\Diactoros\marshalHeadersFromSapi()` to ignore header names from the `$server` array that resolve to integers; previously, it would raise a fatal error.
94+
95+
## 2.1.3 - 2019-07-10
96+
97+
### Added
98+
99+
- Nothing.
100+
101+
### Changed
102+
103+
- Nothing.
104+
105+
### Deprecated
106+
107+
- Nothing.
108+
109+
### Removed
110+
111+
- Nothing.
112+
113+
### Fixed
114+
115+
- [#363](https://github.com/zendframework/zend-diactoros/issues/363) modifies detection of HTTPS schemas via the `$_SERVER['HTTPS']` value
116+
such that an empty HTTPS-key will result in a scheme of `http` and not
117+
`https`.
26118

27119
## 2.1.2 - 2019-04-29
28120

@@ -1516,4 +1608,4 @@ First stable release, and first release as `zend-diactoros`.
15161608

15171609
### Fixed
15181610

1519-
- Nothing.
1611+
- Nothing.

composer.json

+1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
"psr/http-message": "^1.0"
3232
},
3333
"require-dev": {
34+
"ext-curl": "*",
3435
"ext-dom": "*",
3536
"ext-libxml": "*",
3637
"http-interop/http-factory-tests": "^0.5.0",

composer.lock

+10-9
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

phpunit.xml.dist

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
</filter>
1616

1717
<php>
18+
<env name="ALWAYS_REFRESH_IANA_HTTP_STATUS_CODES" value="false"/>
1819
<const name="REQUEST_FACTORY" value="Zend\Diactoros\RequestFactory"/>
1920
<const name="RESPONSE_FACTORY" value="Zend\Diactoros\ResponseFactory"/>
2021
<const name="SERVER_REQUEST_FACTORY" value="Zend\Diactoros\ServerRequestFactory"/>

src/Uri.php

+28-2
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,7 @@
1111

1212
use Psr\Http\Message\UriInterface;
1313

14-
use function array_key_exists;
1514
use function array_keys;
16-
use function count;
1715
use function explode;
1816
use function get_class;
1917
use function gettype;
@@ -23,10 +21,12 @@
2321
use function is_string;
2422
use function ltrim;
2523
use function parse_url;
24+
use function preg_match;
2625
use function preg_replace;
2726
use function preg_replace_callback;
2827
use function rawurlencode;
2928
use function sprintf;
29+
use function str_split;
3030
use function strpos;
3131
use function strtolower;
3232
use function substr;
@@ -560,6 +560,8 @@ private function filterScheme(string $scheme) : string
560560
*/
561561
private function filterUserInfoPart(string $part) : string
562562
{
563+
$part = $this->filterInvalidUtf8($part);
564+
563565
// Note the addition of `%` to initial charset; this allows `|` portion
564566
// to match and thus prevent double-encoding.
565567
return preg_replace_callback(
@@ -574,6 +576,8 @@ private function filterUserInfoPart(string $part) : string
574576
*/
575577
private function filterPath(string $path) : string
576578
{
579+
$path = $this->filterInvalidUtf8($path);
580+
577581
$path = preg_replace_callback(
578582
'/(?:[^' . self::CHAR_UNRESERVED . ')(:@&=\+\$,\/;%]+|%(?![A-Fa-f0-9]{2}))/u',
579583
[$this, 'urlEncodeChar'],
@@ -594,6 +598,26 @@ private function filterPath(string $path) : string
594598
return '/' . ltrim($path, '/');
595599
}
596600

601+
/**
602+
* Encode invalid UTF-8 characters in given string. All other characters are unchanged.
603+
*/
604+
private function filterInvalidUtf8(string $string) : string
605+
{
606+
// check if given string contains only valid UTF-8 characters
607+
if (preg_match('//u', $string)) {
608+
return $string;
609+
}
610+
611+
$letters = str_split($string);
612+
foreach ($letters as $i => $letter) {
613+
if (! preg_match('//u', $letter)) {
614+
$letters[$i] = $this->urlEncodeChar([$letter]);
615+
}
616+
}
617+
618+
return implode('', $letters);
619+
}
620+
597621
/**
598622
* Filter a query string to ensure it is propertly encoded.
599623
*
@@ -654,6 +678,8 @@ private function filterFragment(string $fragment) : string
654678
*/
655679
private function filterQueryOrFragment(string $value) : string
656680
{
681+
$value = $this->filterInvalidUtf8($value);
682+
657683
return preg_replace_callback(
658684
'/(?:[^' . self::CHAR_UNRESERVED . self::CHAR_SUB_DELIMS . '%:@\/\?]+|%(?![A-Fa-f0-9]{2}))/u',
659685
[$this, 'urlEncodeChar'],

src/functions/create_uploaded_file.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ function createUploadedFile(array $spec) : UploadedFile
3333
$spec['tmp_name'],
3434
$spec['size'],
3535
$spec['error'],
36-
isset($spec['name']) ? $spec['name'] : null,
37-
isset($spec['type']) ? $spec['type'] : null
36+
$spec['name'] ?? null,
37+
$spec['type'] ?? null
3838
);
3939
}

src/functions/marshal_headers_from_sapi.php

+10-5
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
namespace Zend\Diactoros;
1111

1212
use function array_key_exists;
13+
use function is_string;
1314
use function strpos;
1415
use function strtolower;
1516
use function strtr;
@@ -23,6 +24,14 @@ function marshalHeadersFromSapi(array $server) : array
2324
{
2425
$headers = [];
2526
foreach ($server as $key => $value) {
27+
if (! is_string($key)) {
28+
continue;
29+
}
30+
31+
if ($value === '') {
32+
continue;
33+
}
34+
2635
// Apache prefixes environment variables with REDIRECT_
2736
// if they are added by rewrite rules
2837
if (strpos($key, 'REDIRECT_') === 0) {
@@ -35,18 +44,14 @@ function marshalHeadersFromSapi(array $server) : array
3544
}
3645
}
3746

38-
if ($value === '') {
39-
continue;
40-
}
41-
4247
if (strpos($key, 'HTTP_') === 0) {
4348
$name = strtr(strtolower(substr($key, 5)), '_', '-');
4449
$headers[$name] = $value;
4550
continue;
4651
}
4752

4853
if (strpos($key, 'CONTENT_') === 0) {
49-
$name = 'content-' . strtolower(substr($key, 8));
54+
$name = strtr(strtolower($key), '_', '-');
5055
$headers[$name] = $value;
5156
continue;
5257
}

src/functions/marshal_method_from_sapi.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,5 @@
1414
*/
1515
function marshalMethodFromSapi(array $server) : string
1616
{
17-
return isset($server['REQUEST_METHOD']) ? $server['REQUEST_METHOD'] : 'GET';
17+
return $server['REQUEST_METHOD'] ?? 'GET';
1818
}

src/functions/marshal_uri_from_sapi.php

+5-5
Original file line numberDiff line numberDiff line change
@@ -132,19 +132,19 @@ function marshalUriFromSapi(array $server, array $headers) : Uri
132132
$marshalRequestPath = function (array $server) : string {
133133
// IIS7 with URL Rewrite: make sure we get the unencoded url
134134
// (double slash problem).
135-
$iisUrlRewritten = array_key_exists('IIS_WasUrlRewritten', $server) ? $server['IIS_WasUrlRewritten'] : null;
136-
$unencodedUrl = array_key_exists('UNENCODED_URL', $server) ? $server['UNENCODED_URL'] : '';
135+
$iisUrlRewritten = $server['IIS_WasUrlRewritten'] ?? null;
136+
$unencodedUrl = $server['UNENCODED_URL'] ?? '';
137137
if ('1' === $iisUrlRewritten && ! empty($unencodedUrl)) {
138138
return $unencodedUrl;
139139
}
140140

141-
$requestUri = array_key_exists('REQUEST_URI', $server) ? $server['REQUEST_URI'] : null;
141+
$requestUri = $server['REQUEST_URI'] ?? null;
142142

143143
if ($requestUri !== null) {
144144
return preg_replace('#^[^/:]+://[^/]+#', '', $requestUri);
145145
}
146146

147-
$origPathInfo = array_key_exists('ORIG_PATH_INFO', $server) ? $server['ORIG_PATH_INFO'] : null;
147+
$origPathInfo = $server['ORIG_PATH_INFO'] ?? null;
148148
if (empty($origPathInfo)) {
149149
return '/';
150150
}
@@ -168,7 +168,7 @@ function marshalUriFromSapi(array $server, array $headers) : Uri
168168
));
169169
}
170170

171-
return 'off' !== strtolower($https);
171+
return 'on' === strtolower($https);
172172
};
173173
if (array_key_exists('HTTPS', $server)) {
174174
$https = $marshalHttpsValue($server['HTTPS']);

0 commit comments

Comments
 (0)