Codebase list php-dflydev-fig-cookies / 80cbefe
php-dflydev-fig-cookies_1.0.2.orig.tar.gz mirabilos authored 5 years ago mirabilos committed 5 years ago
25 changed file(s) with 3918 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
0 /vendor/
0 tools:
1 external_code_coverage:
2 timeout: 600
3 php_mess_detector: true
4 php_code_sniffer: true
5 sensiolabs_security_checker: true
6 php_code_coverage: true
7 php_pdepend: true
8 php_loc:
9 enabled: true
10 excluded_dirs: [vendor, tests]
11 php_cpd:
12 enabled: true
13 excluded_dirs: [vendor, tests]
14 filter:
15 excluded_paths:
16 - tests/*
0 language: php
1
2 php:
3 - 5.4
4 - 5.5
5 - 5.6
6 - 7
7 - hhvm
8
9 cache:
10 directories:
11 - vendor
12 - $HOME/.composer/cache
13
14 matrix:
15 allow_failures:
16 - php: hhvm
17
18 before_script:
19 - composer self-update
20 - composer install --dev --prefer-source
21
22 script:
23 - ./vendor/bin/phpunit --coverage-clover=coverage.clover
24 - ./vendor/bin/phpcs --standard=PSR2 src
25
26 after_script:
27 - wget https://scrutinizer-ci.com/ocular.phar
28 - php ocular.phar code-coverage:upload --format=php-clover coverage.clover
29 - CODECLIMATE_REPO_TOKEN=269a392c7a845b5ca031f9412f44435c0ec9ceebd0e19f97ff1762e6f880ba79 ./vendor/bin/test-reporter --coverage-report=coverage.clover
30
31 notifications:
32 email: true
0 Copyright (c) 2015 Dragonfly Development Inc.
1
2 Permission is hereby granted, free of charge, to any person obtaining a copy
3 of this software and associated documentation files (the "Software"), to deal
4 in the Software without restriction, including without limitation the rights
5 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
6 copies of the Software, and to permit persons to whom the Software is furnished
7 to do so, subject to the following conditions:
8
9 The above copyright notice and this permission notice shall be included in all
10 copies or substantial portions of the Software.
11
12 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
13 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
14 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
15 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
16 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
17 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
18 THE SOFTWARE.
0 FIG Cookies
1 ===========
2
3 Managing Cookies for PSR-7 Requests and Responses.
4
5 [![Latest Stable Version](https://poser.pugx.org/dflydev/fig-cookies/v/stable)](https://packagist.org/packages/dflydev/fig-cookies)
6 [![Total Downloads](https://poser.pugx.org/dflydev/fig-cookies/downloads)](https://packagist.org/packages/dflydev/fig-cookies)
7 [![Latest Unstable Version](https://poser.pugx.org/dflydev/fig-cookies/v/unstable)](https://packagist.org/packages/dflydev/fig-cookies)
8 [![License](https://poser.pugx.org/dflydev/fig-cookies/license)](https://packagist.org/packages/dflydev/fig-cookies)
9 <br>
10 [![Build Status](https://travis-ci.org/dflydev/dflydev-fig-cookies.svg?branch=master)](https://travis-ci.org/dflydev/dflydev-fig-cookies)
11 [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/dflydev/dflydev-fig-cookies/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/dflydev/dflydev-fig-cookies/?branch=master)
12 [![Code Coverage](https://scrutinizer-ci.com/g/dflydev/dflydev-fig-cookies/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/dflydev/dflydev-fig-cookies/?branch=master)
13 [![Code Climate](https://codeclimate.com/github/dflydev/dflydev-fig-cookies/badges/gpa.svg)](https://codeclimate.com/github/dflydev/dflydev-fig-cookies)
14 <br>
15 [![Join the chat at https://gitter.im/dflydev/dflydev-fig-cookies](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/dflydev/dflydev-fig-cookies?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
16
17
18 Requirements
19 ------------
20
21 * PHP 5.4+
22 * [psr/http-message](https://packagist.org/packages/psr/http-message)
23
24
25 Installation
26 ------------
27
28 ```bash
29 $> composer require dflydev/fig-cookies
30 ```
31
32
33 Concepts
34 --------
35
36 FIG Cookies tackles two problems, managing **Cookie** *Request* headers and
37 managing **Set-Cookie** *Response* headers. It does this by way of introducing
38 a `Cookies` class to manage collections of `Cookie` instances and a
39 `SetCookies` class to manage collections of `SetCookie` instances.
40
41 Instantiating these collections looks like this:
42
43 ```php
44 // Get a collection representing the cookies in the Cookie headers
45 // of a PSR-7 Request.
46 $cookies = Dflydev\FigCookies\Cookies::fromRequest($request);
47
48 // Get a collection representing the cookies in the Set-Cookie headers
49 // of a PSR-7 Response
50 $setCookies = Dflydev\FigCookies\SetCookies::fromResponse($response);
51 ```
52
53 After modifying these collections in some way, they are rendered into a
54 PSR-7 Request or PSR-7 Response like this:
55
56 ```php
57 // Render the Cookie headers and add them to the headers of a
58 // PSR-7 Request.
59 $request = $cookies->renderIntoCookieHeader($request);
60
61 // Render the Set-Cookie headers and add them to the headers of a
62 // PSR-7 Response.
63 $response = $setCookies->renderIntoSetCookieHeader($response);
64 ```
65
66 Like PSR-7 Messages, `Cookie`, `Cookies`, `SetCookie`, and `SetCookies`
67 are all represented as immutable value objects and all mutators will
68 return new instances of the original with the requested changes.
69
70 While this style of design has many benefits it can become fairly
71 verbose very quickly. In order to get around that, FIG Cookies provides
72 two facades in an attempt to help simply things and make the whole process
73 less verbose.
74
75
76 Basic Usage
77 -----------
78
79 The easiest way to start working with FIG Cookies is by using the
80 `FigRequestCookies` and `FigResponseCookies` classes. They are facades to the
81 primitive FIG Cookies classes. Their jobs are to make common cookie related
82 tasks easier and less verbose than working with the primitive classes directly.
83
84 There is overhead on creating `Cookies` and `SetCookies` and rebuilding
85 requests and responses. Each of the `FigCookies` methods will go through this
86 process so be wary of using too many of these calls in the same section of
87 code. In some cases it may be better to work with the primitive FIG Cookies
88 classes directly rather than using the facades.
89
90
91 ### Request Cookies
92
93 Requests include cookie information in the **Cookie** request header. The
94 cookies in this header are represented by the `Cookie` class.
95
96 ```php
97 use Dflydev\FigCookies\Cookie;
98
99 $cookie = Cookie::create('theme', 'blue');
100 ```
101
102 To easily work with request cookies, use the `FigRequestCookies` facade.
103
104 #### Get a Request Cookie
105
106 The `get` method will return a `Cookie` instance. If no cookie by the specified
107 name exists, the returned `Cookie` instance will have a `null` value.
108
109 The optional third parameter to `get` sets the value that should be used if a
110 cookie does not exist.
111
112 ```php
113 use Dflydev\FigCookies\FigRequestCookies;
114
115 $cookie = FigRequestCookies::get($request, 'theme');
116 $cookie = FigRequestCookies::get($request, 'theme', 'default-theme');
117 ```
118
119 #### Set a Request Cookie
120
121 The `set` method will either add a cookie or replace an existing cookie.
122
123 The `Cookie` primitive is used as the second argument.
124
125 ```php
126 use Dflydev\FigCookies\FigRequestCookies;
127
128 $request = FigRequestCookies::set($request, Cookie::create('theme', 'blue'));
129 ```
130
131 #### Modify a Request Cookie
132
133 The `modify` method allows for replacing the contents of a cookie based on the
134 current cookie with the specified name. The third argument is a `callable` that
135 takes a `Cookie` instance as its first argument and is expected to return a
136 `Cookie` instance.
137
138 If no cookie by the specified name exists, a new `Cookie` instance with a
139 `null` value will be passed to the callable.
140
141 ```php
142 use Dflydev\FigCookies\FigRequestCookies;
143
144 $modify = function (Cookie $cookie) {
145 $value = $cookie->getValue();
146
147 // ... inspect current $value and determine if $value should
148 // change or if it can stay the same. in all cases, a cookie
149 // should be returned from this callback...
150
151 return $cookie->withValue($value);
152 }
153
154 $request = FigRequestCookies::modify($request, 'theme', $modify);
155 ```
156
157 #### Remove a Request Cookie
158
159 The `remove` method removes a cookie if it exists.
160
161 ```php
162 use Dflydev\FigCookies\FigRequestCookies;
163
164 $request = FigRequestCookies::remove($request, 'theme');
165 ```
166
167 ### Response Cookies
168
169 Responses include cookie information in the **Set-Cookie** response header. The
170 cookies in these headers are represented by the `SetCookie` class.
171
172 ```php
173 use Dflydev\FigCookies\SetCookie;
174
175 $setCookie = SetCookie::create('lu')
176 ->withValue('Rg3vHJZnehYLjVg7qi3bZjzg')
177 ->withExpires('Tue, 15-Jan-2013 21:47:38 GMT')
178 ->withMaxAge(500)
179 ->withPath('/')
180 ->withDomain('.example.com')
181 ->withSecure(true)
182 ->withHttpOnly(true)
183 ;
184 ```
185
186 To easily work with response cookies, use the `FigResponseCookies` facade.
187
188 #### Get a Response Cookie
189
190 The `get` method will return a `SetCookie` instance. If no cookie by the
191 specified name exists, the returned `SetCookie` instance will have a `null`
192 value.
193
194 The optional third parameter to `get` sets the value that should be used if a
195 cookie does not exist.
196
197 ```php
198 use Dflydev\FigCookies\FigResponseCookies;
199
200 $setCookie = FigResponseCookies::get($response, 'theme');
201 $setCookie = FigResponseCookies::get($response, 'theme', 'simple');
202 ```
203
204 #### Set a Response Cookie
205
206 The `set` method will either add a cookie or replace an existing cookie.
207
208 The `SetCookie` primitive is used as the second argument.
209
210 ```php
211 use Dflydev\FigCookies\FigResponseCookies;
212
213 $response = FigResponseCookies::set($response, SetCookie::create('token')
214 ->withValue('a9s87dfz978a9')
215 ->withDomain('example.com')
216 ->withPath('/firewall')
217 );
218 ```
219
220 #### Modify a Response Cookie
221
222 The `modify` method allows for replacing the contents of a cookie based on the
223 current cookie with the specified name. The third argument is a `callable` that
224 takes a `SetCookie` instance as its first argument and is expected to return a
225 `SetCookie` instance.
226
227 If no cookie by the specified name exists, a new `SetCookie` instance with a
228 `null` value will be passed to the callable.
229
230 ```php
231 use Dflydev\FigCookies\FigResponseCookies;
232
233 $modify = function (SetCookie $setCookie) {
234 $value = $setCookie->getValue();
235
236 // ... inspect current $value and determine if $value should
237 // change or if it can stay the same. in all cases, a cookie
238 // should be returned from this callback...
239
240 return $setCookie
241 ->withValue($newValue)
242 ->withExpires($newExpires)
243 ;
244 }
245
246 $response = FigResponseCookies::modify($response, 'theme', $modify);
247 ```
248
249 #### Remove a Response Cookie
250
251 The `remove` method removes a cookie from the response if it exists.
252
253 ```php
254 use Dflydev\FigCookies\FigResponseCookies;
255
256 $response = FigResponseCookies::remove($response, 'theme');
257 ```
258
259
260 FAQ
261 ---
262
263 ### Do you call `setcookies`?
264
265 No.
266
267 Delivery of the rendered `SetCookie` instances is the responsibility of the
268 PSR-7 client implementation.
269
270
271 ### Do you do anything with sessions?
272
273 No.
274
275 It would be possible to build session handling using cookies on top of FIG
276 Cookies but it is out of scope for this package.
277
278
279 ### Do you read from `$_COOKIES`?
280
281 No.
282
283 FIG Cookies only pays attention to the `Cookie` headers on PSR-7 Request
284 instances. In the case of `ServerRequestInterface` instances, PSR-7
285 implementations should be including `$_COOKIES` values in the headers
286 so in that case FIG Cookies may be interacting with `$_COOKIES`
287 indirectly.
288
289
290 License
291 -------
292
293 MIT, see LICENSE.
294
295
296 Community
297 ---------
298
299 Want to get involved? Here are a few ways:
300
301 * Find us in the #dflydev IRC channel on irc.freenode.org.
302 * Mention [@dflydev](https://twitter.com/dflydev) on Twitter.
303 * [![Join the chat at https://gitter.im/dflydev/dflydev-fig-cookies](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/dflydev/dflydev-fig-cookies?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
0 {
1 "name": "dflydev/fig-cookies",
2 "description": "Cookies for PSR-7 HTTP Message Interface.",
3 "license": "MIT",
4 "keywords": ["psr7", "psr-7", "cookies"],
5 "authors": [
6 {
7 "name": "Beau Simensen",
8 "email": "beau@dflydev.com"
9 }
10 ],
11 "require": {
12 "php": ">=5.4",
13 "psr/http-message": "~1.0"
14 },
15 "autoload": {
16 "psr-4": {
17 "Dflydev\\FigCookies\\": "src/Dflydev/FigCookies"
18 }
19 },
20 "require-dev": {
21 "codeclimate/php-test-reporter": "~0.1@dev",
22 "phpunit/phpunit": "~4.5",
23 "squizlabs/php_codesniffer": "~2.3"
24 },
25 "autoload-dev": {
26 "psr-4": {
27 "Dflydev\\FigCookies\\": "tests/Dflydev/FigCookies"
28 }
29 },
30 "extra": {
31 "branch-alias": {
32 "dev-master": "1.0.x-dev"
33 }
34 }
35 }
0 {
1 "_readme": [
2 "This file locks the dependencies of your project to a known state",
3 "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
4 "This file is @generated automatically"
5 ],
6 "hash": "a2aada3c911978a42d70869cbbf6a743",
7 "packages": [
8 {
9 "name": "psr/http-message",
10 "version": "1.0",
11 "source": {
12 "type": "git",
13 "url": "https://github.com/php-fig/http-message.git",
14 "reference": "85d63699f0dbedb190bbd4b0d2b9dc707ea4c298"
15 },
16 "dist": {
17 "type": "zip",
18 "url": "https://api.github.com/repos/php-fig/http-message/zipball/85d63699f0dbedb190bbd4b0d2b9dc707ea4c298",
19 "reference": "85d63699f0dbedb190bbd4b0d2b9dc707ea4c298",
20 "shasum": ""
21 },
22 "require": {
23 "php": ">=5.3.0"
24 },
25 "type": "library",
26 "extra": {
27 "branch-alias": {
28 "dev-master": "1.0.x-dev"
29 }
30 },
31 "autoload": {
32 "psr-4": {
33 "Psr\\Http\\Message\\": "src/"
34 }
35 },
36 "notification-url": "https://packagist.org/downloads/",
37 "license": [
38 "MIT"
39 ],
40 "authors": [
41 {
42 "name": "PHP-FIG",
43 "homepage": "http://www.php-fig.org/"
44 }
45 ],
46 "description": "Common interface for HTTP messages",
47 "keywords": [
48 "http",
49 "http-message",
50 "psr",
51 "psr-7",
52 "request",
53 "response"
54 ],
55 "time": "2015-05-04 20:22:00"
56 }
57 ],
58 "packages-dev": [
59 {
60 "name": "codeclimate/php-test-reporter",
61 "version": "dev-master",
62 "source": {
63 "type": "git",
64 "url": "https://github.com/codeclimate/php-test-reporter.git",
65 "reference": "418ae782307841ac50fe26daa4cfe04520b0de9c"
66 },
67 "dist": {
68 "type": "zip",
69 "url": "https://api.github.com/repos/codeclimate/php-test-reporter/zipball/418ae782307841ac50fe26daa4cfe04520b0de9c",
70 "reference": "418ae782307841ac50fe26daa4cfe04520b0de9c",
71 "shasum": ""
72 },
73 "require": {
74 "ext-curl": "*",
75 "php": ">=5.3",
76 "satooshi/php-coveralls": "0.6.*",
77 "symfony/console": ">=2.0"
78 },
79 "require-dev": {
80 "ext-xdebug": "*",
81 "phpunit/phpunit": "3.7.*@stable"
82 },
83 "bin": [
84 "composer/bin/test-reporter"
85 ],
86 "type": "library",
87 "extra": {
88 "branch-alias": {
89 "dev-master": "0.1.x-dev"
90 }
91 },
92 "autoload": {
93 "psr-0": {
94 "CodeClimate\\Component": "src/",
95 "CodeClimate\\Bundle": "src/"
96 }
97 },
98 "notification-url": "https://packagist.org/downloads/",
99 "license": [
100 "MIT"
101 ],
102 "authors": [
103 {
104 "name": "Code Climate",
105 "email": "hello@codeclimate.com",
106 "homepage": "https://codeclimate.com"
107 }
108 ],
109 "description": "PHP client for reporting test coverage to Code Climate",
110 "homepage": "https://github.com/codeclimate/php-test-reporter",
111 "keywords": [
112 "codeclimate",
113 "coverage"
114 ],
115 "time": "2015-04-18 14:43:54"
116 },
117 {
118 "name": "doctrine/instantiator",
119 "version": "1.0.4",
120 "source": {
121 "type": "git",
122 "url": "https://github.com/doctrine/instantiator.git",
123 "reference": "f976e5de371104877ebc89bd8fecb0019ed9c119"
124 },
125 "dist": {
126 "type": "zip",
127 "url": "https://api.github.com/repos/doctrine/instantiator/zipball/f976e5de371104877ebc89bd8fecb0019ed9c119",
128 "reference": "f976e5de371104877ebc89bd8fecb0019ed9c119",
129 "shasum": ""
130 },
131 "require": {
132 "php": ">=5.3,<8.0-DEV"
133 },
134 "require-dev": {
135 "athletic/athletic": "~0.1.8",
136 "ext-pdo": "*",
137 "ext-phar": "*",
138 "phpunit/phpunit": "~4.0",
139 "squizlabs/php_codesniffer": "2.0.*@ALPHA"
140 },
141 "type": "library",
142 "extra": {
143 "branch-alias": {
144 "dev-master": "1.0.x-dev"
145 }
146 },
147 "autoload": {
148 "psr-0": {
149 "Doctrine\\Instantiator\\": "src"
150 }
151 },
152 "notification-url": "https://packagist.org/downloads/",
153 "license": [
154 "MIT"
155 ],
156 "authors": [
157 {
158 "name": "Marco Pivetta",
159 "email": "ocramius@gmail.com",
160 "homepage": "http://ocramius.github.com/"
161 }
162 ],
163 "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors",
164 "homepage": "https://github.com/doctrine/instantiator",
165 "keywords": [
166 "constructor",
167 "instantiate"
168 ],
169 "time": "2014-10-13 12:58:55"
170 },
171 {
172 "name": "guzzle/guzzle",
173 "version": "v3.9.3",
174 "source": {
175 "type": "git",
176 "url": "https://github.com/guzzle/guzzle3.git",
177 "reference": "0645b70d953bc1c067bbc8d5bc53194706b628d9"
178 },
179 "dist": {
180 "type": "zip",
181 "url": "https://api.github.com/repos/guzzle/guzzle3/zipball/0645b70d953bc1c067bbc8d5bc53194706b628d9",
182 "reference": "0645b70d953bc1c067bbc8d5bc53194706b628d9",
183 "shasum": ""
184 },
185 "require": {
186 "ext-curl": "*",
187 "php": ">=5.3.3",
188 "symfony/event-dispatcher": "~2.1"
189 },
190 "replace": {
191 "guzzle/batch": "self.version",
192 "guzzle/cache": "self.version",
193 "guzzle/common": "self.version",
194 "guzzle/http": "self.version",
195 "guzzle/inflection": "self.version",
196 "guzzle/iterator": "self.version",
197 "guzzle/log": "self.version",
198 "guzzle/parser": "self.version",
199 "guzzle/plugin": "self.version",
200 "guzzle/plugin-async": "self.version",
201 "guzzle/plugin-backoff": "self.version",
202 "guzzle/plugin-cache": "self.version",
203 "guzzle/plugin-cookie": "self.version",
204 "guzzle/plugin-curlauth": "self.version",
205 "guzzle/plugin-error-response": "self.version",
206 "guzzle/plugin-history": "self.version",
207 "guzzle/plugin-log": "self.version",
208 "guzzle/plugin-md5": "self.version",
209 "guzzle/plugin-mock": "self.version",
210 "guzzle/plugin-oauth": "self.version",
211 "guzzle/service": "self.version",
212 "guzzle/stream": "self.version"
213 },
214 "require-dev": {
215 "doctrine/cache": "~1.3",
216 "monolog/monolog": "~1.0",
217 "phpunit/phpunit": "3.7.*",
218 "psr/log": "~1.0",
219 "symfony/class-loader": "~2.1",
220 "zendframework/zend-cache": "2.*,<2.3",
221 "zendframework/zend-log": "2.*,<2.3"
222 },
223 "suggest": {
224 "guzzlehttp/guzzle": "Guzzle 5 has moved to a new package name. The package you have installed, Guzzle 3, is deprecated."
225 },
226 "type": "library",
227 "extra": {
228 "branch-alias": {
229 "dev-master": "3.9-dev"
230 }
231 },
232 "autoload": {
233 "psr-0": {
234 "Guzzle": "src/",
235 "Guzzle\\Tests": "tests/"
236 }
237 },
238 "notification-url": "https://packagist.org/downloads/",
239 "license": [
240 "MIT"
241 ],
242 "authors": [
243 {
244 "name": "Michael Dowling",
245 "email": "mtdowling@gmail.com",
246 "homepage": "https://github.com/mtdowling"
247 },
248 {
249 "name": "Guzzle Community",
250 "homepage": "https://github.com/guzzle/guzzle/contributors"
251 }
252 ],
253 "description": "PHP HTTP client. This library is deprecated in favor of https://packagist.org/packages/guzzlehttp/guzzle",
254 "homepage": "http://guzzlephp.org/",
255 "keywords": [
256 "client",
257 "curl",
258 "framework",
259 "http",
260 "http client",
261 "rest",
262 "web service"
263 ],
264 "time": "2015-03-18 18:23:50"
265 },
266 {
267 "name": "phpdocumentor/reflection-docblock",
268 "version": "2.0.4",
269 "source": {
270 "type": "git",
271 "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
272 "reference": "d68dbdc53dc358a816f00b300704702b2eaff7b8"
273 },
274 "dist": {
275 "type": "zip",
276 "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/d68dbdc53dc358a816f00b300704702b2eaff7b8",
277 "reference": "d68dbdc53dc358a816f00b300704702b2eaff7b8",
278 "shasum": ""
279 },
280 "require": {
281 "php": ">=5.3.3"
282 },
283 "require-dev": {
284 "phpunit/phpunit": "~4.0"
285 },
286 "suggest": {
287 "dflydev/markdown": "~1.0",
288 "erusev/parsedown": "~1.0"
289 },
290 "type": "library",
291 "extra": {
292 "branch-alias": {
293 "dev-master": "2.0.x-dev"
294 }
295 },
296 "autoload": {
297 "psr-0": {
298 "phpDocumentor": [
299 "src/"
300 ]
301 }
302 },
303 "notification-url": "https://packagist.org/downloads/",
304 "license": [
305 "MIT"
306 ],
307 "authors": [
308 {
309 "name": "Mike van Riel",
310 "email": "mike.vanriel@naenius.com"
311 }
312 ],
313 "time": "2015-02-03 12:10:50"
314 },
315 {
316 "name": "phpspec/prophecy",
317 "version": "v1.4.1",
318 "source": {
319 "type": "git",
320 "url": "https://github.com/phpspec/prophecy.git",
321 "reference": "3132b1f44c7bf2ec4c7eb2d3cb78fdeca760d373"
322 },
323 "dist": {
324 "type": "zip",
325 "url": "https://api.github.com/repos/phpspec/prophecy/zipball/3132b1f44c7bf2ec4c7eb2d3cb78fdeca760d373",
326 "reference": "3132b1f44c7bf2ec4c7eb2d3cb78fdeca760d373",
327 "shasum": ""
328 },
329 "require": {
330 "doctrine/instantiator": "^1.0.2",
331 "phpdocumentor/reflection-docblock": "~2.0",
332 "sebastian/comparator": "~1.1"
333 },
334 "require-dev": {
335 "phpspec/phpspec": "~2.0"
336 },
337 "type": "library",
338 "extra": {
339 "branch-alias": {
340 "dev-master": "1.4.x-dev"
341 }
342 },
343 "autoload": {
344 "psr-0": {
345 "Prophecy\\": "src/"
346 }
347 },
348 "notification-url": "https://packagist.org/downloads/",
349 "license": [
350 "MIT"
351 ],
352 "authors": [
353 {
354 "name": "Konstantin Kudryashov",
355 "email": "ever.zet@gmail.com",
356 "homepage": "http://everzet.com"
357 },
358 {
359 "name": "Marcello Duarte",
360 "email": "marcello.duarte@gmail.com"
361 }
362 ],
363 "description": "Highly opinionated mocking framework for PHP 5.3+",
364 "homepage": "https://github.com/phpspec/prophecy",
365 "keywords": [
366 "Double",
367 "Dummy",
368 "fake",
369 "mock",
370 "spy",
371 "stub"
372 ],
373 "time": "2015-04-27 22:15:08"
374 },
375 {
376 "name": "phpunit/php-code-coverage",
377 "version": "2.1.1",
378 "source": {
379 "type": "git",
380 "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
381 "reference": "60991776b3994cd8297b861e8ddc7f9c9500dedc"
382 },
383 "dist": {
384 "type": "zip",
385 "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/60991776b3994cd8297b861e8ddc7f9c9500dedc",
386 "reference": "60991776b3994cd8297b861e8ddc7f9c9500dedc",
387 "shasum": ""
388 },
389 "require": {
390 "php": ">=5.3.3",
391 "phpunit/php-file-iterator": "~1.3",
392 "phpunit/php-text-template": "~1.2",
393 "phpunit/php-token-stream": "~1.3",
394 "sebastian/environment": "~1.0",
395 "sebastian/version": "~1.0"
396 },
397 "require-dev": {
398 "ext-xdebug": ">=2.1.4",
399 "phpunit/phpunit": "~4"
400 },
401 "suggest": {
402 "ext-dom": "*",
403 "ext-xdebug": ">=2.2.1",
404 "ext-xmlwriter": "*"
405 },
406 "type": "library",
407 "extra": {
408 "branch-alias": {
409 "dev-master": "2.1.x-dev"
410 }
411 },
412 "autoload": {
413 "classmap": [
414 "src/"
415 ]
416 },
417 "notification-url": "https://packagist.org/downloads/",
418 "license": [
419 "BSD-3-Clause"
420 ],
421 "authors": [
422 {
423 "name": "Sebastian Bergmann",
424 "email": "sb@sebastian-bergmann.de",
425 "role": "lead"
426 }
427 ],
428 "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.",
429 "homepage": "https://github.com/sebastianbergmann/php-code-coverage",
430 "keywords": [
431 "coverage",
432 "testing",
433 "xunit"
434 ],
435 "time": "2015-05-31 03:14:06"
436 },
437 {
438 "name": "phpunit/php-file-iterator",
439 "version": "1.4.0",
440 "source": {
441 "type": "git",
442 "url": "https://github.com/sebastianbergmann/php-file-iterator.git",
443 "reference": "a923bb15680d0089e2316f7a4af8f437046e96bb"
444 },
445 "dist": {
446 "type": "zip",
447 "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/a923bb15680d0089e2316f7a4af8f437046e96bb",
448 "reference": "a923bb15680d0089e2316f7a4af8f437046e96bb",
449 "shasum": ""
450 },
451 "require": {
452 "php": ">=5.3.3"
453 },
454 "type": "library",
455 "extra": {
456 "branch-alias": {
457 "dev-master": "1.4.x-dev"
458 }
459 },
460 "autoload": {
461 "classmap": [
462 "src/"
463 ]
464 },
465 "notification-url": "https://packagist.org/downloads/",
466 "license": [
467 "BSD-3-Clause"
468 ],
469 "authors": [
470 {
471 "name": "Sebastian Bergmann",
472 "email": "sb@sebastian-bergmann.de",
473 "role": "lead"
474 }
475 ],
476 "description": "FilterIterator implementation that filters files based on a list of suffixes.",
477 "homepage": "https://github.com/sebastianbergmann/php-file-iterator/",
478 "keywords": [
479 "filesystem",
480 "iterator"
481 ],
482 "time": "2015-04-02 05:19:05"
483 },
484 {
485 "name": "phpunit/php-text-template",
486 "version": "1.2.0",
487 "source": {
488 "type": "git",
489 "url": "https://github.com/sebastianbergmann/php-text-template.git",
490 "reference": "206dfefc0ffe9cebf65c413e3d0e809c82fbf00a"
491 },
492 "dist": {
493 "type": "zip",
494 "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/206dfefc0ffe9cebf65c413e3d0e809c82fbf00a",
495 "reference": "206dfefc0ffe9cebf65c413e3d0e809c82fbf00a",
496 "shasum": ""
497 },
498 "require": {
499 "php": ">=5.3.3"
500 },
501 "type": "library",
502 "autoload": {
503 "classmap": [
504 "Text/"
505 ]
506 },
507 "notification-url": "https://packagist.org/downloads/",
508 "include-path": [
509 ""
510 ],
511 "license": [
512 "BSD-3-Clause"
513 ],
514 "authors": [
515 {
516 "name": "Sebastian Bergmann",
517 "email": "sb@sebastian-bergmann.de",
518 "role": "lead"
519 }
520 ],
521 "description": "Simple template engine.",
522 "homepage": "https://github.com/sebastianbergmann/php-text-template/",
523 "keywords": [
524 "template"
525 ],
526 "time": "2014-01-30 17:20:04"
527 },
528 {
529 "name": "phpunit/php-timer",
530 "version": "1.0.5",
531 "source": {
532 "type": "git",
533 "url": "https://github.com/sebastianbergmann/php-timer.git",
534 "reference": "19689d4354b295ee3d8c54b4f42c3efb69cbc17c"
535 },
536 "dist": {
537 "type": "zip",
538 "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/19689d4354b295ee3d8c54b4f42c3efb69cbc17c",
539 "reference": "19689d4354b295ee3d8c54b4f42c3efb69cbc17c",
540 "shasum": ""
541 },
542 "require": {
543 "php": ">=5.3.3"
544 },
545 "type": "library",
546 "autoload": {
547 "classmap": [
548 "PHP/"
549 ]
550 },
551 "notification-url": "https://packagist.org/downloads/",
552 "include-path": [
553 ""
554 ],
555 "license": [
556 "BSD-3-Clause"
557 ],
558 "authors": [
559 {
560 "name": "Sebastian Bergmann",
561 "email": "sb@sebastian-bergmann.de",
562 "role": "lead"
563 }
564 ],
565 "description": "Utility class for timing",
566 "homepage": "https://github.com/sebastianbergmann/php-timer/",
567 "keywords": [
568 "timer"
569 ],
570 "time": "2013-08-02 07:42:54"
571 },
572 {
573 "name": "phpunit/php-token-stream",
574 "version": "1.4.1",
575 "source": {
576 "type": "git",
577 "url": "https://github.com/sebastianbergmann/php-token-stream.git",
578 "reference": "eab81d02569310739373308137284e0158424330"
579 },
580 "dist": {
581 "type": "zip",
582 "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/eab81d02569310739373308137284e0158424330",
583 "reference": "eab81d02569310739373308137284e0158424330",
584 "shasum": ""
585 },
586 "require": {
587 "ext-tokenizer": "*",
588 "php": ">=5.3.3"
589 },
590 "require-dev": {
591 "phpunit/phpunit": "~4.2"
592 },
593 "type": "library",
594 "extra": {
595 "branch-alias": {
596 "dev-master": "1.4-dev"
597 }
598 },
599 "autoload": {
600 "classmap": [
601 "src/"
602 ]
603 },
604 "notification-url": "https://packagist.org/downloads/",
605 "license": [
606 "BSD-3-Clause"
607 ],
608 "authors": [
609 {
610 "name": "Sebastian Bergmann",
611 "email": "sebastian@phpunit.de"
612 }
613 ],
614 "description": "Wrapper around PHP's tokenizer extension.",
615 "homepage": "https://github.com/sebastianbergmann/php-token-stream/",
616 "keywords": [
617 "tokenizer"
618 ],
619 "time": "2015-04-08 04:46:07"
620 },
621 {
622 "name": "phpunit/phpunit",
623 "version": "4.6.9",
624 "source": {
625 "type": "git",
626 "url": "https://github.com/sebastianbergmann/phpunit.git",
627 "reference": "816d12536a7a032adc3b68737f82cfbbf98b79c1"
628 },
629 "dist": {
630 "type": "zip",
631 "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/816d12536a7a032adc3b68737f82cfbbf98b79c1",
632 "reference": "816d12536a7a032adc3b68737f82cfbbf98b79c1",
633 "shasum": ""
634 },
635 "require": {
636 "ext-dom": "*",
637 "ext-json": "*",
638 "ext-pcre": "*",
639 "ext-reflection": "*",
640 "ext-spl": "*",
641 "php": ">=5.3.3",
642 "phpspec/prophecy": "~1.3,>=1.3.1",
643 "phpunit/php-code-coverage": "~2.0,>=2.0.11",
644 "phpunit/php-file-iterator": "~1.4",
645 "phpunit/php-text-template": "~1.2",
646 "phpunit/php-timer": "~1.0",
647 "phpunit/phpunit-mock-objects": "~2.3",
648 "sebastian/comparator": "~1.1",
649 "sebastian/diff": "~1.2",
650 "sebastian/environment": "~1.2",
651 "sebastian/exporter": "~1.2",
652 "sebastian/global-state": "~1.0",
653 "sebastian/version": "~1.0",
654 "symfony/yaml": "~2.1|~3.0"
655 },
656 "suggest": {
657 "phpunit/php-invoker": "~1.1"
658 },
659 "bin": [
660 "phpunit"
661 ],
662 "type": "library",
663 "extra": {
664 "branch-alias": {
665 "dev-master": "4.6.x-dev"
666 }
667 },
668 "autoload": {
669 "classmap": [
670 "src/"
671 ]
672 },
673 "notification-url": "https://packagist.org/downloads/",
674 "license": [
675 "BSD-3-Clause"
676 ],
677 "authors": [
678 {
679 "name": "Sebastian Bergmann",
680 "email": "sebastian@phpunit.de",
681 "role": "lead"
682 }
683 ],
684 "description": "The PHP Unit Testing framework.",
685 "homepage": "https://phpunit.de/",
686 "keywords": [
687 "phpunit",
688 "testing",
689 "xunit"
690 ],
691 "time": "2015-05-29 06:00:03"
692 },
693 {
694 "name": "phpunit/phpunit-mock-objects",
695 "version": "2.3.3",
696 "source": {
697 "type": "git",
698 "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git",
699 "reference": "253c005852591fd547fc18cd5b7b43a1ec82d8f7"
700 },
701 "dist": {
702 "type": "zip",
703 "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/253c005852591fd547fc18cd5b7b43a1ec82d8f7",
704 "reference": "253c005852591fd547fc18cd5b7b43a1ec82d8f7",
705 "shasum": ""
706 },
707 "require": {
708 "doctrine/instantiator": "~1.0,>=1.0.2",
709 "php": ">=5.3.3",
710 "phpunit/php-text-template": "~1.2"
711 },
712 "require-dev": {
713 "phpunit/phpunit": "~4.4"
714 },
715 "suggest": {
716 "ext-soap": "*"
717 },
718 "type": "library",
719 "extra": {
720 "branch-alias": {
721 "dev-master": "2.3.x-dev"
722 }
723 },
724 "autoload": {
725 "classmap": [
726 "src/"
727 ]
728 },
729 "notification-url": "https://packagist.org/downloads/",
730 "license": [
731 "BSD-3-Clause"
732 ],
733 "authors": [
734 {
735 "name": "Sebastian Bergmann",
736 "email": "sb@sebastian-bergmann.de",
737 "role": "lead"
738 }
739 ],
740 "description": "Mock Object library for PHPUnit",
741 "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/",
742 "keywords": [
743 "mock",
744 "xunit"
745 ],
746 "time": "2015-05-29 05:19:18"
747 },
748 {
749 "name": "psr/log",
750 "version": "1.0.0",
751 "source": {
752 "type": "git",
753 "url": "https://github.com/php-fig/log.git",
754 "reference": "fe0936ee26643249e916849d48e3a51d5f5e278b"
755 },
756 "dist": {
757 "type": "zip",
758 "url": "https://api.github.com/repos/php-fig/log/zipball/fe0936ee26643249e916849d48e3a51d5f5e278b",
759 "reference": "fe0936ee26643249e916849d48e3a51d5f5e278b",
760 "shasum": ""
761 },
762 "type": "library",
763 "autoload": {
764 "psr-0": {
765 "Psr\\Log\\": ""
766 }
767 },
768 "notification-url": "https://packagist.org/downloads/",
769 "license": [
770 "MIT"
771 ],
772 "authors": [
773 {
774 "name": "PHP-FIG",
775 "homepage": "http://www.php-fig.org/"
776 }
777 ],
778 "description": "Common interface for logging libraries",
779 "keywords": [
780 "log",
781 "psr",
782 "psr-3"
783 ],
784 "time": "2012-12-21 11:40:51"
785 },
786 {
787 "name": "satooshi/php-coveralls",
788 "version": "v0.6.1",
789 "source": {
790 "type": "git",
791 "url": "https://github.com/satooshi/php-coveralls.git",
792 "reference": "dd0df95bd37a7cf5c5c50304dfe260ffe4b50760"
793 },
794 "dist": {
795 "type": "zip",
796 "url": "https://api.github.com/repos/satooshi/php-coveralls/zipball/dd0df95bd37a7cf5c5c50304dfe260ffe4b50760",
797 "reference": "dd0df95bd37a7cf5c5c50304dfe260ffe4b50760",
798 "shasum": ""
799 },
800 "require": {
801 "ext-curl": "*",
802 "ext-json": "*",
803 "ext-simplexml": "*",
804 "guzzle/guzzle": ">=3.0",
805 "php": ">=5.3",
806 "psr/log": "1.0.0",
807 "symfony/config": ">=2.0",
808 "symfony/console": ">=2.0",
809 "symfony/stopwatch": ">=2.2",
810 "symfony/yaml": ">=2.0"
811 },
812 "require-dev": {
813 "apigen/apigen": "2.8.*@stable",
814 "pdepend/pdepend": "dev-master",
815 "phpmd/phpmd": "dev-master",
816 "phpunit/php-invoker": ">=1.1.0,<1.2.0",
817 "phpunit/phpunit": "3.7.*@stable",
818 "sebastian/finder-facade": "dev-master",
819 "sebastian/phpcpd": "1.4.*@stable",
820 "squizlabs/php_codesniffer": "1.4.*@stable",
821 "theseer/fdomdocument": "dev-master"
822 },
823 "bin": [
824 "composer/bin/coveralls"
825 ],
826 "type": "library",
827 "autoload": {
828 "psr-0": {
829 "Contrib\\Component": "src/",
830 "Contrib\\Bundle": "src/"
831 }
832 },
833 "notification-url": "https://packagist.org/downloads/",
834 "license": [
835 "MIT"
836 ],
837 "authors": [
838 {
839 "name": "Kitamura Satoshi",
840 "email": "with.no.parachute@gmail.com",
841 "homepage": "https://www.facebook.com/satooshi.jp"
842 }
843 ],
844 "description": "PHP client library for Coveralls API",
845 "homepage": "https://github.com/satooshi/php-coveralls",
846 "keywords": [
847 "ci",
848 "coverage",
849 "github",
850 "test"
851 ],
852 "time": "2013-05-04 08:07:33"
853 },
854 {
855 "name": "sebastian/comparator",
856 "version": "1.1.1",
857 "source": {
858 "type": "git",
859 "url": "https://github.com/sebastianbergmann/comparator.git",
860 "reference": "1dd8869519a225f7f2b9eb663e225298fade819e"
861 },
862 "dist": {
863 "type": "zip",
864 "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/1dd8869519a225f7f2b9eb663e225298fade819e",
865 "reference": "1dd8869519a225f7f2b9eb663e225298fade819e",
866 "shasum": ""
867 },
868 "require": {
869 "php": ">=5.3.3",
870 "sebastian/diff": "~1.2",
871 "sebastian/exporter": "~1.2"
872 },
873 "require-dev": {
874 "phpunit/phpunit": "~4.4"
875 },
876 "type": "library",
877 "extra": {
878 "branch-alias": {
879 "dev-master": "1.1.x-dev"
880 }
881 },
882 "autoload": {
883 "classmap": [
884 "src/"
885 ]
886 },
887 "notification-url": "https://packagist.org/downloads/",
888 "license": [
889 "BSD-3-Clause"
890 ],
891 "authors": [
892 {
893 "name": "Jeff Welch",
894 "email": "whatthejeff@gmail.com"
895 },
896 {
897 "name": "Volker Dusch",
898 "email": "github@wallbash.com"
899 },
900 {
901 "name": "Bernhard Schussek",
902 "email": "bschussek@2bepublished.at"
903 },
904 {
905 "name": "Sebastian Bergmann",
906 "email": "sebastian@phpunit.de"
907 }
908 ],
909 "description": "Provides the functionality to compare PHP values for equality",
910 "homepage": "http://www.github.com/sebastianbergmann/comparator",
911 "keywords": [
912 "comparator",
913 "compare",
914 "equality"
915 ],
916 "time": "2015-01-29 16:28:08"
917 },
918 {
919 "name": "sebastian/diff",
920 "version": "1.3.0",
921 "source": {
922 "type": "git",
923 "url": "https://github.com/sebastianbergmann/diff.git",
924 "reference": "863df9687835c62aa423a22412d26fa2ebde3fd3"
925 },
926 "dist": {
927 "type": "zip",
928 "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/863df9687835c62aa423a22412d26fa2ebde3fd3",
929 "reference": "863df9687835c62aa423a22412d26fa2ebde3fd3",
930 "shasum": ""
931 },
932 "require": {
933 "php": ">=5.3.3"
934 },
935 "require-dev": {
936 "phpunit/phpunit": "~4.2"
937 },
938 "type": "library",
939 "extra": {
940 "branch-alias": {
941 "dev-master": "1.3-dev"
942 }
943 },
944 "autoload": {
945 "classmap": [
946 "src/"
947 ]
948 },
949 "notification-url": "https://packagist.org/downloads/",
950 "license": [
951 "BSD-3-Clause"
952 ],
953 "authors": [
954 {
955 "name": "Kore Nordmann",
956 "email": "mail@kore-nordmann.de"
957 },
958 {
959 "name": "Sebastian Bergmann",
960 "email": "sebastian@phpunit.de"
961 }
962 ],
963 "description": "Diff implementation",
964 "homepage": "http://www.github.com/sebastianbergmann/diff",
965 "keywords": [
966 "diff"
967 ],
968 "time": "2015-02-22 15:13:53"
969 },
970 {
971 "name": "sebastian/environment",
972 "version": "1.2.2",
973 "source": {
974 "type": "git",
975 "url": "https://github.com/sebastianbergmann/environment.git",
976 "reference": "5a8c7d31914337b69923db26c4221b81ff5a196e"
977 },
978 "dist": {
979 "type": "zip",
980 "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/5a8c7d31914337b69923db26c4221b81ff5a196e",
981 "reference": "5a8c7d31914337b69923db26c4221b81ff5a196e",
982 "shasum": ""
983 },
984 "require": {
985 "php": ">=5.3.3"
986 },
987 "require-dev": {
988 "phpunit/phpunit": "~4.4"
989 },
990 "type": "library",
991 "extra": {
992 "branch-alias": {
993 "dev-master": "1.3.x-dev"
994 }
995 },
996 "autoload": {
997 "classmap": [
998 "src/"
999 ]
1000 },
1001 "notification-url": "https://packagist.org/downloads/",
1002 "license": [
1003 "BSD-3-Clause"
1004 ],
1005 "authors": [
1006 {
1007 "name": "Sebastian Bergmann",
1008 "email": "sebastian@phpunit.de"
1009 }
1010 ],
1011 "description": "Provides functionality to handle HHVM/PHP environments",
1012 "homepage": "http://www.github.com/sebastianbergmann/environment",
1013 "keywords": [
1014 "Xdebug",
1015 "environment",
1016 "hhvm"
1017 ],
1018 "time": "2015-01-01 10:01:08"
1019 },
1020 {
1021 "name": "sebastian/exporter",
1022 "version": "1.2.0",
1023 "source": {
1024 "type": "git",
1025 "url": "https://github.com/sebastianbergmann/exporter.git",
1026 "reference": "84839970d05254c73cde183a721c7af13aede943"
1027 },
1028 "dist": {
1029 "type": "zip",
1030 "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/84839970d05254c73cde183a721c7af13aede943",
1031 "reference": "84839970d05254c73cde183a721c7af13aede943",
1032 "shasum": ""
1033 },
1034 "require": {
1035 "php": ">=5.3.3",
1036 "sebastian/recursion-context": "~1.0"
1037 },
1038 "require-dev": {
1039 "phpunit/phpunit": "~4.4"
1040 },
1041 "type": "library",
1042 "extra": {
1043 "branch-alias": {
1044 "dev-master": "1.2.x-dev"
1045 }
1046 },
1047 "autoload": {
1048 "classmap": [
1049 "src/"
1050 ]
1051 },
1052 "notification-url": "https://packagist.org/downloads/",
1053 "license": [
1054 "BSD-3-Clause"
1055 ],
1056 "authors": [
1057 {
1058 "name": "Jeff Welch",
1059 "email": "whatthejeff@gmail.com"
1060 },
1061 {
1062 "name": "Volker Dusch",
1063 "email": "github@wallbash.com"
1064 },
1065 {
1066 "name": "Bernhard Schussek",
1067 "email": "bschussek@2bepublished.at"
1068 },
1069 {
1070 "name": "Sebastian Bergmann",
1071 "email": "sebastian@phpunit.de"
1072 },
1073 {
1074 "name": "Adam Harvey",
1075 "email": "aharvey@php.net"
1076 }
1077 ],
1078 "description": "Provides the functionality to export PHP variables for visualization",
1079 "homepage": "http://www.github.com/sebastianbergmann/exporter",
1080 "keywords": [
1081 "export",
1082 "exporter"
1083 ],
1084 "time": "2015-01-27 07:23:06"
1085 },
1086 {
1087 "name": "sebastian/global-state",
1088 "version": "1.0.0",
1089 "source": {
1090 "type": "git",
1091 "url": "https://github.com/sebastianbergmann/global-state.git",
1092 "reference": "c7428acdb62ece0a45e6306f1ae85e1c05b09c01"
1093 },
1094 "dist": {
1095 "type": "zip",
1096 "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/c7428acdb62ece0a45e6306f1ae85e1c05b09c01",
1097 "reference": "c7428acdb62ece0a45e6306f1ae85e1c05b09c01",
1098 "shasum": ""
1099 },
1100 "require": {
1101 "php": ">=5.3.3"
1102 },
1103 "require-dev": {
1104 "phpunit/phpunit": "~4.2"
1105 },
1106 "suggest": {
1107 "ext-uopz": "*"
1108 },
1109 "type": "library",
1110 "extra": {
1111 "branch-alias": {
1112 "dev-master": "1.0-dev"
1113 }
1114 },
1115 "autoload": {
1116 "classmap": [
1117 "src/"
1118 ]
1119 },
1120 "notification-url": "https://packagist.org/downloads/",
1121 "license": [
1122 "BSD-3-Clause"
1123 ],
1124 "authors": [
1125 {
1126 "name": "Sebastian Bergmann",
1127 "email": "sebastian@phpunit.de"
1128 }
1129 ],
1130 "description": "Snapshotting of global state",
1131 "homepage": "http://www.github.com/sebastianbergmann/global-state",
1132 "keywords": [
1133 "global state"
1134 ],
1135 "time": "2014-10-06 09:23:50"
1136 },
1137 {
1138 "name": "sebastian/recursion-context",
1139 "version": "1.0.0",
1140 "source": {
1141 "type": "git",
1142 "url": "https://github.com/sebastianbergmann/recursion-context.git",
1143 "reference": "3989662bbb30a29d20d9faa04a846af79b276252"
1144 },
1145 "dist": {
1146 "type": "zip",
1147 "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/3989662bbb30a29d20d9faa04a846af79b276252",
1148 "reference": "3989662bbb30a29d20d9faa04a846af79b276252",
1149 "shasum": ""
1150 },
1151 "require": {
1152 "php": ">=5.3.3"
1153 },
1154 "require-dev": {
1155 "phpunit/phpunit": "~4.4"
1156 },
1157 "type": "library",
1158 "extra": {
1159 "branch-alias": {
1160 "dev-master": "1.0.x-dev"
1161 }
1162 },
1163 "autoload": {
1164 "classmap": [
1165 "src/"
1166 ]
1167 },
1168 "notification-url": "https://packagist.org/downloads/",
1169 "license": [
1170 "BSD-3-Clause"
1171 ],
1172 "authors": [
1173 {
1174 "name": "Jeff Welch",
1175 "email": "whatthejeff@gmail.com"
1176 },
1177 {
1178 "name": "Sebastian Bergmann",
1179 "email": "sebastian@phpunit.de"
1180 },
1181 {
1182 "name": "Adam Harvey",
1183 "email": "aharvey@php.net"
1184 }
1185 ],
1186 "description": "Provides functionality to recursively process PHP variables",
1187 "homepage": "http://www.github.com/sebastianbergmann/recursion-context",
1188 "time": "2015-01-24 09:48:32"
1189 },
1190 {
1191 "name": "sebastian/version",
1192 "version": "1.0.5",
1193 "source": {
1194 "type": "git",
1195 "url": "https://github.com/sebastianbergmann/version.git",
1196 "reference": "ab931d46cd0d3204a91e1b9a40c4bc13032b58e4"
1197 },
1198 "dist": {
1199 "type": "zip",
1200 "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/ab931d46cd0d3204a91e1b9a40c4bc13032b58e4",
1201 "reference": "ab931d46cd0d3204a91e1b9a40c4bc13032b58e4",
1202 "shasum": ""
1203 },
1204 "type": "library",
1205 "autoload": {
1206 "classmap": [
1207 "src/"
1208 ]
1209 },
1210 "notification-url": "https://packagist.org/downloads/",
1211 "license": [
1212 "BSD-3-Clause"
1213 ],
1214 "authors": [
1215 {
1216 "name": "Sebastian Bergmann",
1217 "email": "sebastian@phpunit.de",
1218 "role": "lead"
1219 }
1220 ],
1221 "description": "Library that helps with managing the version number of Git-hosted PHP projects",
1222 "homepage": "https://github.com/sebastianbergmann/version",
1223 "time": "2015-02-24 06:35:25"
1224 },
1225 {
1226 "name": "squizlabs/php_codesniffer",
1227 "version": "2.3.2",
1228 "source": {
1229 "type": "git",
1230 "url": "https://github.com/squizlabs/PHP_CodeSniffer.git",
1231 "reference": "e96d8579fbed0c95ecf2a0501ec4f307a4aa6404"
1232 },
1233 "dist": {
1234 "type": "zip",
1235 "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/e96d8579fbed0c95ecf2a0501ec4f307a4aa6404",
1236 "reference": "e96d8579fbed0c95ecf2a0501ec4f307a4aa6404",
1237 "shasum": ""
1238 },
1239 "require": {
1240 "ext-tokenizer": "*",
1241 "ext-xmlwriter": "*",
1242 "php": ">=5.1.2"
1243 },
1244 "bin": [
1245 "scripts/phpcs",
1246 "scripts/phpcbf"
1247 ],
1248 "type": "library",
1249 "extra": {
1250 "branch-alias": {
1251 "dev-master": "2.0.x-dev"
1252 }
1253 },
1254 "autoload": {
1255 "classmap": [
1256 "CodeSniffer.php",
1257 "CodeSniffer/CLI.php",
1258 "CodeSniffer/Exception.php",
1259 "CodeSniffer/File.php",
1260 "CodeSniffer/Fixer.php",
1261 "CodeSniffer/Report.php",
1262 "CodeSniffer/Reporting.php",
1263 "CodeSniffer/Sniff.php",
1264 "CodeSniffer/Tokens.php",
1265 "CodeSniffer/Reports/",
1266 "CodeSniffer/Tokenizers/",
1267 "CodeSniffer/DocGenerators/",
1268 "CodeSniffer/Standards/AbstractPatternSniff.php",
1269 "CodeSniffer/Standards/AbstractScopeSniff.php",
1270 "CodeSniffer/Standards/AbstractVariableSniff.php",
1271 "CodeSniffer/Standards/IncorrectPatternException.php",
1272 "CodeSniffer/Standards/Generic/Sniffs/",
1273 "CodeSniffer/Standards/MySource/Sniffs/",
1274 "CodeSniffer/Standards/PEAR/Sniffs/",
1275 "CodeSniffer/Standards/PSR1/Sniffs/",
1276 "CodeSniffer/Standards/PSR2/Sniffs/",
1277 "CodeSniffer/Standards/Squiz/Sniffs/",
1278 "CodeSniffer/Standards/Zend/Sniffs/"
1279 ]
1280 },
1281 "notification-url": "https://packagist.org/downloads/",
1282 "license": [
1283 "BSD-3-Clause"
1284 ],
1285 "authors": [
1286 {
1287 "name": "Greg Sherwood",
1288 "role": "lead"
1289 }
1290 ],
1291 "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.",
1292 "homepage": "http://www.squizlabs.com/php-codesniffer",
1293 "keywords": [
1294 "phpcs",
1295 "standards"
1296 ],
1297 "time": "2015-04-28 23:28:20"
1298 },
1299 {
1300 "name": "symfony/config",
1301 "version": "v2.7.0",
1302 "source": {
1303 "type": "git",
1304 "url": "https://github.com/symfony/Config.git",
1305 "reference": "537e9912063e66aa70cbcddd7d6e6e8db61d98e4"
1306 },
1307 "dist": {
1308 "type": "zip",
1309 "url": "https://api.github.com/repos/symfony/Config/zipball/537e9912063e66aa70cbcddd7d6e6e8db61d98e4",
1310 "reference": "537e9912063e66aa70cbcddd7d6e6e8db61d98e4",
1311 "shasum": ""
1312 },
1313 "require": {
1314 "php": ">=5.3.9",
1315 "symfony/filesystem": "~2.3"
1316 },
1317 "require-dev": {
1318 "symfony/phpunit-bridge": "~2.7"
1319 },
1320 "type": "library",
1321 "extra": {
1322 "branch-alias": {
1323 "dev-master": "2.7-dev"
1324 }
1325 },
1326 "autoload": {
1327 "psr-4": {
1328 "Symfony\\Component\\Config\\": ""
1329 }
1330 },
1331 "notification-url": "https://packagist.org/downloads/",
1332 "license": [
1333 "MIT"
1334 ],
1335 "authors": [
1336 {
1337 "name": "Fabien Potencier",
1338 "email": "fabien@symfony.com"
1339 },
1340 {
1341 "name": "Symfony Community",
1342 "homepage": "https://symfony.com/contributors"
1343 }
1344 ],
1345 "description": "Symfony Config Component",
1346 "homepage": "https://symfony.com",
1347 "time": "2015-05-15 13:33:16"
1348 },
1349 {
1350 "name": "symfony/console",
1351 "version": "v2.7.0",
1352 "source": {
1353 "type": "git",
1354 "url": "https://github.com/symfony/Console.git",
1355 "reference": "7f0bec04961c61c961df0cb8c2ae88dbfd83f399"
1356 },
1357 "dist": {
1358 "type": "zip",
1359 "url": "https://api.github.com/repos/symfony/Console/zipball/7f0bec04961c61c961df0cb8c2ae88dbfd83f399",
1360 "reference": "7f0bec04961c61c961df0cb8c2ae88dbfd83f399",
1361 "shasum": ""
1362 },
1363 "require": {
1364 "php": ">=5.3.9"
1365 },
1366 "require-dev": {
1367 "psr/log": "~1.0",
1368 "symfony/event-dispatcher": "~2.1",
1369 "symfony/phpunit-bridge": "~2.7",
1370 "symfony/process": "~2.1"
1371 },
1372 "suggest": {
1373 "psr/log": "For using the console logger",
1374 "symfony/event-dispatcher": "",
1375 "symfony/process": ""
1376 },
1377 "type": "library",
1378 "extra": {
1379 "branch-alias": {
1380 "dev-master": "2.7-dev"
1381 }
1382 },
1383 "autoload": {
1384 "psr-4": {
1385 "Symfony\\Component\\Console\\": ""
1386 }
1387 },
1388 "notification-url": "https://packagist.org/downloads/",
1389 "license": [
1390 "MIT"
1391 ],
1392 "authors": [
1393 {
1394 "name": "Fabien Potencier",
1395 "email": "fabien@symfony.com"
1396 },
1397 {
1398 "name": "Symfony Community",
1399 "homepage": "https://symfony.com/contributors"
1400 }
1401 ],
1402 "description": "Symfony Console Component",
1403 "homepage": "https://symfony.com",
1404 "time": "2015-05-29 16:22:24"
1405 },
1406 {
1407 "name": "symfony/event-dispatcher",
1408 "version": "v2.7.0",
1409 "source": {
1410 "type": "git",
1411 "url": "https://github.com/symfony/EventDispatcher.git",
1412 "reference": "687039686d0e923429ba6e958d0baa920cd5d458"
1413 },
1414 "dist": {
1415 "type": "zip",
1416 "url": "https://api.github.com/repos/symfony/EventDispatcher/zipball/687039686d0e923429ba6e958d0baa920cd5d458",
1417 "reference": "687039686d0e923429ba6e958d0baa920cd5d458",
1418 "shasum": ""
1419 },
1420 "require": {
1421 "php": ">=5.3.9"
1422 },
1423 "require-dev": {
1424 "psr/log": "~1.0",
1425 "symfony/config": "~2.0,>=2.0.5",
1426 "symfony/dependency-injection": "~2.6",
1427 "symfony/expression-language": "~2.6",
1428 "symfony/phpunit-bridge": "~2.7",
1429 "symfony/stopwatch": "~2.3"
1430 },
1431 "suggest": {
1432 "symfony/dependency-injection": "",
1433 "symfony/http-kernel": ""
1434 },
1435 "type": "library",
1436 "extra": {
1437 "branch-alias": {
1438 "dev-master": "2.7-dev"
1439 }
1440 },
1441 "autoload": {
1442 "psr-4": {
1443 "Symfony\\Component\\EventDispatcher\\": ""
1444 }
1445 },
1446 "notification-url": "https://packagist.org/downloads/",
1447 "license": [
1448 "MIT"
1449 ],
1450 "authors": [
1451 {
1452 "name": "Fabien Potencier",
1453 "email": "fabien@symfony.com"
1454 },
1455 {
1456 "name": "Symfony Community",
1457 "homepage": "https://symfony.com/contributors"
1458 }
1459 ],
1460 "description": "Symfony EventDispatcher Component",
1461 "homepage": "https://symfony.com",
1462 "time": "2015-05-02 15:21:08"
1463 },
1464 {
1465 "name": "symfony/filesystem",
1466 "version": "v2.7.0",
1467 "source": {
1468 "type": "git",
1469 "url": "https://github.com/symfony/Filesystem.git",
1470 "reference": "ae4551fd6d4d4f51f2e7390fbc902fbd67f3b7ba"
1471 },
1472 "dist": {
1473 "type": "zip",
1474 "url": "https://api.github.com/repos/symfony/Filesystem/zipball/ae4551fd6d4d4f51f2e7390fbc902fbd67f3b7ba",
1475 "reference": "ae4551fd6d4d4f51f2e7390fbc902fbd67f3b7ba",
1476 "shasum": ""
1477 },
1478 "require": {
1479 "php": ">=5.3.9"
1480 },
1481 "require-dev": {
1482 "symfony/phpunit-bridge": "~2.7"
1483 },
1484 "type": "library",
1485 "extra": {
1486 "branch-alias": {
1487 "dev-master": "2.7-dev"
1488 }
1489 },
1490 "autoload": {
1491 "psr-4": {
1492 "Symfony\\Component\\Filesystem\\": ""
1493 }
1494 },
1495 "notification-url": "https://packagist.org/downloads/",
1496 "license": [
1497 "MIT"
1498 ],
1499 "authors": [
1500 {
1501 "name": "Fabien Potencier",
1502 "email": "fabien@symfony.com"
1503 },
1504 {
1505 "name": "Symfony Community",
1506 "homepage": "https://symfony.com/contributors"
1507 }
1508 ],
1509 "description": "Symfony Filesystem Component",
1510 "homepage": "https://symfony.com",
1511 "time": "2015-05-15 13:33:16"
1512 },
1513 {
1514 "name": "symfony/stopwatch",
1515 "version": "v2.7.0",
1516 "source": {
1517 "type": "git",
1518 "url": "https://github.com/symfony/Stopwatch.git",
1519 "reference": "7702945bceddc0e1f744519abb8a2baeb94bd5ce"
1520 },
1521 "dist": {
1522 "type": "zip",
1523 "url": "https://api.github.com/repos/symfony/Stopwatch/zipball/7702945bceddc0e1f744519abb8a2baeb94bd5ce",
1524 "reference": "7702945bceddc0e1f744519abb8a2baeb94bd5ce",
1525 "shasum": ""
1526 },
1527 "require": {
1528 "php": ">=5.3.9"
1529 },
1530 "require-dev": {
1531 "symfony/phpunit-bridge": "~2.7"
1532 },
1533 "type": "library",
1534 "extra": {
1535 "branch-alias": {
1536 "dev-master": "2.7-dev"
1537 }
1538 },
1539 "autoload": {
1540 "psr-4": {
1541 "Symfony\\Component\\Stopwatch\\": ""
1542 }
1543 },
1544 "notification-url": "https://packagist.org/downloads/",
1545 "license": [
1546 "MIT"
1547 ],
1548 "authors": [
1549 {
1550 "name": "Fabien Potencier",
1551 "email": "fabien@symfony.com"
1552 },
1553 {
1554 "name": "Symfony Community",
1555 "homepage": "https://symfony.com/contributors"
1556 }
1557 ],
1558 "description": "Symfony Stopwatch Component",
1559 "homepage": "https://symfony.com",
1560 "time": "2015-05-02 15:21:08"
1561 },
1562 {
1563 "name": "symfony/yaml",
1564 "version": "v2.7.0",
1565 "source": {
1566 "type": "git",
1567 "url": "https://github.com/symfony/Yaml.git",
1568 "reference": "4a29a5248aed4fb45f626a7bbbd330291492f5c3"
1569 },
1570 "dist": {
1571 "type": "zip",
1572 "url": "https://api.github.com/repos/symfony/Yaml/zipball/4a29a5248aed4fb45f626a7bbbd330291492f5c3",
1573 "reference": "4a29a5248aed4fb45f626a7bbbd330291492f5c3",
1574 "shasum": ""
1575 },
1576 "require": {
1577 "php": ">=5.3.9"
1578 },
1579 "require-dev": {
1580 "symfony/phpunit-bridge": "~2.7"
1581 },
1582 "type": "library",
1583 "extra": {
1584 "branch-alias": {
1585 "dev-master": "2.7-dev"
1586 }
1587 },
1588 "autoload": {
1589 "psr-4": {
1590 "Symfony\\Component\\Yaml\\": ""
1591 }
1592 },
1593 "notification-url": "https://packagist.org/downloads/",
1594 "license": [
1595 "MIT"
1596 ],
1597 "authors": [
1598 {
1599 "name": "Fabien Potencier",
1600 "email": "fabien@symfony.com"
1601 },
1602 {
1603 "name": "Symfony Community",
1604 "homepage": "https://symfony.com/contributors"
1605 }
1606 ],
1607 "description": "Symfony Yaml Component",
1608 "homepage": "https://symfony.com",
1609 "time": "2015-05-02 15:21:08"
1610 }
1611 ],
1612 "aliases": [],
1613 "minimum-stability": "stable",
1614 "stability-flags": {
1615 "codeclimate/php-test-reporter": 20
1616 },
1617 "prefer-stable": false,
1618 "prefer-lowest": false,
1619 "platform": {
1620 "php": ">=5.4"
1621 },
1622 "platform-dev": []
1623 }
0 <phpunit bootstrap="vendor/autoload.php" colors="true">
1 <testsuites>
2 <testsuite name="dflydev FIG Cookies Tests">
3 <directory>./tests</directory>
4 </testsuite>
5 </testsuites>
6 </phpunit>
0 <?php
1
2 namespace Dflydev\FigCookies;
3
4 class Cookie
5 {
6 /**
7 * @var string
8 */
9 private $name;
10
11 /**
12 * @var string|null
13 */
14 private $value;
15
16 /**
17 * @param string $name
18 * @param string|null $value
19 */
20 public function __construct($name, $value = null)
21 {
22 $this->name = $name;
23 $this->value = $value;
24 }
25
26 /**
27 * @return string
28 */
29 public function getName()
30 {
31 return $this->name;
32 }
33
34 /**
35 * @return string|null
36 */
37 public function getValue()
38 {
39 return $this->value;
40 }
41
42 /**
43 * @param string|null $value
44 * @return Cookie
45 */
46 public function withValue($value = null)
47 {
48 $clone = clone($this);
49
50 $clone->value = $value;
51
52 return $clone;
53 }
54
55 /**
56 * Render Cookie as a string.
57 *
58 * @return string
59 */
60 public function __toString()
61 {
62 return urlencode($this->name).'='.urlencode($this->value);
63 }
64
65 /**
66 * Create a Cookie.
67 *
68 * @param string $name
69 * @param string|null $value
70 * @return Cookie
71 */
72 public static function create($name, $value = null)
73 {
74 return new static($name, $value);
75 }
76
77 /**
78 * Create a list of Cookies from a Cookie header value string.
79 *
80 * @param string $string
81 * @return Cookie[]
82 */
83 public static function listFromCookieString($string)
84 {
85 $cookies = StringUtil::splitOnAttributeDelimiter($string);
86
87 return array_map(function ($cookiePair) {
88 return static::oneFromCookiePair($cookiePair);
89 }, $cookies);
90 }
91
92 /**
93 * Create one Cookie from a cookie key/value header value string.
94 *
95 * @param string $string
96 * @return Cookie
97 */
98 public static function oneFromCookiePair($string)
99 {
100 list ($cookieName, $cookieValue) = StringUtil::splitCookiePair($string);
101
102 /** @var Cookie $cookie */
103 $cookie = new static($cookieName);
104
105 if (! is_null($cookieValue)) {
106 $cookie = $cookie->withValue($cookieValue);
107 }
108
109 return $cookie;
110 }
111 }
0 <?php
1
2 namespace Dflydev\FigCookies;
3
4 use Psr\Http\Message\RequestInterface;
5
6 class Cookies
7 {
8 /**
9 * The name of the Cookie header.
10 */
11 const COOKIE_HEADER = 'Cookie';
12
13 /**
14 * @var Cookie[]
15 */
16 private $cookies = [];
17
18 /**
19 * @param Cookie[] $cookies
20 */
21 public function __construct(array $cookies = [])
22 {
23 foreach ($cookies as $cookie) {
24 $this->cookies[$cookie->getName()] = $cookie;
25 }
26 }
27
28 /**
29 * @param $name
30 * @return bool
31 */
32 public function has($name)
33 {
34 return isset($this->cookies[$name]);
35 }
36
37 /**
38 * @param $name
39 * @return Cookie|null
40 */
41 public function get($name)
42 {
43 if (! $this->has($name)) {
44 return null;
45 }
46
47 return $this->cookies[$name];
48 }
49
50 /**
51 * @return Cookie[]
52 */
53 public function getAll()
54 {
55 return array_values($this->cookies);
56 }
57
58 /**
59 * @param Cookie $cookie
60 * @return Cookies
61 */
62 public function with(Cookie $cookie)
63 {
64 $clone = clone($this);
65
66 $clone->cookies[$cookie->getName()] = $cookie;
67
68 return $clone;
69 }
70
71 /**
72 * @param $name
73 * @return Cookies
74 */
75 public function without($name)
76 {
77 $clone = clone($this);
78
79 if (! $clone->has($name)) {
80 return $clone;
81 }
82
83 unset($clone->cookies[$name]);
84
85 return $clone;
86 }
87
88 /**
89 * Render Cookies into a Request.
90 *
91 * @param RequestInterface $request
92 * @return RequestInterface
93 */
94 public function renderIntoCookieHeader(RequestInterface $request)
95 {
96 $cookieString = implode('; ', $this->cookies);
97
98 $request = $request->withHeader(static::COOKIE_HEADER, $cookieString);
99
100 return $request;
101 }
102
103 /**
104 * Create Cookies from a Cookie header value string.
105 *
106 * @param $string
107 * @return static
108 */
109 public static function fromCookieString($string)
110 {
111 return new static(Cookie::listFromCookieString($string));
112 }
113
114 /**
115 * Create Cookies from a Request.
116 *
117 * @param RequestInterface $request
118 * @return Cookies
119 */
120 public static function fromRequest(RequestInterface $request)
121 {
122 $cookieString = $request->getHeaderLine(static::COOKIE_HEADER);
123
124 return static::fromCookieString($cookieString);
125 }
126 }
0 <?php
1
2 namespace Dflydev\FigCookies;
3
4 use InvalidArgumentException;
5 use Psr\Http\Message\RequestInterface;
6
7 class FigRequestCookies
8 {
9 /**
10 * @param RequestInterface $request
11 * @param string $name
12 * @param string|null $value
13 *
14 * @return Cookie
15 */
16 public static function get(RequestInterface $request, $name, $value = null)
17 {
18 $cookies = Cookies::fromRequest($request);
19 if ($cookies->has($name)) {
20 return $cookies->get($name);
21 }
22
23 return Cookie::create($name, $value);
24 }
25
26 /**
27 * @param RequestInterface $request
28 * @param Cookie $cookie
29 *
30 * @return RequestInterface
31 */
32 public static function set(RequestInterface $request, Cookie $cookie)
33 {
34 return Cookies::fromRequest($request)
35 ->with($cookie)
36 ->renderIntoCookieHeader($request)
37 ;
38 }
39
40 /**
41 * @param RequestInterface $request
42 * @param string $name
43 * @param callable $modify
44 *
45 * @return RequestInterface
46 */
47 public static function modify(RequestInterface $request, $name, $modify)
48 {
49 if (! is_callable($modify)) {
50 throw new InvalidArgumentException('$modify must be callable.');
51 }
52
53 $cookies = Cookies::fromRequest($request);
54 $cookie = $modify($cookies->has($name)
55 ? $cookies->get($name)
56 : Cookie::create($name)
57 );
58
59 return $cookies
60 ->with($cookie)
61 ->renderIntoCookieHeader($request)
62 ;
63 }
64
65 /**
66 * @param RequestInterface $request
67 * @param string $name
68 *
69 * @return RequestInterface
70 */
71 public static function remove(RequestInterface $request, $name)
72 {
73 return Cookies::fromRequest($request)
74 ->without($name)
75 ->renderIntoCookieHeader($request)
76 ;
77 }
78 }
0 <?php
1
2 namespace Dflydev\FigCookies;
3
4 use InvalidArgumentException;
5 use Psr\Http\Message\ResponseInterface;
6
7 class FigResponseCookies
8 {
9 /**
10 * @param ResponseInterface $response
11 * @param string $name
12 * @param string|null $value
13 *
14 * @return SetCookie
15 */
16 public static function get(ResponseInterface $response, $name, $value = null)
17 {
18 $setCookies = SetCookies::fromResponse($response);
19 if ($setCookies->has($name)) {
20 return $setCookies->get($name);
21 }
22
23 return SetCookie::create($name, $value);
24 }
25
26 /**
27 * @param ResponseInterface $response
28 * @param SetCookie $setCookie
29 *
30 * @return ResponseInterface
31 */
32 public static function set(ResponseInterface $response, SetCookie $setCookie)
33 {
34 return SetCookies::fromResponse($response)
35 ->with($setCookie)
36 ->renderIntoSetCookieHeader($response)
37 ;
38 }
39
40 /**
41 * @param ResponseInterface $response
42 * @param string $cookieName
43 *
44 * @return ResponseInterface
45 */
46 public static function expire(ResponseInterface $response, $cookieName)
47 {
48 return static::set($response, SetCookie::createExpired($cookieName));
49 }
50
51 /**
52 * @param ResponseInterface $response
53 * @param string $name
54 * @param callable $modify
55 *
56 * @return ResponseInterface
57 */
58 public static function modify(ResponseInterface $response, $name, $modify)
59 {
60 if (! is_callable($modify)) {
61 throw new InvalidArgumentException('$modify must be callable.');
62 }
63
64 $setCookies = SetCookies::fromResponse($response);
65 $setCookie = $modify($setCookies->has($name)
66 ? $setCookies->get($name)
67 : SetCookie::create($name)
68 );
69
70 return $setCookies
71 ->with($setCookie)
72 ->renderIntoSetCookieHeader($response)
73 ;
74 }
75
76 /**
77 * @param ResponseInterface $response
78 * @param string $name
79 *
80 * @return ResponseInterface
81 */
82 public static function remove(ResponseInterface $response, $name)
83 {
84 return SetCookies::fromResponse($response)
85 ->without($name)
86 ->renderIntoSetCookieHeader($response)
87 ;
88 }
89 }
0 <?php
1
2 namespace Dflydev\FigCookies;
3
4 use DateTime;
5 use DateTimeInterface;
6
7 class SetCookie
8 {
9 private $name;
10 private $value;
11 private $expires = 0;
12 private $maxAge = 0;
13 private $path;
14 private $domain;
15 private $secure = false;
16 private $httpOnly = false;
17
18 private function __construct($name, $value = null)
19 {
20 $this->name = $name;
21 $this->value = $value;
22 }
23
24 public function getName()
25 {
26 return $this->name;
27 }
28
29 public function getValue()
30 {
31 return $this->value;
32 }
33
34 public function getExpires()
35 {
36 return $this->expires;
37 }
38
39 public function getMaxAge()
40 {
41 return $this->maxAge;
42 }
43
44 public function getPath()
45 {
46 return $this->path;
47 }
48
49 public function getDomain()
50 {
51 return $this->domain;
52 }
53
54 public function getSecure()
55 {
56 return $this->secure;
57 }
58
59 public function getHttpOnly()
60 {
61 return $this->httpOnly;
62 }
63
64 public function withValue($value = null)
65 {
66 $clone = clone($this);
67
68 $clone->value = $value;
69
70 return $clone;
71 }
72
73 private function resolveExpires($expires = null)
74 {
75 if (is_null($expires)) {
76 return null;
77 }
78
79 if ($expires instanceof DateTime || $expires instanceof DateTimeInterface) {
80 return $expires->getTimestamp();
81 }
82
83 if (is_numeric($expires)) {
84 return $expires;
85 }
86
87 return strtotime($expires);
88 }
89
90 public function withExpires($expires = null)
91 {
92 $expires = $this->resolveExpires($expires);
93
94 $clone = clone($this);
95
96 $clone->expires = $expires;
97
98 return $clone;
99 }
100
101 public function rememberForever()
102 {
103 return $this->withExpires(new DateTime('+5 years'));
104 }
105
106 public function expire()
107 {
108 return $this->withExpires(new DateTime('-5 years'));
109 }
110
111 public function withMaxAge($maxAge = null)
112 {
113 $clone = clone($this);
114
115 $clone->maxAge = $maxAge;
116
117 return $clone;
118 }
119
120 public function withPath($path = null)
121 {
122 $clone = clone($this);
123
124 $clone->path = $path;
125
126 return $clone;
127 }
128
129 public function withDomain($domain = null)
130 {
131 $clone = clone($this);
132
133 $clone->domain = $domain;
134
135 return $clone;
136 }
137
138 public function withSecure($secure = null)
139 {
140 $clone = clone($this);
141
142 $clone->secure = $secure;
143
144 return $clone;
145 }
146
147 public function withHttpOnly($httpOnly = null)
148 {
149 $clone = clone($this);
150
151 $clone->httpOnly = $httpOnly;
152
153 return $clone;
154 }
155
156 public function __toString()
157 {
158 $cookieStringParts = [
159 urlencode($this->name).'='.urlencode($this->value),
160 ];
161
162 $cookieStringParts = $this->appendFormattedDomainPartIfSet($cookieStringParts);
163 $cookieStringParts = $this->appendFormattedPathPartIfSet($cookieStringParts);
164 $cookieStringParts = $this->appendFormattedExpiresPartIfSet($cookieStringParts);
165 $cookieStringParts = $this->appendFormattedMaxAgePartIfSet($cookieStringParts);
166 $cookieStringParts = $this->appendFormattedSecurePartIfSet($cookieStringParts);
167 $cookieStringParts = $this->appendFormattedHttpOnlyPartIfSet($cookieStringParts);
168
169 return implode('; ', $cookieStringParts);
170 }
171
172 public static function create($name, $value = null)
173 {
174 return new static($name, $value);
175 }
176
177 public static function createRememberedForever($name, $value = null)
178 {
179 return static::create($name, $value)->rememberForever();
180 }
181
182 public static function createExpired($name)
183 {
184 return static::create($name)->expire();
185 }
186
187 public static function fromSetCookieString($string)
188 {
189 $rawAttributes = StringUtil::splitOnAttributeDelimiter($string);
190
191 list ($cookieName, $cookieValue) = StringUtil::splitCookiePair(array_shift($rawAttributes));
192
193 /** @var SetCookie $setCookie */
194 $setCookie = new static($cookieName);
195
196 if (! is_null($cookieValue)) {
197 $setCookie = $setCookie->withValue($cookieValue);
198 }
199
200 while ($rawAttribute = array_shift($rawAttributes)) {
201 $rawAttributePair = explode('=', $rawAttribute, 2);
202
203 $attributeKey = $rawAttributePair[0];
204 $attributeValue = count($rawAttributePair) > 1 ? $rawAttributePair[1] : null;
205
206 $attributeKey = strtolower($attributeKey);
207
208 switch ($attributeKey) {
209 case 'expires':
210 $setCookie = $setCookie->withExpires($attributeValue);
211 break;
212 case 'max-age':
213 $setCookie = $setCookie->withMaxAge($attributeValue);
214 break;
215 case 'domain':
216 $setCookie = $setCookie->withDomain($attributeValue);
217 break;
218 case 'path':
219 $setCookie = $setCookie->withPath($attributeValue);
220 break;
221 case 'secure':
222 $setCookie = $setCookie->withSecure(true);
223 break;
224 case 'httponly':
225 $setCookie = $setCookie->withHttpOnly(true);
226 break;
227 }
228
229 }
230
231 return $setCookie;
232 }
233 private function appendFormattedDomainPartIfSet(array $cookieStringParts)
234 {
235 if ($this->domain) {
236 $cookieStringParts[] = sprintf("Domain=%s", $this->domain);
237 }
238
239 return $cookieStringParts;
240 }
241
242 private function appendFormattedPathPartIfSet(array $cookieStringParts)
243 {
244 if ($this->path) {
245 $cookieStringParts[] = sprintf("Path=%s", $this->path);
246 }
247
248 return $cookieStringParts;
249 }
250
251 private function appendFormattedExpiresPartIfSet(array $cookieStringParts)
252 {
253 if ($this->expires) {
254 $cookieStringParts[] = sprintf("Expires=%s", gmdate('D, d M Y H:i:s T', $this->expires));
255 }
256
257 return $cookieStringParts;
258 }
259
260 private function appendFormattedMaxAgePartIfSet(array $cookieStringParts)
261 {
262 if ($this->maxAge) {
263 $cookieStringParts[] = sprintf("Max-Age=%s", $this->maxAge);
264 }
265
266 return $cookieStringParts;
267 }
268
269 private function appendFormattedSecurePartIfSet(array $cookieStringParts)
270 {
271 if ($this->secure) {
272 $cookieStringParts[] = 'Secure';
273 }
274
275 return $cookieStringParts;
276 }
277
278 private function appendFormattedHttpOnlyPartIfSet(array $cookieStringParts)
279 {
280 if ($this->httpOnly) {
281 $cookieStringParts[] = 'HttpOnly';
282 }
283
284 return $cookieStringParts;
285 }
286 }
0 <?php
1
2 namespace Dflydev\FigCookies;
3
4 use Psr\Http\Message\ResponseInterface;
5
6 class SetCookies
7 {
8 /**
9 * The name of the Set-Cookie header.
10 */
11 const SET_COOKIE_HEADER = 'Set-Cookie';
12
13 /**
14 * @var SetCookie[]
15 */
16 private $setCookies = [];
17
18 /**
19 * @param SetCookie[] $setCookies
20 */
21 public function __construct(array $setCookies = [])
22 {
23 foreach ($setCookies as $setCookie) {
24 $this->setCookies[$setCookie->getName()] = $setCookie;
25 }
26 }
27
28 /**
29 * @param string $name
30 * @return bool
31 */
32 public function has($name)
33 {
34 return isset($this->setCookies[$name]);
35 }
36
37 /**
38 * @param string $name
39 * @return SetCookie|null
40 */
41 public function get($name)
42 {
43 if (! $this->has($name)) {
44 return null;
45 }
46
47 return $this->setCookies[$name];
48 }
49
50 /**
51 * @return SetCookie[]
52 */
53 public function getAll()
54 {
55 return array_values($this->setCookies);
56 }
57
58 /**
59 * @param SetCookie $setCookie
60 * @return SetCookies
61 */
62 public function with(SetCookie $setCookie)
63 {
64 $clone = clone($this);
65
66 $clone->setCookies[$setCookie->getName()] = $setCookie;
67
68 return $clone;
69 }
70
71 /**
72 * @param string $name
73 * @return SetCookies
74 */
75 public function without($name)
76 {
77 $clone = clone($this);
78
79 if (! $clone->has($name)) {
80 return $clone;
81 }
82
83 unset($clone->setCookies[$name]);
84
85 return $clone;
86 }
87
88 /**
89 * Render SetCookies into a Response.
90 *
91 * @param ResponseInterface $response
92 * @return ResponseInterface
93 */
94 public function renderIntoSetCookieHeader(ResponseInterface $response)
95 {
96 $response = $response->withoutHeader(static::SET_COOKIE_HEADER);
97 foreach ($this->setCookies as $setCookie) {
98 $response = $response->withAddedHeader(static::SET_COOKIE_HEADER, (string) $setCookie);
99 }
100
101 return $response;
102 }
103
104 /**
105 * Create SetCookies from a collection of SetCookie header value strings.
106 *
107 * @param string[] $setCookieStrings
108 * @return static
109 */
110 public static function fromSetCookieStrings($setCookieStrings)
111 {
112 return new static(array_map(function ($setCookieString) {
113 return SetCookie::fromSetCookieString($setCookieString);
114 }, $setCookieStrings));
115 }
116
117 /**
118 * Create SetCookies from a Response.
119 *
120 * @param ResponseInterface $response
121 * @return SetCookies
122 */
123 public static function fromResponse(ResponseInterface $response)
124 {
125 return new static(array_map(function ($setCookieString) {
126 return SetCookie::fromSetCookieString($setCookieString);
127 }, $response->getHeader(static::SET_COOKIE_HEADER)));
128 }
129 }
0 <?php
1
2 namespace Dflydev\FigCookies;
3
4 class StringUtil
5 {
6 public static function splitOnAttributeDelimiter($string)
7 {
8 return array_filter(preg_split('@\s*[;]\s*@', $string));
9 }
10
11 public static function splitCookiePair($string)
12 {
13 $pairParts = explode('=', $string, 2);
14
15 if (count($pairParts) === 1) {
16 $pairParts[1] = '';
17 }
18
19 return array_map(function ($part) {
20 return urldecode($part);
21 }, $pairParts);
22 }
23 }
0 <?php
1
2 namespace Dflydev\FigCookies;
3
4 class CookieTest extends \PHPUnit_Framework_TestCase
5 {
6 /**
7 * @test
8 * @dataProvider provideParsesOneFromCookieStringData
9 */
10 public function it_parses_one_from_cookie_string($cookieString, $expectedName, $expectedValue)
11 {
12 $cookie = Cookie::oneFromCookiePair($cookieString);
13
14 $this->assertCookieNameAndValue($cookie, $expectedName, $expectedValue);
15 }
16
17 /**
18 * @test
19 * @dataProvider provideParsesListFromCookieString
20 */
21 public function it_parses_list_from_cookie_string($cookieString, array $expectedNameValuePairs)
22 {
23 $cookies = Cookie::listFromCookieString($cookieString);
24
25 $this->assertCount(count($expectedNameValuePairs), $cookies);
26
27 for ($i = 0; $i < count($cookies); $i++) {
28 $cookie = $cookies[$i];
29 list ($expectedName, $expectedValue) = $expectedNameValuePairs[$i];
30
31 $this->assertCookieNameAndValue($cookie, $expectedName, $expectedValue);
32 }
33 }
34
35 private function assertCookieNameAndValue(Cookie $cookie, $expectedName, $expectedValue)
36 {
37 $this->assertEquals($expectedName, $cookie->getName());
38 $this->assertEquals($expectedValue, $cookie->getValue());
39 }
40
41 public function provideParsesOneFromCookieStringData()
42 {
43 return [
44 ['someCookie=something', 'someCookie', 'something'],
45 ['hello%3Dworld=how%22are%27you', 'hello=world', 'how"are\'you'],
46 ['empty=', 'empty', ''],
47 ];
48 }
49
50 public function provideParsesListFromCookieString()
51 {
52 return [
53 ['theme=light; sessionToken=abc123', [
54 ['theme', 'light'],
55 ['sessionToken', 'abc123'],
56 ]],
57
58 ['theme=light; sessionToken=abc123;', [
59 ['theme', 'light'],
60 ['sessionToken', 'abc123'],
61 ]],
62 ];
63 }
64 }
0 <?php
1
2 namespace Dflydev\FigCookies;
3
4 class CookiesTest extends \PHPUnit_Framework_TestCase
5 {
6 const INTERFACE_PSR_HTTP_MESSAGE_REQUEST = 'Psr\Http\Message\RequestInterface';
7
8 /**
9 * @param string[] $cookieString
10 * @param Cookie[] $expectedCookies
11 *
12 * @test
13 * @dataProvider provideCookieStringAndExpectedCookiesData
14 */
15 public function it_creates_from_request($cookieString, array $expectedCookies)
16 {
17 $request = $this->prophesize(static::INTERFACE_PSR_HTTP_MESSAGE_REQUEST);
18 $request->getHeaderLine(Cookies::COOKIE_HEADER)->willReturn($cookieString);
19
20 $cookies = Cookies::fromRequest($request->reveal());
21
22 $this->assertEquals($expectedCookies, $cookies->getAll());
23 }
24
25 /**
26 * @param string[] $cookieString
27 * @param Cookie[] $expectedCookies
28 *
29 * @test
30 * @dataProvider provideCookieStringAndExpectedCookiesData
31 */
32 public function it_creates_from_cookie_string($cookieString, array $expectedCookies)
33 {
34 $cookies = Cookies::fromCookieString($cookieString);
35
36 $this->assertEquals($expectedCookies, $cookies->getAll());
37 }
38
39 /**
40 * @param string[] $cookieString
41 * @param Cookie[] $expectedCookies
42 *
43 * @test
44 * @dataProvider provideCookieStringAndExpectedCookiesData
45 */
46 public function it_knows_which_cookies_are_available($cookieString, array $expectedCookies)
47 {
48 $cookies = Cookies::fromCookieString($cookieString);
49
50 foreach ($expectedCookies as $expectedCookie) {
51 $this->assertTrue($cookies->has($expectedCookie->getName()));
52 }
53
54 $this->assertFalse($cookies->has('i know this cookie does not exist'));
55 }
56
57 /**
58 * @test
59 * @dataProvider provideGetsCookieByNameData
60 */
61 public function it_gets_cookie_by_name($cookieString, $cookieName, Cookie $expectedCookie)
62 {
63 $cookies = Cookies::fromCookieString($cookieString);
64
65 $this->assertEquals($expectedCookie, $cookies->get($cookieName));
66 }
67
68 /**
69 * @test
70 */
71 public function it_sets_overrides_and_removes_cookie()
72 {
73 $cookies = new Cookies();
74
75 $cookies = $cookies->with(Cookie::create('theme', 'blue'));
76
77 $this->assertEquals('blue', $cookies->get('theme')->getValue());
78
79 $cookies = $cookies->with(Cookie::create('theme', 'red'));
80
81 $this->assertEquals('red', $cookies->get('theme')->getValue());
82
83 $cookies = $cookies->without('theme');
84
85 $this->assertFalse($cookies->has('theme'));
86 }
87
88 /**
89 * @test
90 */
91 public function it_renders_new_cookies_into_empty_cookie_header()
92 {
93 $cookies = (new Cookies())
94 ->with(Cookie::create('theme', 'light'))
95 ->with(Cookie::create('sessionToken', 'abc123'))
96 ;
97
98 $originalRequest = new FigCookieTestingRequest();
99 $request = $cookies->renderIntoCookieHeader($originalRequest);
100
101 $this->assertNotEquals($request, $originalRequest);
102
103 $this->assertEquals('theme=light; sessionToken=abc123', $request->getHeaderLine(Cookies::COOKIE_HEADER));
104 }
105
106 /**
107 * @test
108 */
109 public function it_renders_added_and_removed_cookies_header()
110 {
111 $cookies = Cookies::fromCookieString('theme=light; sessionToken=abc123; hello=world')
112 ->with(Cookie::create('theme', 'blue'))
113 ->without('sessionToken')
114 ->with(Cookie::create('who', 'me'))
115 ;
116
117 $originalRequest = new FigCookieTestingRequest();
118 $request = $cookies->renderIntoCookieHeader($originalRequest);
119
120 $this->assertNotEquals($request, $originalRequest);
121
122 $this->assertEquals('theme=blue; hello=world; who=me', $request->getHeaderLine(Cookies::COOKIE_HEADER));
123 }
124
125 /**
126 * @test
127 */
128 public function it_gets_cookie_value_from_request()
129 {
130 //
131 // Example of accessing a cookie value.
132 //
133
134 // Simulate a request coming in with several cookies.
135 $request = (new FigCookieTestingRequest())
136 ->withHeader(Cookies::COOKIE_HEADER, 'theme=light; sessionToken=RAPELCGRQ; hello=world')
137 ;
138
139 $theme = Cookies::fromRequest($request)->get('theme')->getValue();
140
141 $this->assertEquals('light', $theme);
142 }
143
144 /**
145 * @test
146 */
147 public function it_gets_and_updates_cookie_value_on_request()
148 {
149 //
150 // Example of naive cookie decryption middleware.
151 //
152 // Shows how to access and manipulate cookies using PSR-7 Request
153 // instances from outside the Request object itself.
154 //
155
156 // Simulate a request coming in with several cookies.
157 $request = (new FigCookieTestingRequest())
158 ->withHeader(Cookies::COOKIE_HEADER, 'theme=light; sessionToken=RAPELCGRQ; hello=world')
159 ;
160
161 // Get our cookies from the request.
162 $cookies = Cookies::fromRequest($request);
163
164 // Ask for the encrypted session token.
165 $encryptedSessionToken = $cookies->get('sessionToken');
166
167 // Get the encrypted value from the cookie and decrypt it.
168 $encryptedValue = $encryptedSessionToken->getValue();
169 $decryptedValue = str_rot13($encryptedValue);
170
171 // Create a new cookie with the decrypted value.
172 $decryptedSessionToken = $encryptedSessionToken->withValue($decryptedValue);
173
174 // Include our decrypted session token with the rest of our cookies.
175 $cookies = $cookies->with($decryptedSessionToken);
176
177 // Render our cookies, along with the newly decrypted session token, into a request.
178 $request = $cookies->renderIntoCookieHeader($request);
179
180 // From this point on, any request based on this one can get the plaintext version
181 // of the session token.
182 $this->assertEquals(
183 'theme=light; sessionToken=ENCRYPTED; hello=world',
184 $request->getHeaderLine(Cookies::COOKIE_HEADER)
185 );
186 }
187
188 public function provideCookieStringAndExpectedCookiesData()
189 {
190 return [
191 [
192 '',
193 []
194 ],
195 [
196 'theme=light',
197 [
198 Cookie::create('theme', 'light'),
199 ]
200 ],
201 [
202 'theme=light; sessionToken=abc123',
203 [
204 Cookie::create('theme', 'light'),
205 Cookie::create('sessionToken', 'abc123'),
206 ]
207 ]
208 ];
209 }
210
211 public function provideGetsCookieByNameData()
212 {
213 return [
214 ['theme=light', 'theme', Cookie::create('theme', 'light')],
215 ['theme=', 'theme', Cookie::create('theme')],
216 ['hello=world; theme=light; sessionToken=abc123', 'theme', Cookie::create('theme', 'light')],
217 ['hello=world; theme=; sessionToken=abc123', 'theme', Cookie::create('theme')],
218 ];
219 }
220 }
0 <?php
1
2 namespace Dflydev\FigCookies;
3
4 use Psr\Http\Message\StreamInterface;
5
6 trait FigCookieTestingMessage
7 {
8 private $headers = [];
9 public function getProtocolVersion()
10 {
11 throw new \RuntimeException("This method has not been implemented.");
12 }
13
14 public function withProtocolVersion($version)
15 {
16 throw new \RuntimeException("This method has not been implemented.");
17 }
18
19 public function hasHeader($name)
20 {
21 throw new \RuntimeException("This method has not been implemented.");
22 }
23
24 public function withHeader($name, $value)
25 {
26 $clone = clone($this);
27
28 $clone->headers[$name] = [$value];
29
30 return $clone;
31 }
32
33 public function withAddedHeader($name, $value)
34 {
35 $clone = clone($this);
36
37 if (! isset($clone->headers[$name])) {
38 $clone->headers[$name] = [];
39 }
40
41 $clone->headers[$name][] = $value;
42
43 return $clone;
44 }
45
46 public function withoutHeader($name)
47 {
48 $clone = clone($this);
49
50 if (isset($clone->headers[$name])) {
51 unset($clone->headers[$name]);
52 }
53
54 return $clone;
55 }
56
57 public function getBody()
58 {
59 throw new \RuntimeException("This method has not been implemented.");
60 }
61
62 public function withBody(StreamInterface $body)
63 {
64 throw new \RuntimeException("This method has not been implemented.");
65 }
66
67 public function getHeaders()
68 {
69 throw new \RuntimeException("This method has not been implemented.");
70 }
71
72 public function getHeader($name)
73 {
74 if (! isset($this->headers[$name])) {
75 return [];
76 }
77
78 return $this->headers[$name];
79 }
80
81 public function getHeaderLine($name)
82 {
83 return implode(',', $this->headers[$name]);
84 }
85
86 public function getHeaderLines($name)
87 {
88 if (! isset($this->headers[$name])) {
89 return [];
90 }
91
92 return $this->headers[$name];
93 }
94 }
0 <?php
1
2 namespace Dflydev\FigCookies;
3
4 use Psr\Http\Message\RequestInterface;
5 use Psr\Http\Message\StreamInterface;
6 use Psr\Http\Message\UriInterface;
7
8 class FigCookieTestingRequest implements RequestInterface
9 {
10 use FigCookieTestingMessage;
11
12 public function getRequestTarget()
13 {
14 throw new \RuntimeException("This method has not been implemented.");
15 }
16
17 public function withRequestTarget($requestTarget)
18 {
19 throw new \RuntimeException("This method has not been implemented.");
20 }
21
22 public function getMethod()
23 {
24 throw new \RuntimeException("This method has not been implemented.");
25 }
26
27 public function withMethod($method)
28 {
29 throw new \RuntimeException("This method has not been implemented.");
30 }
31
32 public function getUri()
33 {
34 throw new \RuntimeException("This method has not been implemented.");
35 }
36
37 public function withUri(UriInterface $uri, $preserveHost = false)
38 {
39 throw new \RuntimeException("This method has not been implemented.");
40 }
41 }
0 <?php
1
2 namespace Dflydev\FigCookies;
3
4 use Psr\Http\Message\ResponseInterface;
5
6 class FigCookieTestingResponse implements ResponseInterface
7 {
8 use FigCookieTestingMessage;
9
10 public function getStatusCode()
11 {
12 throw new \RuntimeException("This method has not been implemented.");
13 }
14
15 public function withStatus($code, $reasonPhrase = '')
16 {
17 throw new \RuntimeException("This method has not been implemented.");
18 }
19
20 public function getReasonPhrase()
21 {
22 throw new \RuntimeException("This method has not been implemented.");
23 }
24
25 }
0 <?php
1
2 namespace Dflydev\FigCookies;
3
4 class FigCookiesTest extends \PHPUnit_Framework_TestCase
5 {
6 /**
7 * @test
8 */
9 public function it_encrypts_and_decrypts_cookies()
10 {
11 // Simulate a request coming in with several cookies.
12 $request = (new FigCookieTestingRequest())
13 ->withHeader(Cookies::COOKIE_HEADER, 'theme=light; sessionToken=RAPELCGRQ; hello=world')
14 ;
15
16 // "Before" Middleware Example
17 //
18 // Get our token from an encrypted cookie value, "decrypt" it, and replace the cookie on the request.
19 // From here on out, any part of the system that gets our token will be able to see the contents
20 // in plaintext.
21 $request = FigRequestCookies::modify($request, 'sessionToken', function (Cookie $cookie) {
22 return $cookie->withValue(str_rot13($cookie->getValue()));
23 });
24
25 // Even though the sessionToken initially comes in "encrypted", at this point (and any point in
26 // the future) the sessionToken cookie will be available in plaintext.
27 $this->assertEquals(
28 'theme=light; sessionToken=ENCRYPTED; hello=world',
29 $request->getHeaderLine(Cookies::COOKIE_HEADER)
30 );
31
32 // Simulate a response going out.
33 $response = (new FigCookieTestingResponse());
34
35 // Various parts of the system will add set cookies to the response. In this case, we are
36 // going to show that the rest of the system interacts with the session token using
37 // plaintext.
38 $response = $response
39 ->withAddedHeader(SetCookies::SET_COOKIE_HEADER, SetCookie::create('theme', 'light'))
40 ->withAddedHeader(SetCookies::SET_COOKIE_HEADER, SetCookie::create('sessionToken', 'ENCRYPTED'))
41 ->withAddedHeader(SetCookies::SET_COOKIE_HEADER, SetCookie::create('hello', 'world'))
42 ;
43
44 // "After" Middleware Example
45 //
46 // Get our token from an unencrypted set cookie value, "encrypt" it, and replace the cook on the response.
47 // From here on out, any part of the system that gets our token will only be able to see the encrypted
48 // value.
49 $response = FigResponseCookies::modify($response, 'sessionToken', function (SetCookie $setCookie) {
50 return $setCookie->withValue(str_rot13($setCookie->getValue()));
51 });
52
53 // Even though the sessionToken intiially went out "decrypted", at this point (and at any point
54 // in the future) the sessionToken cookie will remain "encrypted."
55 $this->assertEquals(
56 ['theme=light', 'sessionToken=RAPELCGRQ', 'hello=world'],
57 $response->getHeader(SetCookies::SET_COOKIE_HEADER)
58 );
59 }
60 }
0 <?php
1
2 namespace Dflydev\FigCookies;
3
4 class FigRequestCookiesTest extends \PHPUnit_Framework_TestCase
5 {
6 /**
7 * @test
8 */
9 public function it_gets_cookies()
10 {
11 $request = (new FigCookieTestingRequest())
12 ->withHeader(Cookies::COOKIE_HEADER, 'theme=light; sessionToken=RAPELCGRQ; hello=world')
13 ;
14
15 $this->assertEquals(
16 'RAPELCGRQ',
17 FigRequestCookies::get($request, 'sessionToken')->getValue()
18 );
19 }
20
21 /**
22 * @test
23 */
24 public function it_sets_cookies()
25 {
26 $request = (new FigCookieTestingRequest())
27 ->withHeader(Cookies::COOKIE_HEADER, 'theme=light; sessionToken=RAPELCGRQ; hello=world')
28 ;
29
30 $request = FigRequestCookies::set($request, Cookie::create('hello', 'WORLD!'));
31
32 $this->assertEquals(
33 'theme=light; sessionToken=RAPELCGRQ; hello=WORLD%21',
34 $request->getHeaderLine('Cookie')
35 );
36 }
37
38 /**
39 * @test
40 */
41 public function it_modifies_cookies()
42 {
43 $request = (new FigCookieTestingRequest())
44 ->withHeader(Cookies::COOKIE_HEADER, 'theme=light; sessionToken=RAPELCGRQ; hello=world')
45 ;
46
47 $request = FigRequestCookies::modify($request, 'hello', function (Cookie $cookie) {
48 return $cookie->withValue(strtoupper($cookie->getName()));
49 });
50
51 $this->assertEquals(
52 'theme=light; sessionToken=RAPELCGRQ; hello=HELLO',
53 $request->getHeaderLine('Cookie')
54 );
55 }
56
57 /**
58 * @test
59 */
60 public function it_removes_cookies()
61 {
62 $request = (new FigCookieTestingRequest())
63 ->withHeader(Cookies::COOKIE_HEADER, 'theme=light; sessionToken=RAPELCGRQ; hello=world')
64 ;
65
66 $request = FigRequestCookies::remove($request, 'sessionToken');
67
68 $this->assertEquals(
69 'theme=light; hello=world',
70 $request->getHeaderLine('Cookie')
71 );
72 }
73 }
0 <?php
1
2 namespace Dflydev\FigCookies;
3
4 class FigResponseCookiesTest extends \PHPUnit_Framework_TestCase
5 {
6 /**
7 * @test
8 */
9 public function it_gets_cookies()
10 {
11 $response = (new FigCookieTestingResponse());
12
13 $response = $response
14 ->withAddedHeader(SetCookies::SET_COOKIE_HEADER, SetCookie::create('theme', 'light'))
15 ->withAddedHeader(SetCookies::SET_COOKIE_HEADER, SetCookie::create('sessionToken', 'ENCRYPTED'))
16 ->withAddedHeader(SetCookies::SET_COOKIE_HEADER, SetCookie::create('hello', 'world'))
17 ;
18
19 $this->assertEquals(
20 'ENCRYPTED',
21 FigResponseCookies::get($response, 'sessionToken')->getValue()
22 );
23 }
24
25 /**
26 * @test
27 */
28 public function it_sets_cookies()
29 {
30 $response = (new FigCookieTestingResponse());
31
32 $response = $response
33 ->withAddedHeader(SetCookies::SET_COOKIE_HEADER, SetCookie::create('theme', 'light'))
34 ->withAddedHeader(SetCookies::SET_COOKIE_HEADER, SetCookie::create('sessionToken', 'ENCRYPTED'))
35 ->withAddedHeader(SetCookies::SET_COOKIE_HEADER, SetCookie::create('hello', 'world'))
36 ;
37
38 $response = FigResponseCookies::set($response, SetCookie::create('hello', 'WORLD!'));
39
40 $this->assertEquals(
41 'theme=light,sessionToken=ENCRYPTED,hello=WORLD%21',
42 $response->getHeaderLine('Set-Cookie')
43 );
44 }
45
46 /**
47 * @test
48 */
49 public function it_modifies_cookies()
50 {
51 $response = (new FigCookieTestingResponse());
52
53 $response = $response
54 ->withAddedHeader(SetCookies::SET_COOKIE_HEADER, SetCookie::create('theme', 'light'))
55 ->withAddedHeader(SetCookies::SET_COOKIE_HEADER, SetCookie::create('sessionToken', 'ENCRYPTED'))
56 ->withAddedHeader(SetCookies::SET_COOKIE_HEADER, SetCookie::create('hello', 'world'))
57 ;
58
59 $response = FigResponseCookies::modify($response, 'hello', function (SetCookie $setCookie) {
60 return $setCookie->withValue(strtoupper($setCookie->getName()));
61 });
62
63 $this->assertEquals(
64 'theme=light,sessionToken=ENCRYPTED,hello=HELLO',
65 $response->getHeaderLine('Set-Cookie')
66 );
67 }
68
69 /**
70 * @test
71 */
72 public function it_removes_cookies()
73 {
74 $response = (new FigCookieTestingResponse());
75
76 $response = $response
77 ->withAddedHeader(SetCookies::SET_COOKIE_HEADER, SetCookie::create('theme', 'light'))
78 ->withAddedHeader(SetCookies::SET_COOKIE_HEADER, SetCookie::create('sessionToken', 'ENCRYPTED'))
79 ->withAddedHeader(SetCookies::SET_COOKIE_HEADER, SetCookie::create('hello', 'world'))
80 ;
81
82 $response = FigResponseCookies::remove($response, 'sessionToken');
83
84 $this->assertEquals(
85 'theme=light,hello=world',
86 $response->getHeaderLine('Set-Cookie')
87 );
88 }
89 }
0 <?php
1
2 namespace Dflydev\FigCookies;
3
4 class SetCookieTest extends \PHPUnit_Framework_TestCase
5 {
6 /**
7 * @test
8 * @dataProvider provideParsesFromSetCookieStringData
9 */
10 public function it_parses_from_set_cookie_string($cookieString, SetCookie $expectedSetCookie)
11 {
12 $setCookie = SetCookie::fromSetCookieString($cookieString);
13
14 $this->assertEquals($expectedSetCookie, $setCookie);
15 $this->assertEquals($cookieString, (string) $setCookie);
16 }
17
18 public function provideParsesFromSetCookieStringData()
19 {
20 return [
21 [
22 'someCookie=',
23 SetCookie::create('someCookie'),
24 ],
25 [
26 'someCookie=someValue',
27 SetCookie::create('someCookie')
28 ->withValue('someValue')
29 ],
30 [
31 'LSID=DQAAAK%2FEaem_vYg; Path=/accounts; Expires=Wed, 13 Jan 2021 22:23:01 GMT; Secure; HttpOnly',
32 SetCookie::create('LSID')
33 ->withValue('DQAAAK/Eaem_vYg')
34 ->withPath('/accounts')
35 ->withExpires('Wed, 13 Jan 2021 22:23:01 GMT')
36 ->withSecure(true)
37 ->withHttpOnly(true)
38 ],
39 [
40 'HSID=AYQEVn%2F.DKrdst; Domain=.foo.com; Path=/; Expires=Wed, 13 Jan 2021 22:23:01 GMT; HttpOnly',
41 SetCookie::create('HSID')
42 ->withValue('AYQEVn/.DKrdst')
43 ->withDomain('.foo.com')
44 ->withPath('/')
45 ->withExpires('Wed, 13 Jan 2021 22:23:01 GMT')
46 ->withHttpOnly(true)
47 ],
48 [
49 'SSID=Ap4P%2F.GTEq; Domain=foo.com; Path=/; Expires=Wed, 13 Jan 2021 22:23:01 GMT; Secure; HttpOnly',
50 SetCookie::create('SSID')
51 ->withValue('Ap4P/.GTEq')
52 ->withDomain('foo.com')
53 ->withPath('/')
54 ->withExpires('Wed, 13 Jan 2021 22:23:01 GMT')
55 ->withSecure(true)
56 ->withHttpOnly(true)
57 ],
58 [
59 'lu=Rg3vHJZnehYLjVg7qi3bZjzg; Domain=.example.com; Path=/; Expires=Tue, 15 Jan 2013 21:47:38 GMT; HttpOnly',
60 SetCookie::create('lu')
61 ->withValue('Rg3vHJZnehYLjVg7qi3bZjzg')
62 ->withExpires('Tue, 15-Jan-2013 21:47:38 GMT')
63 ->withPath('/')
64 ->withDomain('.example.com')
65 ->withHttpOnly(true)
66 ],
67 [
68 'lu=Rg3vHJZnehYLjVg7qi3bZjzg; Domain=.example.com; Path=/; Max-Age=500; Secure; HttpOnly',
69 SetCookie::create('lu')
70 ->withValue('Rg3vHJZnehYLjVg7qi3bZjzg')
71 ->withMaxAge(500)
72 ->withPath('/')
73 ->withDomain('.example.com')
74 ->withSecure(true)
75 ->withHttpOnly(true)
76 ],
77 [
78 'lu=Rg3vHJZnehYLjVg7qi3bZjzg; Domain=.example.com; Path=/; Expires=Tue, 15 Jan 2013 21:47:38 GMT; Max-Age=500; Secure; HttpOnly',
79 SetCookie::create('lu')
80 ->withValue('Rg3vHJZnehYLjVg7qi3bZjzg')
81 ->withExpires('Tue, 15-Jan-2013 21:47:38 GMT')
82 ->withMaxAge(500)
83 ->withPath('/')
84 ->withDomain('.example.com')
85 ->withSecure(true)
86 ->withHttpOnly(true)
87 ],
88 [
89 'lu=Rg3vHJZnehYLjVg7qi3bZjzg; Domain=.example.com; Path=/; Expires=Tue, 15 Jan 2013 21:47:38 GMT; Max-Age=500; Secure; HttpOnly',
90 SetCookie::create('lu')
91 ->withValue('Rg3vHJZnehYLjVg7qi3bZjzg')
92 ->withExpires(1358286458)
93 ->withMaxAge(500)
94 ->withPath('/')
95 ->withDomain('.example.com')
96 ->withSecure(true)
97 ->withHttpOnly(true)
98 ],
99 [
100 'lu=Rg3vHJZnehYLjVg7qi3bZjzg; Domain=.example.com; Path=/; Expires=Tue, 15 Jan 2013 21:47:38 GMT; Max-Age=500; Secure; HttpOnly',
101 SetCookie::create('lu')
102 ->withValue('Rg3vHJZnehYLjVg7qi3bZjzg')
103 ->withExpires(new \DateTime('Tue, 15-Jan-2013 21:47:38 GMT'))
104 ->withMaxAge(500)
105 ->withPath('/')
106 ->withDomain('.example.com')
107 ->withSecure(true)
108 ->withHttpOnly(true)
109 ],
110 ];
111 }
112
113 /**
114 * @test
115 */
116 public function it_expires_cookies()
117 {
118 $setCookie = SetCookie::createExpired('expire_immediately');
119
120 $this->assertLessThan(time(), $setCookie->getExpires());
121 }
122
123 /**
124 * @test
125 */
126 public function it_creates_long_living_cookies()
127 {
128 $setCookie = SetCookie::createRememberedForever('remember_forever');
129
130 $fourYearsFromNow = (new \DateTime('+4 years'))->getTimestamp();
131 $this->assertGreaterThan($fourYearsFromNow, $setCookie->getExpires());
132 }
133 }
0 <?php
1
2 namespace Dflydev\FigCookies;
3
4 class SetCookiesTest extends \PHPUnit_Framework_TestCase
5 {
6 const INTERFACE_PSR_HTTP_MESSAGE_RESPONSE = 'Psr\Http\Message\ResponseInterface';
7
8 /**
9 * @param string[] $setCookieStrings
10 * @param SetCookie[] $expectedSetCookies
11 *
12 * @test
13 * @dataProvider provideSetCookieStringsAndExpectedSetCookiesData
14 */
15 public function it_creates_from_response($setCookieStrings, array $expectedSetCookies)
16 {
17 $response = $this->prophesize(static::INTERFACE_PSR_HTTP_MESSAGE_RESPONSE);
18 $response->getHeader(SetCookies::SET_COOKIE_HEADER)->willReturn($setCookieStrings);
19
20 $setCookies = SetCookies::fromResponse($response->reveal());
21
22 $this->assertEquals($expectedSetCookies, $setCookies->getAll());
23 }
24
25 /**
26 * @param string[] $setCookieStrings
27 * @param SetCookie[] $expectedSetCookies
28 *
29 * @test
30 * @dataProvider provideSetCookieStringsAndExpectedSetCookiesData
31 */
32 public function it_creates_from_set_cookie_strings($setCookieStrings, array $expectedSetCookies)
33 {
34 $setCookies = SetCookies::fromSetCookieStrings($setCookieStrings);
35
36 $this->assertEquals($expectedSetCookies, $setCookies->getAll());
37 }
38
39 /**
40 * @param string[] $setCookieStrings
41 * @param SetCookie[] $expectedSetCookies
42 *
43 * @test
44 * @dataProvider provideSetCookieStringsAndExpectedSetCookiesData
45 */
46 public function it_knows_which_set_cookies_are_available($setCookieStrings, array $expectedSetCookies)
47 {
48 $setCookies = SetCookies::fromSetCookieStrings($setCookieStrings);
49
50 foreach ($expectedSetCookies as $expectedSetCookie) {
51 $this->assertTrue($setCookies->has($expectedSetCookie->getName()));
52 }
53
54 $this->assertFalse($setCookies->has('i know this cookie does not exist'));
55 }
56
57 /**
58 * @test
59 * @dataProvider provideGetsSetCookieByNameData
60 */
61 public function it_gets_set_cookie_by_name($setCookieStrings, $setCookieName, SetCookie $expectedSetCookie = null)
62 {
63 $setCookies = SetCookies::fromSetCookieStrings($setCookieStrings);
64
65 $this->assertEquals($expectedSetCookie, $setCookies->get($setCookieName));
66 }
67
68 /**
69 * @test
70 */
71 public function it_renders_added_and_removed_set_cookies_header()
72 {
73 $setCookies = SetCookies::fromSetCookieStrings(['theme=light', 'sessionToken=abc123', 'hello=world'])
74 ->with(SetCookie::create('theme', 'blue'))
75 ->without('sessionToken')
76 ->with(SetCookie::create('who', 'me'))
77 ;
78
79 $originalResponse = new FigCookieTestingResponse();
80 $response = $setCookies->renderIntoSetCookieHeader($originalResponse);
81
82 $this->assertNotEquals($response, $originalResponse);
83
84 $this->assertEquals(
85 ['theme=blue', 'hello=world', 'who=me'],
86 $response->getHeader(SetCookies::SET_COOKIE_HEADER)
87 );
88 }
89
90 /**
91 * @test
92 */
93 public function it_gets_and_updates_set_cookie_value_on_request()
94 {
95 //
96 // Example of naive cookie encryption middleware.
97 //
98 // Shows how to access and manipulate cookies using PSR-7 Response
99 // instances from outside the Response object itself.
100 //
101
102 // Simulate a response coming in with several cookies.
103 $response = (new FigCookieTestingResponse())
104 ->withAddedHeader(SetCookies::SET_COOKIE_HEADER, 'theme=light')
105 ->withAddedHeader(SetCookies::SET_COOKIE_HEADER, 'sessionToken=ENCRYPTED')
106 ->withAddedHeader(SetCookies::SET_COOKIE_HEADER, 'hello=world')
107 ;
108
109 // Get our set cookies from the response.
110 $setCookies = SetCookies::fromResponse($response);
111
112 // Ask for the encrypted session token.
113 $decryptedSessionToken = $setCookies->get('sessionToken');
114
115 // Get the encrypted value from the cookie and decrypt it.
116 $decryptedValue = $decryptedSessionToken->getValue();
117 $encryptedValue = str_rot13($decryptedValue);
118
119 // Create a new set cookie with the encrypted value.
120 $encryptedSessionToken = $decryptedSessionToken->withValue($encryptedValue);
121
122 // Include our encrypted session token with the rest of our cookies.
123 $setCookies = $setCookies->with($encryptedSessionToken);
124
125 // Render our cookies, along with the newly decrypted session token, into a response.
126 $response = $setCookies->renderIntoSetCookieHeader($response);
127
128 // From this point on, any response based on this one can get the encrypted version
129 // of the session token.
130 $this->assertEquals(
131 ['theme=light', 'sessionToken=RAPELCGRQ', 'hello=world'],
132 $response->getHeader(SetCookies::SET_COOKIE_HEADER)
133 );
134 }
135
136 public function provideSetCookieStringsAndExpectedSetCookiesData()
137 {
138 return [
139 [
140 [],
141 [],
142 ],
143 [
144 [
145 'someCookie=',
146 ],
147 [
148 SetCookie::create('someCookie'),
149 ],
150 ],
151 [
152 [
153 'someCookie=someValue',
154 'LSID=DQAAAK%2FEaem_vYg; Path=/accounts; Expires=Wed, 13 Jan 2021 22:23:01 GMT; Secure; HttpOnly',
155 ],
156 [
157 SetCookie::create('someCookie', 'someValue'),
158 SetCookie::create('LSID')
159 ->withValue('DQAAAK/Eaem_vYg')
160 ->withPath('/accounts')
161 ->withExpires('Wed, 13 Jan 2021 22:23:01 GMT')
162 ->withSecure(true)
163 ->withHttpOnly(true),
164 ],
165 ],
166 [
167 [
168 'a=AAA',
169 'b=BBB',
170 'c=CCC',
171 ],
172 [
173 SetCookie::create('a', 'AAA'),
174 SetCookie::create('b', 'BBB'),
175 SetCookie::create('c', 'CCC'),
176 ],
177 ],
178 ];
179 }
180
181 public function provideGetsSetCookieByNameData()
182 {
183 return [
184 [
185 [
186 'a=AAA',
187 'b=BBB',
188 'c=CCC',
189 ],
190 'b',
191 SetCookie::create('b', 'BBB'),
192 ],
193 [
194 [
195 'a=AAA',
196 'b=BBB',
197 'c=CCC',
198 'LSID=DQAAAK%2FEaem_vYg; Path=/accounts; Expires=Wed, 13 Jan 2021 22:23:01 GMT; Secure; HttpOnly',
199 ],
200 'LSID',
201 SetCookie::create('LSID')
202 ->withValue('DQAAAK/Eaem_vYg')
203 ->withPath('/accounts')
204 ->withExpires('Wed, 13 Jan 2021 22:23:01 GMT')
205 ->withSecure(true)
206 ->withHttpOnly(true),
207 ],
208 [
209 [
210 'a=AAA',
211 'b=BBB',
212 'c=CCC',
213 ],
214 'LSID',
215 null,
216 ],
217 ];
218 }
219 }