diff --git a/.travis.yml b/.travis.yml
index d6e27d3f..347e0d1d 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -9,7 +9,6 @@ cache:
env:
global:
- COMPOSER_ARGS="--no-interaction"
- - COVERAGE_DEPS="php-coveralls/php-coveralls"
- LEGACY_DEPS="phpunit/phpunit"
matrix:
@@ -31,6 +30,7 @@ matrix:
- DEPS=locked
- CHECK_CS=true
- TEST_COVERAGE=true
+ - INTEGRATION_DEPS="php-coveralls/php-coveralls"
- php: 7
env:
- DEPS=latest
@@ -52,6 +52,10 @@ matrix:
- php: 7.2
env:
- DEPS=latest
+ - php: 7.2
+ name: Integration tests
+ env:
+ - INTEGRATION_DEPS="http-interop/http-factory-diactoros"
before_install:
- if [[ $TEST_COVERAGE != 'true' && "$(php --version | grep xdebug -ci)" -ge 1 ]]; then phpenv config-rm xdebug.ini || return 0 ; fi
@@ -62,7 +66,7 @@ install:
- if [[ $TRAVIS_PHP_VERSION =~ ^5.6 ]]; then travis_retry composer update $COMPOSER_ARGS --with-dependencies $LEGACY_DEPS ; fi
- if [[ $DEPS == 'latest' ]]; then travis_retry composer update $COMPOSER_ARGS ; fi
- if [[ $DEPS == 'lowest' ]]; then travis_retry composer update --prefer-lowest --prefer-stable $COMPOSER_ARGS ; fi
- - if [[ $TEST_COVERAGE == 'true' ]]; then travis_retry composer require --dev $COMPOSER_ARGS $COVERAGE_DEPS ; fi
+ - if [[ $INTEGRATION_DEPS != '' ]]; then travis_retry composer require --dev $COMPOSER_ARGS $INTEGRATION_DEPS ; fi
- stty cols 120 && composer show
script:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 628f857b..4ea9683b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,7 +2,7 @@
All notable changes to this project will be documented in this file, in reverse chronological order by release.
-## 1.8.5 - TBD
+## 1.8.6 - 2018-09-05
### Added
@@ -10,7 +10,13 @@ All notable changes to this project will be documented in this file, in reverse
### Changed
-- Nothing.
+- [#325](https://github.com/zendframework/zend-diactoros/pull/325) changes the behavior of `ServerRequest::withParsedBody()`. Per
+- PSR-7, it now no longer allows values other than `null`, arrays, or objects.
+
+- [#325](https://github.com/zendframework/zend-diactoros/pull/325) changes the behavior of each of `Request`, `ServerRequest`, and
+ `Response` in relation to the validation of header values. Previously, we
+ allowed empty arrays to be provided via `withHeader()`; however, this was
+ contrary to the PSR-7 specification. Empty arrays are no longer allowed.
### Deprecated
@@ -22,8 +28,36 @@ All notable changes to this project will be documented in this file, in reverse
### Fixed
+- [#325](https://github.com/zendframework/zend-diactoros/pull/325) ensures that `Uri::withUserInfo()` no longer ignores values of
+ `0` (numeric zero).
+
+- [#325](https://github.com/zendframework/zend-diactoros/pull/325) fixes how header values are merged when calling
+ `withAddedHeader()`, ensuring that array keys are ignored.
+
+## 1.8.5 - 2018-08-10
+
+### Added
+
+- Nothing.
+
+### Changed
+
- Nothing.
+### Deprecated
+
+- Nothing.
+
+### Removed
+
+- Nothing.
+
+### Fixed
+
+- [#324](https://github.com/zendframework/zend-diactoros/pull/324) fixes a reference
+ to an undefined variable in the `ServerRequestFactory`, which made it
+ impossible to fetch a specific header by name.
+
## 1.8.4 - 2018-08-01
### Added
diff --git a/composer.json b/composer.json
index fd36a529..ddb91d96 100644
--- a/composer.json
+++ b/composer.json
@@ -30,6 +30,7 @@
"require-dev": {
"ext-dom": "*",
"ext-libxml": "*",
+ "php-http/psr7-integration-tests": "dev-master",
"phpunit/phpunit": "^5.7.16 || ^6.0.8 || ^7.2.7",
"zendframework/zend-coding-standard": "~1.0"
},
diff --git a/composer.lock b/composer.lock
index e1a6ce1f..261ae10c 100644
--- a/composer.lock
+++ b/composer.lock
@@ -1,11 +1,10 @@
{
"_readme": [
"This file locks the dependencies of your project to a known state",
- "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
+ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "hash": "05aee370693f6857d599da36d8a0d865",
- "content-hash": "2f426f134b2d07e6f2dc4a83e7feb0a1",
+ "content-hash": "7ca0087aabf01eb8dbf67e0ae741f2f2",
"packages": [
{
"name": "psr/http-message",
@@ -55,7 +54,7 @@
"request",
"response"
],
- "time": "2016-08-06 14:39:51"
+ "time": "2016-08-06T14:39:51+00:00"
}
],
"packages-dev": [
@@ -111,7 +110,7 @@
"constructor",
"instantiate"
],
- "time": "2015-06-14 21:17:01"
+ "time": "2015-06-14T21:17:01+00:00"
},
{
"name": "myclabs/deep-copy",
@@ -156,7 +155,7 @@
"object",
"object graph"
],
- "time": "2017-10-19 19:58:43"
+ "time": "2017-10-19T19:58:43+00:00"
},
{
"name": "phar-io/manifest",
@@ -211,7 +210,7 @@
}
],
"description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)",
- "time": "2017-03-05 18:14:27"
+ "time": "2017-03-05T18:14:27+00:00"
},
{
"name": "phar-io/version",
@@ -258,7 +257,62 @@
}
],
"description": "Library for handling version information and constraints",
- "time": "2017-03-05 17:38:23"
+ "time": "2017-03-05T17:38:23+00:00"
+ },
+ {
+ "name": "php-http/psr7-integration-tests",
+ "version": "dev-master",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-http/psr7-integration-tests.git",
+ "reference": "5dfefb2da33ca24ae20c971b725c9a6fe7403008"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-http/psr7-integration-tests/zipball/5dfefb2da33ca24ae20c971b725c9a6fe7403008",
+ "reference": "5dfefb2da33ca24ae20c971b725c9a6fe7403008",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^5.4 || ^7.0",
+ "phpunit/phpunit": "^5.4 || ^6.0 || ^7.0",
+ "psr/http-message": "^1.0"
+ },
+ "require-dev": {
+ "guzzlehttp/psr7": "^1.4",
+ "nyholm/psr7": "dev-master",
+ "ringcentral/psr7": "^1.2",
+ "slim/http": "^0.3",
+ "zendframework/zend-diactoros": "^1.8"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Http\\Psr7Test\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Tobias Nyholm",
+ "email": "tobias.nyholm@gmail.com"
+ }
+ ],
+ "description": "Test suite for PSR7",
+ "homepage": "http://php-http.org",
+ "keywords": [
+ "psr-7",
+ "test"
+ ],
+ "time": "2018-09-02T10:01:55+00:00"
},
{
"name": "phpdocumentor/reflection-common",
@@ -312,7 +366,7 @@
"reflection",
"static analysis"
],
- "time": "2017-09-11 18:02:19"
+ "time": "2017-09-11T18:02:19+00:00"
},
{
"name": "phpdocumentor/reflection-docblock",
@@ -363,7 +417,7 @@
}
],
"description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
- "time": "2017-11-30 07:14:17"
+ "time": "2017-11-30T07:14:17+00:00"
},
{
"name": "phpdocumentor/type-resolver",
@@ -410,7 +464,7 @@
"email": "me@mikevanriel.com"
}
],
- "time": "2017-07-14 14:27:02"
+ "time": "2017-07-14T14:27:02+00:00"
},
{
"name": "phpspec/prophecy",
@@ -473,7 +527,7 @@
"spy",
"stub"
],
- "time": "2018-04-18 13:57:24"
+ "time": "2018-04-18T13:57:24+00:00"
},
{
"name": "phpunit/php-code-coverage",
@@ -536,7 +590,7 @@
"testing",
"xunit"
],
- "time": "2018-04-06 15:36:58"
+ "time": "2018-04-06T15:36:58+00:00"
},
{
"name": "phpunit/php-file-iterator",
@@ -583,7 +637,7 @@
"filesystem",
"iterator"
],
- "time": "2017-11-27 13:52:08"
+ "time": "2017-11-27T13:52:08+00:00"
},
{
"name": "phpunit/php-text-template",
@@ -624,7 +678,7 @@
"keywords": [
"template"
],
- "time": "2015-06-21 13:50:34"
+ "time": "2015-06-21T13:50:34+00:00"
},
{
"name": "phpunit/php-timer",
@@ -673,7 +727,7 @@
"keywords": [
"timer"
],
- "time": "2017-02-26 11:10:40"
+ "time": "2017-02-26T11:10:40+00:00"
},
{
"name": "phpunit/php-token-stream",
@@ -722,7 +776,7 @@
"keywords": [
"tokenizer"
],
- "time": "2017-11-27 05:48:46"
+ "time": "2017-11-27T05:48:46+00:00"
},
{
"name": "phpunit/phpunit",
@@ -806,7 +860,7 @@
"testing",
"xunit"
],
- "time": "2018-07-03 06:40:40"
+ "time": "2018-07-03T06:40:40+00:00"
},
{
"name": "phpunit/phpunit-mock-objects",
@@ -865,7 +919,7 @@
"mock",
"xunit"
],
- "time": "2018-07-13 03:27:23"
+ "time": "2018-07-13T03:27:23+00:00"
},
{
"name": "sebastian/code-unit-reverse-lookup",
@@ -910,7 +964,7 @@
],
"description": "Looks up which function or method a line of code belongs to",
"homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/",
- "time": "2017-03-04 06:30:41"
+ "time": "2017-03-04T06:30:41+00:00"
},
{
"name": "sebastian/comparator",
@@ -974,7 +1028,7 @@
"compare",
"equality"
],
- "time": "2018-02-01 13:46:46"
+ "time": "2018-02-01T13:46:46+00:00"
},
{
"name": "sebastian/diff",
@@ -1026,7 +1080,7 @@
"keywords": [
"diff"
],
- "time": "2017-08-03 08:09:46"
+ "time": "2017-08-03T08:09:46+00:00"
},
{
"name": "sebastian/environment",
@@ -1076,7 +1130,7 @@
"environment",
"hhvm"
],
- "time": "2017-07-01 08:51:00"
+ "time": "2017-07-01T08:51:00+00:00"
},
{
"name": "sebastian/exporter",
@@ -1143,7 +1197,7 @@
"export",
"exporter"
],
- "time": "2017-04-03 13:19:02"
+ "time": "2017-04-03T13:19:02+00:00"
},
{
"name": "sebastian/global-state",
@@ -1194,7 +1248,7 @@
"keywords": [
"global state"
],
- "time": "2017-04-27 15:39:26"
+ "time": "2017-04-27T15:39:26+00:00"
},
{
"name": "sebastian/object-enumerator",
@@ -1241,7 +1295,7 @@
],
"description": "Traverses array structures and object graphs to enumerate all referenced objects",
"homepage": "https://github.com/sebastianbergmann/object-enumerator/",
- "time": "2017-08-03 12:35:26"
+ "time": "2017-08-03T12:35:26+00:00"
},
{
"name": "sebastian/object-reflector",
@@ -1286,7 +1340,7 @@
],
"description": "Allows reflection of object attributes, including inherited and non-public ones",
"homepage": "https://github.com/sebastianbergmann/object-reflector/",
- "time": "2017-03-29 09:07:27"
+ "time": "2017-03-29T09:07:27+00:00"
},
{
"name": "sebastian/recursion-context",
@@ -1339,7 +1393,7 @@
],
"description": "Provides functionality to recursively process PHP variables",
"homepage": "http://www.github.com/sebastianbergmann/recursion-context",
- "time": "2017-03-03 06:23:57"
+ "time": "2017-03-03T06:23:57+00:00"
},
{
"name": "sebastian/resource-operations",
@@ -1381,7 +1435,7 @@
],
"description": "Provides a list of PHP built-in functions that operate on resources",
"homepage": "https://www.github.com/sebastianbergmann/resource-operations",
- "time": "2015-07-28 20:34:47"
+ "time": "2015-07-28T20:34:47+00:00"
},
{
"name": "sebastian/version",
@@ -1424,7 +1478,7 @@
],
"description": "Library that helps with managing the version number of Git-hosted PHP projects",
"homepage": "https://github.com/sebastianbergmann/version",
- "time": "2016-10-03 07:35:21"
+ "time": "2016-10-03T07:35:21+00:00"
},
{
"name": "squizlabs/php_codesniffer",
@@ -1502,7 +1556,7 @@
"phpcs",
"standards"
],
- "time": "2017-05-22 02:43:20"
+ "time": "2017-05-22T02:43:20+00:00"
},
{
"name": "theseer/tokenizer",
@@ -1542,7 +1596,7 @@
}
],
"description": "A small library for converting tokenized PHP source code into XML and potentially other formats",
- "time": "2017-04-07 12:08:54"
+ "time": "2017-04-07T12:08:54+00:00"
},
{
"name": "webmozart/assert",
@@ -1592,7 +1646,7 @@
"check",
"validate"
],
- "time": "2018-01-29 19:49:41"
+ "time": "2018-01-29T19:49:41+00:00"
},
{
"name": "zendframework/zend-coding-standard",
@@ -1621,12 +1675,14 @@
"Coding Standard",
"zf"
],
- "time": "2016-11-09 21:30:43"
+ "time": "2016-11-09T21:30:43+00:00"
}
],
"aliases": [],
"minimum-stability": "stable",
- "stability-flags": [],
+ "stability-flags": {
+ "php-http/psr7-integration-tests": 20
+ },
"prefer-stable": false,
"prefer-lowest": false,
"platform": {
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
index 6de09f62..aa69fe9b 100644
--- a/phpunit.xml.dist
+++ b/phpunit.xml.dist
@@ -10,4 +10,13 @@
src
+
+
+
+
+
+
+
+
+
diff --git a/src/MessageTrait.php b/src/MessageTrait.php
index d249d86a..6b83be46 100644
--- a/src/MessageTrait.php
+++ b/src/MessageTrait.php
@@ -385,11 +385,18 @@ private function filterHeaderValue($values)
$values = [$values];
}
+ if ([] === $values) {
+ throw new InvalidArgumentException(
+ 'Invalid header value: must be a string or array of strings; '
+ . 'cannot be an empty array'
+ );
+ }
+
return array_map(function ($value) {
HeaderSecurity::assertValid($value);
return (string) $value;
- }, $values);
+ }, array_values($values));
}
/**
diff --git a/src/ServerRequest.php b/src/ServerRequest.php
index bf98cd32..8523d59e 100644
--- a/src/ServerRequest.php
+++ b/src/ServerRequest.php
@@ -180,6 +180,14 @@ public function getParsedBody()
*/
public function withParsedBody($data)
{
+ if (! is_array($data) && ! is_object($data) && null !== $data) {
+ throw new InvalidArgumentException(sprintf(
+ '%s expects a null, array, or object argument; received %s',
+ __METHOD__,
+ gettype($data)
+ ));
+ }
+
$new = clone $this;
$new->parsedBody = $data;
return $new;
diff --git a/src/ServerRequestFactory.php b/src/ServerRequestFactory.php
index ebcd51f4..b56a0dee 100644
--- a/src/ServerRequestFactory.php
+++ b/src/ServerRequestFactory.php
@@ -124,7 +124,7 @@ public static function get($key, array $values, $default = null)
*/
public static function getHeader($header, array $headers, $default = null)
{
- $header = strtolower($name);
+ $header = strtolower($header);
$headers = array_change_key_case($headers, CASE_LOWER);
if (array_key_exists($header, $headers)) {
$value = is_array($headers[$header]) ? implode(', ', $headers[$header]) : $headers[$header];
diff --git a/src/Uri.php b/src/Uri.php
index 1181468f..5dcfb0e2 100644
--- a/src/Uri.php
+++ b/src/Uri.php
@@ -291,7 +291,7 @@ public function withUserInfo($user, $password = null)
}
$info = $this->filterUserInfoPart($user);
- if ($password) {
+ if (null !== $password) {
$info .= ':' . $this->filterUserInfoPart($password);
}
diff --git a/test/Integration/RequestTest.php b/test/Integration/RequestTest.php
new file mode 100644
index 00000000..8b82e198
--- /dev/null
+++ b/test/Integration/RequestTest.php
@@ -0,0 +1,28 @@
+write('foobar');
+
+ return new UploadedFile($stream, $stream->getSize(), UPLOAD_ERR_OK);
+ }
+}
diff --git a/test/Integration/UriTest.php b/test/Integration/UriTest.php
new file mode 100644
index 00000000..f70392c3
--- /dev/null
+++ b/test/Integration/UriTest.php
@@ -0,0 +1,28 @@
+assertSame('Foo,Bar', $message2->getHeaderLine('X-Foo'));
}
- public function testHeaderExistsIfWithNoValues()
- {
- $message = $this->message->withHeader('X-Foo', []);
-
- $this->assertTrue($message->hasHeader('X-Foo'));
- }
-
- public function testHeaderWithNoValues()
- {
- $message = $this->message->withHeader('X-Foo', []);
-
- $this->assertSame([], $message->getHeader('X-Foo'));
- $this->assertSame('', $message->getHeaderLine('X-Foo'));
- }
-
-
public function testCanRemoveHeaders()
{
$message = $this->message->withHeader('X-Foo', 'Foo');
diff --git a/test/ServerRequestFactoryTest.php b/test/ServerRequestFactoryTest.php
index 6146cc93..003b8aec 100644
--- a/test/ServerRequestFactoryTest.php
+++ b/test/ServerRequestFactoryTest.php
@@ -607,4 +607,13 @@ public function testMarshalRequestUriPrefersRequestUriServerParamWhenXOriginalUr
$uri = marshalUriFromSapi($server, $headers);
$this->assertSame('/requested/path', $uri->getPath());
}
+
+ public function testGetHeader()
+ {
+ $headers = [
+ 'Host' => 'example.com'
+ ];
+
+ $this->assertSame('example.com', ServerRequestFactory::getHeader('Host', $headers));
+ }
}