├── .coveralls.yml ├── .github └── workflows │ └── test.yml ├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── LICENSE ├── README.md ├── bin └── register_secure_session.php ├── composer.json ├── composer.lock ├── phpunit.xml.dist ├── src ├── Exception │ └── AuthenticationFailedException.php └── SecureHandler.php └── test ├── SecureHandlerTest.php ├── autoload.php └── demo └── index.php /.coveralls.yml: -------------------------------------------------------------------------------- 1 | coverage_clover: clover.xml 2 | json_path: coveralls-upload.json 3 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | build: 11 | 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v2 16 | 17 | - name: Validate composer.json and composer.lock 18 | run: composer validate 19 | 20 | - name: Cache Composer packages 21 | id: composer-cache 22 | uses: actions/cache@v2 23 | with: 24 | path: vendor 25 | key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }} 26 | restore-keys: | 27 | ${{ runner.os }}-php- 28 | 29 | - name: Install dependencies 30 | if: steps.composer-cache.outputs.cache-hit != 'true' 31 | run: composer install --prefer-dist --no-progress --no-suggest 32 | 33 | # Add a test script to composer.json, for instance: "test": "vendor/bin/phpunit" 34 | # Docs: https://getcomposer.org/doc/articles/scripts.md 35 | 36 | # - name: Run test suite 37 | # run: composer run-script test 38 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | vendor 2 | clover.xml 3 | coveralls-upload.json 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | 3 | language: php 4 | 5 | branches: 6 | except: 7 | - /^release-.*$/ 8 | - /^ghgfk-.*$/ 9 | 10 | cache: 11 | directories: 12 | - $HOME/.composer/cache 13 | - $HOME/.local 14 | - vendor 15 | 16 | matrix: 17 | fast_finish: true 18 | include: 19 | - php: 5.6 20 | env: 21 | - EXECUTE_TEST_COVERALLS=true 22 | - php: 7 23 | - php: 7.1 24 | - php: 7.2 25 | - php: hhvm 26 | allow_failures: 27 | - php: hhvm 28 | 29 | before_install: 30 | - if [[ $EXECUTE_TEST_COVERALLS != 'true' ]]; then phpenv config-rm xdebug.ini || return 0 ; fi 31 | - travis_retry composer self-update 32 | - if [[ $EXECUTE_TEST_COVERALLS == 'true' ]]; then composer require --dev --no-update satooshi/php-coveralls ; fi 33 | 34 | install: 35 | - travis_retry composer install --no-interaction 36 | 37 | script: 38 | - if [[ $EXECUTE_TEST_COVERALLS == 'true' ]]; then composer test-coverage ; fi 39 | - if [[ $EXECUTE_TEST_COVERALLS != 'true' ]]; then composer test ; fi 40 | 41 | after_script: 42 | - if [[ $EXECUTE_TEST_COVERALLS == 'true' ]]; then ./vendor/bin/coveralls -v; fi 43 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file, in reverse chronological order by release. 4 | 5 | ## 1.1.0 - 2018-02-01 6 | 7 | ### Added 8 | 9 | - [#29](https://github.com/ezimuel/PHP-Secure-Session/issues/29) added the 10 | `PHPSecureSession\Exception\AuthenticationFailedException` in case of 11 | authentication error of `SecureHandler::decrypt()`. 12 | 13 | ### Changed 14 | 15 | - [d39d3aa](https://github.com/ezimuel/PHP-Secure-Session/commit/d39d3aa381ebc9cd98b6de59b34ec7129d43a8fd) 16 | refactored the unit test removing the usage of `@runInSeparateProcess`. 17 | 18 | ### Deprecated 19 | 20 | - Nothing. 21 | 22 | ### Removed 23 | 24 | - Nothing. 25 | 26 | ### Fixed 27 | 28 | - Nothing. 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Enrico Zimuel 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PHP-Secure-Session 2 | 3 | [![Build Status](https://secure.travis-ci.org/ezimuel/PHP-Secure-Session.svg?branch=master)](https://secure.travis-ci.org/ezimuel/PHP-Secure-Session) 4 | [![Coverage Status](https://coveralls.io/repos/github/ezimuel/PHP-Secure-Session/badge.svg?branch=master)](https://coveralls.io/github/ezimuel/PHP-Secure-Session?branch=master) 5 | 6 | ## About 7 | 8 | This project adds encryption to internal PHP save handlers. 9 | It uses [OpenSSL](http://php.net/manual/en/book.openssl.php) extension to 10 | provide encryption with [AES-256](http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf) 11 | and authentication using HMAC-SHA-256. 12 | 13 | The [SecureHandler](src/SecureHandler.php) class extends the default 14 | [SessionHandler](http://php.net/manual/en/class.sessionhandler.php) of PHP and 15 | it adds only an encryption layer on the internal save handler. 16 | The session management logic remains the same, that means you can use 17 | `SecureSession` with all the PHP session handlers like 'file', 'sqlite', 18 | 'memcache' or 'memcached' which are provided by PHP extensions. 19 | 20 | ## Installation 21 | 22 | You can install this library using [composer](https://getcomposer.org/) with the 23 | following command: 24 | 25 | ``` 26 | composer require ezimuel/php-secure-session 27 | ``` 28 | 29 | After that the PHP-Secure-Session handler will be automatically executed in your 30 | project when consuming the `vendor/autoload.php` file. 31 | 32 | ## Usage 33 | 34 | You don't have to do nothing to consume this library, the [SecureHandler](src/SecureHandler.php) 35 | is automatically registered with [session_set_save_handler()](http://php.net/manual/en/function.session-set-save-handler.php) 36 | during the composer autoload. 37 | 38 | ## How it works 39 | 40 | The session data are encrypted using a **random key** stored in a cookie variable 41 | starting with the prefix `KEY_`. 42 | 43 | This random key is generated using the [random_bytes()](http://php.net/manual/en/function.random-bytes.php) 44 | function of PHP 7. For PHP 5 versions we used the [paragonie/random_compat](https://github.com/paragonie/random_compat) 45 | project that is a polyfill for `random_bytes()`. 46 | 47 | We also generated a random authentication key stored in the same cookie variable. 48 | The value stored in the `KEY_` cookie is the [Base64](https://en.wikipedia.org/wiki/Base64) 49 | representation of the encryption key concatenated with the authentication key. 50 | 51 | ## Demo 52 | 53 | You can test the PHP-Secure-Session using the [test/demo/index.php](test/demo/index.php) 54 | example. You can run the demo using the internal web server of PHP with the 55 | following command: 56 | 57 | ``` 58 | php -S 0.0.0.0:8000 -t test/demo 59 | ``` 60 | 61 | If you open the browser to [localhost:8000](http://localhost:8000) you will see 62 | the demo in action. 63 | 64 | 65 | --- 66 | 67 | Copyright 2011-2018 by [Enrico Zimuel](http://www.zimuel.it) 68 | 69 | Released under the [MIT License](LICENSE) 70 | -------------------------------------------------------------------------------- /bin/register_secure_session.php: -------------------------------------------------------------------------------- 1 | =5.2.0" 25 | }, 26 | "require-dev": { 27 | "phpunit/phpunit": "4.*|5.*" 28 | }, 29 | "suggest": { 30 | "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes." 31 | }, 32 | "type": "library", 33 | "autoload": { 34 | "files": [ 35 | "lib/random.php" 36 | ] 37 | }, 38 | "notification-url": "https://packagist.org/downloads/", 39 | "license": [ 40 | "MIT" 41 | ], 42 | "authors": [ 43 | { 44 | "name": "Paragon Initiative Enterprises", 45 | "email": "security@paragonie.com", 46 | "homepage": "https://paragonie.com" 47 | } 48 | ], 49 | "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7", 50 | "keywords": [ 51 | "csprng", 52 | "pseudorandom", 53 | "random" 54 | ], 55 | "time": "2017-09-27T21:40:39+00:00" 56 | } 57 | ], 58 | "packages-dev": [ 59 | { 60 | "name": "doctrine/instantiator", 61 | "version": "1.0.5", 62 | "source": { 63 | "type": "git", 64 | "url": "https://github.com/doctrine/instantiator.git", 65 | "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d" 66 | }, 67 | "dist": { 68 | "type": "zip", 69 | "url": "https://api.github.com/repos/doctrine/instantiator/zipball/8e884e78f9f0eb1329e445619e04456e64d8051d", 70 | "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d", 71 | "shasum": "" 72 | }, 73 | "require": { 74 | "php": ">=5.3,<8.0-DEV" 75 | }, 76 | "require-dev": { 77 | "athletic/athletic": "~0.1.8", 78 | "ext-pdo": "*", 79 | "ext-phar": "*", 80 | "phpunit/phpunit": "~4.0", 81 | "squizlabs/php_codesniffer": "~2.0" 82 | }, 83 | "type": "library", 84 | "extra": { 85 | "branch-alias": { 86 | "dev-master": "1.0.x-dev" 87 | } 88 | }, 89 | "autoload": { 90 | "psr-4": { 91 | "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" 92 | } 93 | }, 94 | "notification-url": "https://packagist.org/downloads/", 95 | "license": [ 96 | "MIT" 97 | ], 98 | "authors": [ 99 | { 100 | "name": "Marco Pivetta", 101 | "email": "ocramius@gmail.com", 102 | "homepage": "http://ocramius.github.com/" 103 | } 104 | ], 105 | "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", 106 | "homepage": "https://github.com/doctrine/instantiator", 107 | "keywords": [ 108 | "constructor", 109 | "instantiate" 110 | ], 111 | "time": "2015-06-14T21:17:01+00:00" 112 | }, 113 | { 114 | "name": "myclabs/deep-copy", 115 | "version": "1.7.0", 116 | "source": { 117 | "type": "git", 118 | "url": "https://github.com/myclabs/DeepCopy.git", 119 | "reference": "3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e" 120 | }, 121 | "dist": { 122 | "type": "zip", 123 | "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e", 124 | "reference": "3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e", 125 | "shasum": "" 126 | }, 127 | "require": { 128 | "php": "^5.6 || ^7.0" 129 | }, 130 | "require-dev": { 131 | "doctrine/collections": "^1.0", 132 | "doctrine/common": "^2.6", 133 | "phpunit/phpunit": "^4.1" 134 | }, 135 | "type": "library", 136 | "autoload": { 137 | "psr-4": { 138 | "DeepCopy\\": "src/DeepCopy/" 139 | }, 140 | "files": [ 141 | "src/DeepCopy/deep_copy.php" 142 | ] 143 | }, 144 | "notification-url": "https://packagist.org/downloads/", 145 | "license": [ 146 | "MIT" 147 | ], 148 | "description": "Create deep copies (clones) of your objects", 149 | "keywords": [ 150 | "clone", 151 | "copy", 152 | "duplicate", 153 | "object", 154 | "object graph" 155 | ], 156 | "time": "2017-10-19T19:58:43+00:00" 157 | }, 158 | { 159 | "name": "phpdocumentor/reflection-common", 160 | "version": "1.0.1", 161 | "source": { 162 | "type": "git", 163 | "url": "https://github.com/phpDocumentor/ReflectionCommon.git", 164 | "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6" 165 | }, 166 | "dist": { 167 | "type": "zip", 168 | "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6", 169 | "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6", 170 | "shasum": "" 171 | }, 172 | "require": { 173 | "php": ">=5.5" 174 | }, 175 | "require-dev": { 176 | "phpunit/phpunit": "^4.6" 177 | }, 178 | "type": "library", 179 | "extra": { 180 | "branch-alias": { 181 | "dev-master": "1.0.x-dev" 182 | } 183 | }, 184 | "autoload": { 185 | "psr-4": { 186 | "phpDocumentor\\Reflection\\": [ 187 | "src" 188 | ] 189 | } 190 | }, 191 | "notification-url": "https://packagist.org/downloads/", 192 | "license": [ 193 | "MIT" 194 | ], 195 | "authors": [ 196 | { 197 | "name": "Jaap van Otterdijk", 198 | "email": "opensource@ijaap.nl" 199 | } 200 | ], 201 | "description": "Common reflection classes used by phpdocumentor to reflect the code structure", 202 | "homepage": "http://www.phpdoc.org", 203 | "keywords": [ 204 | "FQSEN", 205 | "phpDocumentor", 206 | "phpdoc", 207 | "reflection", 208 | "static analysis" 209 | ], 210 | "time": "2017-09-11T18:02:19+00:00" 211 | }, 212 | { 213 | "name": "phpdocumentor/reflection-docblock", 214 | "version": "3.3.2", 215 | "source": { 216 | "type": "git", 217 | "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", 218 | "reference": "bf329f6c1aadea3299f08ee804682b7c45b326a2" 219 | }, 220 | "dist": { 221 | "type": "zip", 222 | "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/bf329f6c1aadea3299f08ee804682b7c45b326a2", 223 | "reference": "bf329f6c1aadea3299f08ee804682b7c45b326a2", 224 | "shasum": "" 225 | }, 226 | "require": { 227 | "php": "^5.6 || ^7.0", 228 | "phpdocumentor/reflection-common": "^1.0.0", 229 | "phpdocumentor/type-resolver": "^0.4.0", 230 | "webmozart/assert": "^1.0" 231 | }, 232 | "require-dev": { 233 | "mockery/mockery": "^0.9.4", 234 | "phpunit/phpunit": "^4.4" 235 | }, 236 | "type": "library", 237 | "autoload": { 238 | "psr-4": { 239 | "phpDocumentor\\Reflection\\": [ 240 | "src/" 241 | ] 242 | } 243 | }, 244 | "notification-url": "https://packagist.org/downloads/", 245 | "license": [ 246 | "MIT" 247 | ], 248 | "authors": [ 249 | { 250 | "name": "Mike van Riel", 251 | "email": "me@mikevanriel.com" 252 | } 253 | ], 254 | "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", 255 | "time": "2017-11-10T14:09:06+00:00" 256 | }, 257 | { 258 | "name": "phpdocumentor/type-resolver", 259 | "version": "0.4.0", 260 | "source": { 261 | "type": "git", 262 | "url": "https://github.com/phpDocumentor/TypeResolver.git", 263 | "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7" 264 | }, 265 | "dist": { 266 | "type": "zip", 267 | "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/9c977708995954784726e25d0cd1dddf4e65b0f7", 268 | "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7", 269 | "shasum": "" 270 | }, 271 | "require": { 272 | "php": "^5.5 || ^7.0", 273 | "phpdocumentor/reflection-common": "^1.0" 274 | }, 275 | "require-dev": { 276 | "mockery/mockery": "^0.9.4", 277 | "phpunit/phpunit": "^5.2||^4.8.24" 278 | }, 279 | "type": "library", 280 | "extra": { 281 | "branch-alias": { 282 | "dev-master": "1.0.x-dev" 283 | } 284 | }, 285 | "autoload": { 286 | "psr-4": { 287 | "phpDocumentor\\Reflection\\": [ 288 | "src/" 289 | ] 290 | } 291 | }, 292 | "notification-url": "https://packagist.org/downloads/", 293 | "license": [ 294 | "MIT" 295 | ], 296 | "authors": [ 297 | { 298 | "name": "Mike van Riel", 299 | "email": "me@mikevanriel.com" 300 | } 301 | ], 302 | "time": "2017-07-14T14:27:02+00:00" 303 | }, 304 | { 305 | "name": "phpspec/prophecy", 306 | "version": "1.7.3", 307 | "source": { 308 | "type": "git", 309 | "url": "https://github.com/phpspec/prophecy.git", 310 | "reference": "e4ed002c67da8eceb0eb8ddb8b3847bb53c5c2bf" 311 | }, 312 | "dist": { 313 | "type": "zip", 314 | "url": "https://api.github.com/repos/phpspec/prophecy/zipball/e4ed002c67da8eceb0eb8ddb8b3847bb53c5c2bf", 315 | "reference": "e4ed002c67da8eceb0eb8ddb8b3847bb53c5c2bf", 316 | "shasum": "" 317 | }, 318 | "require": { 319 | "doctrine/instantiator": "^1.0.2", 320 | "php": "^5.3|^7.0", 321 | "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0", 322 | "sebastian/comparator": "^1.1|^2.0", 323 | "sebastian/recursion-context": "^1.0|^2.0|^3.0" 324 | }, 325 | "require-dev": { 326 | "phpspec/phpspec": "^2.5|^3.2", 327 | "phpunit/phpunit": "^4.8.35 || ^5.7" 328 | }, 329 | "type": "library", 330 | "extra": { 331 | "branch-alias": { 332 | "dev-master": "1.7.x-dev" 333 | } 334 | }, 335 | "autoload": { 336 | "psr-0": { 337 | "Prophecy\\": "src/" 338 | } 339 | }, 340 | "notification-url": "https://packagist.org/downloads/", 341 | "license": [ 342 | "MIT" 343 | ], 344 | "authors": [ 345 | { 346 | "name": "Konstantin Kudryashov", 347 | "email": "ever.zet@gmail.com", 348 | "homepage": "http://everzet.com" 349 | }, 350 | { 351 | "name": "Marcello Duarte", 352 | "email": "marcello.duarte@gmail.com" 353 | } 354 | ], 355 | "description": "Highly opinionated mocking framework for PHP 5.3+", 356 | "homepage": "https://github.com/phpspec/prophecy", 357 | "keywords": [ 358 | "Double", 359 | "Dummy", 360 | "fake", 361 | "mock", 362 | "spy", 363 | "stub" 364 | ], 365 | "time": "2017-11-24T13:59:53+00:00" 366 | }, 367 | { 368 | "name": "phpunit/php-code-coverage", 369 | "version": "4.0.8", 370 | "source": { 371 | "type": "git", 372 | "url": "https://github.com/sebastianbergmann/php-code-coverage.git", 373 | "reference": "ef7b2f56815df854e66ceaee8ebe9393ae36a40d" 374 | }, 375 | "dist": { 376 | "type": "zip", 377 | "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/ef7b2f56815df854e66ceaee8ebe9393ae36a40d", 378 | "reference": "ef7b2f56815df854e66ceaee8ebe9393ae36a40d", 379 | "shasum": "" 380 | }, 381 | "require": { 382 | "ext-dom": "*", 383 | "ext-xmlwriter": "*", 384 | "php": "^5.6 || ^7.0", 385 | "phpunit/php-file-iterator": "^1.3", 386 | "phpunit/php-text-template": "^1.2", 387 | "phpunit/php-token-stream": "^1.4.2 || ^2.0", 388 | "sebastian/code-unit-reverse-lookup": "^1.0", 389 | "sebastian/environment": "^1.3.2 || ^2.0", 390 | "sebastian/version": "^1.0 || ^2.0" 391 | }, 392 | "require-dev": { 393 | "ext-xdebug": "^2.1.4", 394 | "phpunit/phpunit": "^5.7" 395 | }, 396 | "suggest": { 397 | "ext-xdebug": "^2.5.1" 398 | }, 399 | "type": "library", 400 | "extra": { 401 | "branch-alias": { 402 | "dev-master": "4.0.x-dev" 403 | } 404 | }, 405 | "autoload": { 406 | "classmap": [ 407 | "src/" 408 | ] 409 | }, 410 | "notification-url": "https://packagist.org/downloads/", 411 | "license": [ 412 | "BSD-3-Clause" 413 | ], 414 | "authors": [ 415 | { 416 | "name": "Sebastian Bergmann", 417 | "email": "sb@sebastian-bergmann.de", 418 | "role": "lead" 419 | } 420 | ], 421 | "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", 422 | "homepage": "https://github.com/sebastianbergmann/php-code-coverage", 423 | "keywords": [ 424 | "coverage", 425 | "testing", 426 | "xunit" 427 | ], 428 | "time": "2017-04-02T07:44:40+00:00" 429 | }, 430 | { 431 | "name": "phpunit/php-file-iterator", 432 | "version": "1.4.5", 433 | "source": { 434 | "type": "git", 435 | "url": "https://github.com/sebastianbergmann/php-file-iterator.git", 436 | "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4" 437 | }, 438 | "dist": { 439 | "type": "zip", 440 | "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/730b01bc3e867237eaac355e06a36b85dd93a8b4", 441 | "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4", 442 | "shasum": "" 443 | }, 444 | "require": { 445 | "php": ">=5.3.3" 446 | }, 447 | "type": "library", 448 | "extra": { 449 | "branch-alias": { 450 | "dev-master": "1.4.x-dev" 451 | } 452 | }, 453 | "autoload": { 454 | "classmap": [ 455 | "src/" 456 | ] 457 | }, 458 | "notification-url": "https://packagist.org/downloads/", 459 | "license": [ 460 | "BSD-3-Clause" 461 | ], 462 | "authors": [ 463 | { 464 | "name": "Sebastian Bergmann", 465 | "email": "sb@sebastian-bergmann.de", 466 | "role": "lead" 467 | } 468 | ], 469 | "description": "FilterIterator implementation that filters files based on a list of suffixes.", 470 | "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", 471 | "keywords": [ 472 | "filesystem", 473 | "iterator" 474 | ], 475 | "time": "2017-11-27T13:52:08+00:00" 476 | }, 477 | { 478 | "name": "phpunit/php-text-template", 479 | "version": "1.2.1", 480 | "source": { 481 | "type": "git", 482 | "url": "https://github.com/sebastianbergmann/php-text-template.git", 483 | "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" 484 | }, 485 | "dist": { 486 | "type": "zip", 487 | "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", 488 | "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", 489 | "shasum": "" 490 | }, 491 | "require": { 492 | "php": ">=5.3.3" 493 | }, 494 | "type": "library", 495 | "autoload": { 496 | "classmap": [ 497 | "src/" 498 | ] 499 | }, 500 | "notification-url": "https://packagist.org/downloads/", 501 | "license": [ 502 | "BSD-3-Clause" 503 | ], 504 | "authors": [ 505 | { 506 | "name": "Sebastian Bergmann", 507 | "email": "sebastian@phpunit.de", 508 | "role": "lead" 509 | } 510 | ], 511 | "description": "Simple template engine.", 512 | "homepage": "https://github.com/sebastianbergmann/php-text-template/", 513 | "keywords": [ 514 | "template" 515 | ], 516 | "time": "2015-06-21T13:50:34+00:00" 517 | }, 518 | { 519 | "name": "phpunit/php-timer", 520 | "version": "1.0.9", 521 | "source": { 522 | "type": "git", 523 | "url": "https://github.com/sebastianbergmann/php-timer.git", 524 | "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f" 525 | }, 526 | "dist": { 527 | "type": "zip", 528 | "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", 529 | "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", 530 | "shasum": "" 531 | }, 532 | "require": { 533 | "php": "^5.3.3 || ^7.0" 534 | }, 535 | "require-dev": { 536 | "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" 537 | }, 538 | "type": "library", 539 | "extra": { 540 | "branch-alias": { 541 | "dev-master": "1.0-dev" 542 | } 543 | }, 544 | "autoload": { 545 | "classmap": [ 546 | "src/" 547 | ] 548 | }, 549 | "notification-url": "https://packagist.org/downloads/", 550 | "license": [ 551 | "BSD-3-Clause" 552 | ], 553 | "authors": [ 554 | { 555 | "name": "Sebastian Bergmann", 556 | "email": "sb@sebastian-bergmann.de", 557 | "role": "lead" 558 | } 559 | ], 560 | "description": "Utility class for timing", 561 | "homepage": "https://github.com/sebastianbergmann/php-timer/", 562 | "keywords": [ 563 | "timer" 564 | ], 565 | "time": "2017-02-26T11:10:40+00:00" 566 | }, 567 | { 568 | "name": "phpunit/php-token-stream", 569 | "version": "1.4.12", 570 | "source": { 571 | "type": "git", 572 | "url": "https://github.com/sebastianbergmann/php-token-stream.git", 573 | "reference": "1ce90ba27c42e4e44e6d8458241466380b51fa16" 574 | }, 575 | "dist": { 576 | "type": "zip", 577 | "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/1ce90ba27c42e4e44e6d8458241466380b51fa16", 578 | "reference": "1ce90ba27c42e4e44e6d8458241466380b51fa16", 579 | "shasum": "" 580 | }, 581 | "require": { 582 | "ext-tokenizer": "*", 583 | "php": ">=5.3.3" 584 | }, 585 | "require-dev": { 586 | "phpunit/phpunit": "~4.2" 587 | }, 588 | "type": "library", 589 | "extra": { 590 | "branch-alias": { 591 | "dev-master": "1.4-dev" 592 | } 593 | }, 594 | "autoload": { 595 | "classmap": [ 596 | "src/" 597 | ] 598 | }, 599 | "notification-url": "https://packagist.org/downloads/", 600 | "license": [ 601 | "BSD-3-Clause" 602 | ], 603 | "authors": [ 604 | { 605 | "name": "Sebastian Bergmann", 606 | "email": "sebastian@phpunit.de" 607 | } 608 | ], 609 | "description": "Wrapper around PHP's tokenizer extension.", 610 | "homepage": "https://github.com/sebastianbergmann/php-token-stream/", 611 | "keywords": [ 612 | "tokenizer" 613 | ], 614 | "time": "2017-12-04T08:55:13+00:00" 615 | }, 616 | { 617 | "name": "phpunit/phpunit", 618 | "version": "5.7.27", 619 | "source": { 620 | "type": "git", 621 | "url": "https://github.com/sebastianbergmann/phpunit.git", 622 | "reference": "b7803aeca3ccb99ad0a506fa80b64cd6a56bbc0c" 623 | }, 624 | "dist": { 625 | "type": "zip", 626 | "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/b7803aeca3ccb99ad0a506fa80b64cd6a56bbc0c", 627 | "reference": "b7803aeca3ccb99ad0a506fa80b64cd6a56bbc0c", 628 | "shasum": "" 629 | }, 630 | "require": { 631 | "ext-dom": "*", 632 | "ext-json": "*", 633 | "ext-libxml": "*", 634 | "ext-mbstring": "*", 635 | "ext-xml": "*", 636 | "myclabs/deep-copy": "~1.3", 637 | "php": "^5.6 || ^7.0", 638 | "phpspec/prophecy": "^1.6.2", 639 | "phpunit/php-code-coverage": "^4.0.4", 640 | "phpunit/php-file-iterator": "~1.4", 641 | "phpunit/php-text-template": "~1.2", 642 | "phpunit/php-timer": "^1.0.6", 643 | "phpunit/phpunit-mock-objects": "^3.2", 644 | "sebastian/comparator": "^1.2.4", 645 | "sebastian/diff": "^1.4.3", 646 | "sebastian/environment": "^1.3.4 || ^2.0", 647 | "sebastian/exporter": "~2.0", 648 | "sebastian/global-state": "^1.1", 649 | "sebastian/object-enumerator": "~2.0", 650 | "sebastian/resource-operations": "~1.0", 651 | "sebastian/version": "^1.0.6|^2.0.1", 652 | "symfony/yaml": "~2.1|~3.0|~4.0" 653 | }, 654 | "conflict": { 655 | "phpdocumentor/reflection-docblock": "3.0.2" 656 | }, 657 | "require-dev": { 658 | "ext-pdo": "*" 659 | }, 660 | "suggest": { 661 | "ext-xdebug": "*", 662 | "phpunit/php-invoker": "~1.1" 663 | }, 664 | "bin": [ 665 | "phpunit" 666 | ], 667 | "type": "library", 668 | "extra": { 669 | "branch-alias": { 670 | "dev-master": "5.7.x-dev" 671 | } 672 | }, 673 | "autoload": { 674 | "classmap": [ 675 | "src/" 676 | ] 677 | }, 678 | "notification-url": "https://packagist.org/downloads/", 679 | "license": [ 680 | "BSD-3-Clause" 681 | ], 682 | "authors": [ 683 | { 684 | "name": "Sebastian Bergmann", 685 | "email": "sebastian@phpunit.de", 686 | "role": "lead" 687 | } 688 | ], 689 | "description": "The PHP Unit Testing framework.", 690 | "homepage": "https://phpunit.de/", 691 | "keywords": [ 692 | "phpunit", 693 | "testing", 694 | "xunit" 695 | ], 696 | "time": "2018-02-01T05:50:59+00:00" 697 | }, 698 | { 699 | "name": "phpunit/phpunit-mock-objects", 700 | "version": "3.4.4", 701 | "source": { 702 | "type": "git", 703 | "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", 704 | "reference": "a23b761686d50a560cc56233b9ecf49597cc9118" 705 | }, 706 | "dist": { 707 | "type": "zip", 708 | "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/a23b761686d50a560cc56233b9ecf49597cc9118", 709 | "reference": "a23b761686d50a560cc56233b9ecf49597cc9118", 710 | "shasum": "" 711 | }, 712 | "require": { 713 | "doctrine/instantiator": "^1.0.2", 714 | "php": "^5.6 || ^7.0", 715 | "phpunit/php-text-template": "^1.2", 716 | "sebastian/exporter": "^1.2 || ^2.0" 717 | }, 718 | "conflict": { 719 | "phpunit/phpunit": "<5.4.0" 720 | }, 721 | "require-dev": { 722 | "phpunit/phpunit": "^5.4" 723 | }, 724 | "suggest": { 725 | "ext-soap": "*" 726 | }, 727 | "type": "library", 728 | "extra": { 729 | "branch-alias": { 730 | "dev-master": "3.2.x-dev" 731 | } 732 | }, 733 | "autoload": { 734 | "classmap": [ 735 | "src/" 736 | ] 737 | }, 738 | "notification-url": "https://packagist.org/downloads/", 739 | "license": [ 740 | "BSD-3-Clause" 741 | ], 742 | "authors": [ 743 | { 744 | "name": "Sebastian Bergmann", 745 | "email": "sb@sebastian-bergmann.de", 746 | "role": "lead" 747 | } 748 | ], 749 | "description": "Mock Object library for PHPUnit", 750 | "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", 751 | "keywords": [ 752 | "mock", 753 | "xunit" 754 | ], 755 | "time": "2017-06-30T09:13:00+00:00" 756 | }, 757 | { 758 | "name": "sebastian/code-unit-reverse-lookup", 759 | "version": "1.0.1", 760 | "source": { 761 | "type": "git", 762 | "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", 763 | "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18" 764 | }, 765 | "dist": { 766 | "type": "zip", 767 | "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/4419fcdb5eabb9caa61a27c7a1db532a6b55dd18", 768 | "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18", 769 | "shasum": "" 770 | }, 771 | "require": { 772 | "php": "^5.6 || ^7.0" 773 | }, 774 | "require-dev": { 775 | "phpunit/phpunit": "^5.7 || ^6.0" 776 | }, 777 | "type": "library", 778 | "extra": { 779 | "branch-alias": { 780 | "dev-master": "1.0.x-dev" 781 | } 782 | }, 783 | "autoload": { 784 | "classmap": [ 785 | "src/" 786 | ] 787 | }, 788 | "notification-url": "https://packagist.org/downloads/", 789 | "license": [ 790 | "BSD-3-Clause" 791 | ], 792 | "authors": [ 793 | { 794 | "name": "Sebastian Bergmann", 795 | "email": "sebastian@phpunit.de" 796 | } 797 | ], 798 | "description": "Looks up which function or method a line of code belongs to", 799 | "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", 800 | "time": "2017-03-04T06:30:41+00:00" 801 | }, 802 | { 803 | "name": "sebastian/comparator", 804 | "version": "1.2.4", 805 | "source": { 806 | "type": "git", 807 | "url": "https://github.com/sebastianbergmann/comparator.git", 808 | "reference": "2b7424b55f5047b47ac6e5ccb20b2aea4011d9be" 809 | }, 810 | "dist": { 811 | "type": "zip", 812 | "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/2b7424b55f5047b47ac6e5ccb20b2aea4011d9be", 813 | "reference": "2b7424b55f5047b47ac6e5ccb20b2aea4011d9be", 814 | "shasum": "" 815 | }, 816 | "require": { 817 | "php": ">=5.3.3", 818 | "sebastian/diff": "~1.2", 819 | "sebastian/exporter": "~1.2 || ~2.0" 820 | }, 821 | "require-dev": { 822 | "phpunit/phpunit": "~4.4" 823 | }, 824 | "type": "library", 825 | "extra": { 826 | "branch-alias": { 827 | "dev-master": "1.2.x-dev" 828 | } 829 | }, 830 | "autoload": { 831 | "classmap": [ 832 | "src/" 833 | ] 834 | }, 835 | "notification-url": "https://packagist.org/downloads/", 836 | "license": [ 837 | "BSD-3-Clause" 838 | ], 839 | "authors": [ 840 | { 841 | "name": "Jeff Welch", 842 | "email": "whatthejeff@gmail.com" 843 | }, 844 | { 845 | "name": "Volker Dusch", 846 | "email": "github@wallbash.com" 847 | }, 848 | { 849 | "name": "Bernhard Schussek", 850 | "email": "bschussek@2bepublished.at" 851 | }, 852 | { 853 | "name": "Sebastian Bergmann", 854 | "email": "sebastian@phpunit.de" 855 | } 856 | ], 857 | "description": "Provides the functionality to compare PHP values for equality", 858 | "homepage": "http://www.github.com/sebastianbergmann/comparator", 859 | "keywords": [ 860 | "comparator", 861 | "compare", 862 | "equality" 863 | ], 864 | "time": "2017-01-29T09:50:25+00:00" 865 | }, 866 | { 867 | "name": "sebastian/diff", 868 | "version": "1.4.3", 869 | "source": { 870 | "type": "git", 871 | "url": "https://github.com/sebastianbergmann/diff.git", 872 | "reference": "7f066a26a962dbe58ddea9f72a4e82874a3975a4" 873 | }, 874 | "dist": { 875 | "type": "zip", 876 | "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/7f066a26a962dbe58ddea9f72a4e82874a3975a4", 877 | "reference": "7f066a26a962dbe58ddea9f72a4e82874a3975a4", 878 | "shasum": "" 879 | }, 880 | "require": { 881 | "php": "^5.3.3 || ^7.0" 882 | }, 883 | "require-dev": { 884 | "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" 885 | }, 886 | "type": "library", 887 | "extra": { 888 | "branch-alias": { 889 | "dev-master": "1.4-dev" 890 | } 891 | }, 892 | "autoload": { 893 | "classmap": [ 894 | "src/" 895 | ] 896 | }, 897 | "notification-url": "https://packagist.org/downloads/", 898 | "license": [ 899 | "BSD-3-Clause" 900 | ], 901 | "authors": [ 902 | { 903 | "name": "Kore Nordmann", 904 | "email": "mail@kore-nordmann.de" 905 | }, 906 | { 907 | "name": "Sebastian Bergmann", 908 | "email": "sebastian@phpunit.de" 909 | } 910 | ], 911 | "description": "Diff implementation", 912 | "homepage": "https://github.com/sebastianbergmann/diff", 913 | "keywords": [ 914 | "diff" 915 | ], 916 | "time": "2017-05-22T07:24:03+00:00" 917 | }, 918 | { 919 | "name": "sebastian/environment", 920 | "version": "2.0.0", 921 | "source": { 922 | "type": "git", 923 | "url": "https://github.com/sebastianbergmann/environment.git", 924 | "reference": "5795ffe5dc5b02460c3e34222fee8cbe245d8fac" 925 | }, 926 | "dist": { 927 | "type": "zip", 928 | "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/5795ffe5dc5b02460c3e34222fee8cbe245d8fac", 929 | "reference": "5795ffe5dc5b02460c3e34222fee8cbe245d8fac", 930 | "shasum": "" 931 | }, 932 | "require": { 933 | "php": "^5.6 || ^7.0" 934 | }, 935 | "require-dev": { 936 | "phpunit/phpunit": "^5.0" 937 | }, 938 | "type": "library", 939 | "extra": { 940 | "branch-alias": { 941 | "dev-master": "2.0.x-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": "Sebastian Bergmann", 956 | "email": "sebastian@phpunit.de" 957 | } 958 | ], 959 | "description": "Provides functionality to handle HHVM/PHP environments", 960 | "homepage": "http://www.github.com/sebastianbergmann/environment", 961 | "keywords": [ 962 | "Xdebug", 963 | "environment", 964 | "hhvm" 965 | ], 966 | "time": "2016-11-26T07:53:53+00:00" 967 | }, 968 | { 969 | "name": "sebastian/exporter", 970 | "version": "2.0.0", 971 | "source": { 972 | "type": "git", 973 | "url": "https://github.com/sebastianbergmann/exporter.git", 974 | "reference": "ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4" 975 | }, 976 | "dist": { 977 | "type": "zip", 978 | "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4", 979 | "reference": "ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4", 980 | "shasum": "" 981 | }, 982 | "require": { 983 | "php": ">=5.3.3", 984 | "sebastian/recursion-context": "~2.0" 985 | }, 986 | "require-dev": { 987 | "ext-mbstring": "*", 988 | "phpunit/phpunit": "~4.4" 989 | }, 990 | "type": "library", 991 | "extra": { 992 | "branch-alias": { 993 | "dev-master": "2.0.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": "Jeff Welch", 1008 | "email": "whatthejeff@gmail.com" 1009 | }, 1010 | { 1011 | "name": "Volker Dusch", 1012 | "email": "github@wallbash.com" 1013 | }, 1014 | { 1015 | "name": "Bernhard Schussek", 1016 | "email": "bschussek@2bepublished.at" 1017 | }, 1018 | { 1019 | "name": "Sebastian Bergmann", 1020 | "email": "sebastian@phpunit.de" 1021 | }, 1022 | { 1023 | "name": "Adam Harvey", 1024 | "email": "aharvey@php.net" 1025 | } 1026 | ], 1027 | "description": "Provides the functionality to export PHP variables for visualization", 1028 | "homepage": "http://www.github.com/sebastianbergmann/exporter", 1029 | "keywords": [ 1030 | "export", 1031 | "exporter" 1032 | ], 1033 | "time": "2016-11-19T08:54:04+00:00" 1034 | }, 1035 | { 1036 | "name": "sebastian/global-state", 1037 | "version": "1.1.1", 1038 | "source": { 1039 | "type": "git", 1040 | "url": "https://github.com/sebastianbergmann/global-state.git", 1041 | "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4" 1042 | }, 1043 | "dist": { 1044 | "type": "zip", 1045 | "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bc37d50fea7d017d3d340f230811c9f1d7280af4", 1046 | "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4", 1047 | "shasum": "" 1048 | }, 1049 | "require": { 1050 | "php": ">=5.3.3" 1051 | }, 1052 | "require-dev": { 1053 | "phpunit/phpunit": "~4.2" 1054 | }, 1055 | "suggest": { 1056 | "ext-uopz": "*" 1057 | }, 1058 | "type": "library", 1059 | "extra": { 1060 | "branch-alias": { 1061 | "dev-master": "1.0-dev" 1062 | } 1063 | }, 1064 | "autoload": { 1065 | "classmap": [ 1066 | "src/" 1067 | ] 1068 | }, 1069 | "notification-url": "https://packagist.org/downloads/", 1070 | "license": [ 1071 | "BSD-3-Clause" 1072 | ], 1073 | "authors": [ 1074 | { 1075 | "name": "Sebastian Bergmann", 1076 | "email": "sebastian@phpunit.de" 1077 | } 1078 | ], 1079 | "description": "Snapshotting of global state", 1080 | "homepage": "http://www.github.com/sebastianbergmann/global-state", 1081 | "keywords": [ 1082 | "global state" 1083 | ], 1084 | "time": "2015-10-12T03:26:01+00:00" 1085 | }, 1086 | { 1087 | "name": "sebastian/object-enumerator", 1088 | "version": "2.0.1", 1089 | "source": { 1090 | "type": "git", 1091 | "url": "https://github.com/sebastianbergmann/object-enumerator.git", 1092 | "reference": "1311872ac850040a79c3c058bea3e22d0f09cbb7" 1093 | }, 1094 | "dist": { 1095 | "type": "zip", 1096 | "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/1311872ac850040a79c3c058bea3e22d0f09cbb7", 1097 | "reference": "1311872ac850040a79c3c058bea3e22d0f09cbb7", 1098 | "shasum": "" 1099 | }, 1100 | "require": { 1101 | "php": ">=5.6", 1102 | "sebastian/recursion-context": "~2.0" 1103 | }, 1104 | "require-dev": { 1105 | "phpunit/phpunit": "~5" 1106 | }, 1107 | "type": "library", 1108 | "extra": { 1109 | "branch-alias": { 1110 | "dev-master": "2.0.x-dev" 1111 | } 1112 | }, 1113 | "autoload": { 1114 | "classmap": [ 1115 | "src/" 1116 | ] 1117 | }, 1118 | "notification-url": "https://packagist.org/downloads/", 1119 | "license": [ 1120 | "BSD-3-Clause" 1121 | ], 1122 | "authors": [ 1123 | { 1124 | "name": "Sebastian Bergmann", 1125 | "email": "sebastian@phpunit.de" 1126 | } 1127 | ], 1128 | "description": "Traverses array structures and object graphs to enumerate all referenced objects", 1129 | "homepage": "https://github.com/sebastianbergmann/object-enumerator/", 1130 | "time": "2017-02-18T15:18:39+00:00" 1131 | }, 1132 | { 1133 | "name": "sebastian/recursion-context", 1134 | "version": "2.0.0", 1135 | "source": { 1136 | "type": "git", 1137 | "url": "https://github.com/sebastianbergmann/recursion-context.git", 1138 | "reference": "2c3ba150cbec723aa057506e73a8d33bdb286c9a" 1139 | }, 1140 | "dist": { 1141 | "type": "zip", 1142 | "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/2c3ba150cbec723aa057506e73a8d33bdb286c9a", 1143 | "reference": "2c3ba150cbec723aa057506e73a8d33bdb286c9a", 1144 | "shasum": "" 1145 | }, 1146 | "require": { 1147 | "php": ">=5.3.3" 1148 | }, 1149 | "require-dev": { 1150 | "phpunit/phpunit": "~4.4" 1151 | }, 1152 | "type": "library", 1153 | "extra": { 1154 | "branch-alias": { 1155 | "dev-master": "2.0.x-dev" 1156 | } 1157 | }, 1158 | "autoload": { 1159 | "classmap": [ 1160 | "src/" 1161 | ] 1162 | }, 1163 | "notification-url": "https://packagist.org/downloads/", 1164 | "license": [ 1165 | "BSD-3-Clause" 1166 | ], 1167 | "authors": [ 1168 | { 1169 | "name": "Jeff Welch", 1170 | "email": "whatthejeff@gmail.com" 1171 | }, 1172 | { 1173 | "name": "Sebastian Bergmann", 1174 | "email": "sebastian@phpunit.de" 1175 | }, 1176 | { 1177 | "name": "Adam Harvey", 1178 | "email": "aharvey@php.net" 1179 | } 1180 | ], 1181 | "description": "Provides functionality to recursively process PHP variables", 1182 | "homepage": "http://www.github.com/sebastianbergmann/recursion-context", 1183 | "time": "2016-11-19T07:33:16+00:00" 1184 | }, 1185 | { 1186 | "name": "sebastian/resource-operations", 1187 | "version": "1.0.0", 1188 | "source": { 1189 | "type": "git", 1190 | "url": "https://github.com/sebastianbergmann/resource-operations.git", 1191 | "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52" 1192 | }, 1193 | "dist": { 1194 | "type": "zip", 1195 | "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", 1196 | "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", 1197 | "shasum": "" 1198 | }, 1199 | "require": { 1200 | "php": ">=5.6.0" 1201 | }, 1202 | "type": "library", 1203 | "extra": { 1204 | "branch-alias": { 1205 | "dev-master": "1.0.x-dev" 1206 | } 1207 | }, 1208 | "autoload": { 1209 | "classmap": [ 1210 | "src/" 1211 | ] 1212 | }, 1213 | "notification-url": "https://packagist.org/downloads/", 1214 | "license": [ 1215 | "BSD-3-Clause" 1216 | ], 1217 | "authors": [ 1218 | { 1219 | "name": "Sebastian Bergmann", 1220 | "email": "sebastian@phpunit.de" 1221 | } 1222 | ], 1223 | "description": "Provides a list of PHP built-in functions that operate on resources", 1224 | "homepage": "https://www.github.com/sebastianbergmann/resource-operations", 1225 | "time": "2015-07-28T20:34:47+00:00" 1226 | }, 1227 | { 1228 | "name": "sebastian/version", 1229 | "version": "2.0.1", 1230 | "source": { 1231 | "type": "git", 1232 | "url": "https://github.com/sebastianbergmann/version.git", 1233 | "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019" 1234 | }, 1235 | "dist": { 1236 | "type": "zip", 1237 | "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/99732be0ddb3361e16ad77b68ba41efc8e979019", 1238 | "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019", 1239 | "shasum": "" 1240 | }, 1241 | "require": { 1242 | "php": ">=5.6" 1243 | }, 1244 | "type": "library", 1245 | "extra": { 1246 | "branch-alias": { 1247 | "dev-master": "2.0.x-dev" 1248 | } 1249 | }, 1250 | "autoload": { 1251 | "classmap": [ 1252 | "src/" 1253 | ] 1254 | }, 1255 | "notification-url": "https://packagist.org/downloads/", 1256 | "license": [ 1257 | "BSD-3-Clause" 1258 | ], 1259 | "authors": [ 1260 | { 1261 | "name": "Sebastian Bergmann", 1262 | "email": "sebastian@phpunit.de", 1263 | "role": "lead" 1264 | } 1265 | ], 1266 | "description": "Library that helps with managing the version number of Git-hosted PHP projects", 1267 | "homepage": "https://github.com/sebastianbergmann/version", 1268 | "time": "2016-10-03T07:35:21+00:00" 1269 | }, 1270 | { 1271 | "name": "symfony/yaml", 1272 | "version": "v3.4.4", 1273 | "source": { 1274 | "type": "git", 1275 | "url": "https://github.com/symfony/yaml.git", 1276 | "reference": "eab73b6c21d27ae4cd037c417618dfd4befb0bfe" 1277 | }, 1278 | "dist": { 1279 | "type": "zip", 1280 | "url": "https://api.github.com/repos/symfony/yaml/zipball/eab73b6c21d27ae4cd037c417618dfd4befb0bfe", 1281 | "reference": "eab73b6c21d27ae4cd037c417618dfd4befb0bfe", 1282 | "shasum": "" 1283 | }, 1284 | "require": { 1285 | "php": "^5.5.9|>=7.0.8" 1286 | }, 1287 | "conflict": { 1288 | "symfony/console": "<3.4" 1289 | }, 1290 | "require-dev": { 1291 | "symfony/console": "~3.4|~4.0" 1292 | }, 1293 | "suggest": { 1294 | "symfony/console": "For validating YAML files using the lint command" 1295 | }, 1296 | "type": "library", 1297 | "extra": { 1298 | "branch-alias": { 1299 | "dev-master": "3.4-dev" 1300 | } 1301 | }, 1302 | "autoload": { 1303 | "psr-4": { 1304 | "Symfony\\Component\\Yaml\\": "" 1305 | }, 1306 | "exclude-from-classmap": [ 1307 | "/Tests/" 1308 | ] 1309 | }, 1310 | "notification-url": "https://packagist.org/downloads/", 1311 | "license": [ 1312 | "MIT" 1313 | ], 1314 | "authors": [ 1315 | { 1316 | "name": "Fabien Potencier", 1317 | "email": "fabien@symfony.com" 1318 | }, 1319 | { 1320 | "name": "Symfony Community", 1321 | "homepage": "https://symfony.com/contributors" 1322 | } 1323 | ], 1324 | "description": "Symfony Yaml Component", 1325 | "homepage": "https://symfony.com", 1326 | "time": "2018-01-21T19:05:02+00:00" 1327 | }, 1328 | { 1329 | "name": "webmozart/assert", 1330 | "version": "1.3.0", 1331 | "source": { 1332 | "type": "git", 1333 | "url": "https://github.com/webmozart/assert.git", 1334 | "reference": "0df1908962e7a3071564e857d86874dad1ef204a" 1335 | }, 1336 | "dist": { 1337 | "type": "zip", 1338 | "url": "https://api.github.com/repos/webmozart/assert/zipball/0df1908962e7a3071564e857d86874dad1ef204a", 1339 | "reference": "0df1908962e7a3071564e857d86874dad1ef204a", 1340 | "shasum": "" 1341 | }, 1342 | "require": { 1343 | "php": "^5.3.3 || ^7.0" 1344 | }, 1345 | "require-dev": { 1346 | "phpunit/phpunit": "^4.6", 1347 | "sebastian/version": "^1.0.1" 1348 | }, 1349 | "type": "library", 1350 | "extra": { 1351 | "branch-alias": { 1352 | "dev-master": "1.3-dev" 1353 | } 1354 | }, 1355 | "autoload": { 1356 | "psr-4": { 1357 | "Webmozart\\Assert\\": "src/" 1358 | } 1359 | }, 1360 | "notification-url": "https://packagist.org/downloads/", 1361 | "license": [ 1362 | "MIT" 1363 | ], 1364 | "authors": [ 1365 | { 1366 | "name": "Bernhard Schussek", 1367 | "email": "bschussek@gmail.com" 1368 | } 1369 | ], 1370 | "description": "Assertions to validate method input/output with nice error messages.", 1371 | "keywords": [ 1372 | "assert", 1373 | "check", 1374 | "validate" 1375 | ], 1376 | "time": "2018-01-29T19:49:41+00:00" 1377 | } 1378 | ], 1379 | "aliases": [], 1380 | "minimum-stability": "dev", 1381 | "stability-flags": [], 1382 | "prefer-stable": true, 1383 | "prefer-lowest": false, 1384 | "platform": { 1385 | "php": "^5.6 || ^7.0", 1386 | "ext-openssl": "*", 1387 | "ext-mbstring": "*" 1388 | }, 1389 | "platform-dev": [] 1390 | } 1391 | -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ./test 5 | 6 | 7 | 8 | 9 | 10 | src 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/Exception/AuthenticationFailedException.php: -------------------------------------------------------------------------------- 1 | key = $this->getKey('KEY_' . $session_name); 52 | return parent::open($save_path, $session_name); 53 | } 54 | 55 | /** 56 | * Read from session and decrypt 57 | * 58 | * @param string $id 59 | */ 60 | public function read($id) 61 | { 62 | $data = parent::read($id); 63 | return empty($data) ? '' : $this->decrypt($data, $this->key); 64 | } 65 | 66 | /** 67 | * Encrypt the data and write into the session 68 | * 69 | * @param string $id 70 | * @param string $data 71 | */ 72 | public function write($id, $data) 73 | { 74 | return parent::write($id, $this->encrypt($data, $this->key)); 75 | } 76 | 77 | /** 78 | * Encrypt and authenticate 79 | * 80 | * @param string $data 81 | * @param string $key 82 | * @return string 83 | */ 84 | protected function encrypt($data, $key) 85 | { 86 | $iv = random_bytes(16); // AES block size in CBC mode 87 | // Encryption 88 | $ciphertext = openssl_encrypt( 89 | $data, 90 | 'AES-256-CBC', 91 | mb_substr($key, 0, 32, '8bit'), 92 | OPENSSL_RAW_DATA, 93 | $iv 94 | ); 95 | // Authentication 96 | $hmac = hash_hmac( 97 | 'SHA256', 98 | $iv . $ciphertext, 99 | mb_substr($key, 32, null, '8bit'), 100 | true 101 | ); 102 | return $hmac . $iv . $ciphertext; 103 | } 104 | 105 | /** 106 | * Authenticate and decrypt 107 | * 108 | * @param string $data 109 | * @param string $key 110 | * @return string 111 | */ 112 | protected function decrypt($data, $key) 113 | { 114 | $hmac = mb_substr($data, 0, 32, '8bit'); 115 | $iv = mb_substr($data, 32, 16, '8bit'); 116 | $ciphertext = mb_substr($data, 48, null, '8bit'); 117 | // Authentication 118 | $hmacNew = hash_hmac( 119 | 'SHA256', 120 | $iv . $ciphertext, 121 | mb_substr($key, 32, null, '8bit'), 122 | true 123 | ); 124 | if (! hash_equals($hmac, $hmacNew)) { 125 | throw new Exception\AuthenticationFailedException('Authentication failed'); 126 | } 127 | // Decrypt 128 | return openssl_decrypt( 129 | $ciphertext, 130 | 'AES-256-CBC', 131 | mb_substr($key, 0, 32, '8bit'), 132 | OPENSSL_RAW_DATA, 133 | $iv 134 | ); 135 | } 136 | 137 | /** 138 | * Get the encryption and authentication keys from cookie 139 | * 140 | * @param string $name 141 | * @return string 142 | */ 143 | protected function getKey($name) 144 | { 145 | if (empty($_COOKIE[$name])) { 146 | $key = random_bytes(64); // 32 for encryption and 32 for authentication 147 | $cookieParam = session_get_cookie_params(); 148 | $encKey = base64_encode($key); 149 | setcookie( 150 | $name, 151 | $encKey, 152 | // if session cookie lifetime > 0 then add to current time 153 | // otherwise leave it as zero, honoring zero's special meaning 154 | // expire at browser close. 155 | ($cookieParam['lifetime'] > 0) ? time() + $cookieParam['lifetime'] : 0, 156 | $cookieParam['path'], 157 | $cookieParam['domain'], 158 | $cookieParam['secure'], 159 | $cookieParam['httponly'] 160 | ); 161 | $_COOKIE[$name] = $encKey; 162 | } else { 163 | $key = base64_decode($_COOKIE[$name]); 164 | } 165 | return $key; 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /test/SecureHandlerTest.php: -------------------------------------------------------------------------------- 1 | secureHandler = new SecureHandler(); 17 | session_set_save_handler($this->secureHandler, true); 18 | session_start(); 19 | } 20 | 21 | public function tearDown() 22 | { 23 | session_destroy(); 24 | session_write_close(); 25 | } 26 | 27 | public function testConstructor() 28 | { 29 | $this->assertInstanceOf(SessionHandler::class, $this->secureHandler); 30 | } 31 | 32 | public function testOpen() 33 | { 34 | $this->assertTrue($this->secureHandler->open(sys_get_temp_dir(), '')); 35 | 36 | $handler = new ReflectionObject($this->secureHandler); 37 | $key = $handler->getProperty('key'); 38 | $key->setAccessible(true); 39 | $this->assertEquals(64, mb_strlen($key->getValue($this->secureHandler), '8bit')); 40 | } 41 | 42 | public function testWriteRead() 43 | { 44 | $this->assertTrue($this->secureHandler->open(sys_get_temp_dir(), '')); 45 | $id = session_id(); 46 | $data = random_bytes(1024); 47 | $this->assertTrue($this->secureHandler->write($id, $data)); 48 | $this->assertEquals($data, $this->secureHandler->read($id)); 49 | } 50 | 51 | /** 52 | * Test for issue #27 53 | * @see https://github.com/ezimuel/PHP-Secure-Session/issues/27 54 | */ 55 | public function testDoubleOpen() 56 | { 57 | $this->assertTrue($this->secureHandler->open(sys_get_temp_dir(), '')); 58 | $id1 = session_id(); 59 | 60 | $handler = new ReflectionObject($this->secureHandler); 61 | $key = $handler->getProperty('key'); 62 | $key->setAccessible(true); 63 | $key1 = $key->getValue($this->secureHandler); 64 | 65 | $this->assertTrue($this->secureHandler->open(sys_get_temp_dir(), '')); 66 | $id2 = session_id(); 67 | $key2 = $key->getValue($this->secureHandler); 68 | 69 | $this->assertEquals($id1, $id2); 70 | $this->assertEquals($key1, $key2); 71 | } 72 | 73 | public function testAuthenticationFailureDecrypt() 74 | { 75 | $this->assertTrue($this->secureHandler->open(sys_get_temp_dir(), '')); 76 | $id = session_id(); 77 | $data = "This is a test!"; 78 | $this->assertTrue($this->secureHandler->write($id, $data)); 79 | 80 | // Change the session data to generate an authentication error 81 | $alteredData = str_replace('!', '.', $data); 82 | file_put_contents(sys_get_temp_dir() . "/sess_$id", $alteredData); 83 | 84 | $this->expectException(AuthenticationFailedException::class); 85 | $this->assertEquals($data, $this->secureHandler->read($id)); 86 | 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /test/autoload.php: -------------------------------------------------------------------------------- 1 | composer install!"; 15 | exit; 16 | } 17 | require_once $autoload; 18 | 19 | // change the default session folder in a temporary dir 20 | session_save_path(sys_get_temp_dir()); 21 | session_start(); 22 | 23 | if (empty($_SESSION['time'])) { 24 | $_SESSION['time'] = time(); // set the time 25 | } 26 | session_write_close(); 27 | 28 | $filename = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'sess_' . session_id(); 29 | 30 | $time = microtime(true) - $start; 31 | 32 | echo "

PHP-Secure-Session Demo

"; 33 | echo "

Session created at " . date("G:i:s ", $_SESSION['time']) . "

"; 34 | echo "

Session file: " . $filename . "

"; 35 | echo "

Content:

" . session_encode() . "

"; 36 | echo "

Encrypted content in Base64:

" . base64_encode(file_get_contents($filename)). "

"; 37 | echo "

Note: If you reload the page you will see the encrypted data changing

"; 38 | 39 | printf("Execution time: %.6f", $time * 1000); 40 | --------------------------------------------------------------------------------