├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── composer.json ├── composer.lock └── src ├── AbstractValidator.php ├── Barcode.php ├── Barcode ├── AbstractAdapter.php ├── AdapterInterface.php ├── ChecksumTrait.php ├── ChecksummableInterface.php ├── Codabar.php ├── Code128.php ├── Code25.php ├── Code25ChecksumTrait.php ├── Code25interleaved.php ├── Code39.php ├── Code39ChecksumTrait.php ├── Code39ext.php ├── Code93.php ├── Code93ChecksumTrait.php ├── Code93ext.php ├── Ean12.php ├── Ean13.php ├── Ean14.php ├── Ean18.php ├── Ean2.php ├── Ean5.php ├── Ean8.php ├── Gtin12.php ├── Gtin13.php ├── Gtin14.php ├── GtinChecksumTrait.php ├── Identcode.php ├── IdentcodeChecksumTrait.php ├── Intelligentmail.php ├── Issn.php ├── Itf14.php ├── Leitcode.php ├── Planet.php ├── Postnet.php ├── PostnetChecksumTrait.php ├── Royalmail.php ├── Sscc.php ├── Upca.php └── Upce.php ├── Between.php ├── Callback.php ├── ConfigProvider.php ├── Date.php ├── Exception ├── ExceptionInterface.php ├── InvalidArgumentException.php ├── InvalidCallbackResultException.php └── MissingResultsException.php ├── LegacyValidatorDecorator.php ├── LegacyValidatorTrait.php ├── NotEmpty.php ├── Result.php ├── ResultAggregate.php ├── ResultInterface.php ├── Uuid.php ├── ValidationFailureMessage.php ├── ValidatorChain.php └── ValidatorInterface.php /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 | ## 0.1.0 - TBD 6 | 7 | ### Added 8 | 9 | - Nothing. 10 | 11 | ### Changed 12 | 13 | - Nothing. 14 | 15 | ### Deprecated 16 | 17 | - Nothing. 18 | 19 | ### Removed 20 | 21 | - Nothing. 22 | 23 | ### Fixed 24 | 25 | - Nothing. 26 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018, Zend Technologies USA, Inc. 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, 5 | are permitted provided that the following conditions are met: 6 | 7 | - Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | - Redistributions in binary form must reproduce the above copyright notice, this 11 | list of conditions and the following disclaimer in the documentation and/or 12 | other materials provided with the distribution. 13 | 14 | - Neither the name of Zend Technologies USA, Inc. nor the names of its 15 | contributors may be used to endorse or promote products derived from this 16 | software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 19 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 22 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 25 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 27 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # zend-datavalidator 2 | 3 | [![Build Status](https://secure.travis-ci.org/zendframework/zend-datavalidator.svg?branch=master)](https://secure.travis-ci.org/zendframework/zend-datavalidator) 4 | [![Coverage Status](https://coveralls.io/repos/github/zendframework/zend-datavalidator/badge.svg?branch=master)](https://coveralls.io/github/zendframework/zend-datavalidator?branch=master) 5 | 6 | > ## UNSTABLE 7 | > 8 | > This is a draft library that will eventually be included in Zend Framework. It 9 | > is currently unstable, and likely should not be used in production. Use at 10 | > your own risk! 11 | 12 | This library provides general purpose, stateless validation for PHP values. 13 | 14 | Design document: https://discourse.zendframework.com/t/rfc-new-validation-component/208 15 | 16 | ## Installation 17 | 18 | Run the following to install this library: 19 | 20 | ```bash 21 | $ composer require zendframework/zend-datavalidator 22 | ``` 23 | 24 | > Note: this package is not yet on Packagist; you will need to add a repository 25 | > entry to your `composer.json` referencing this github repo in order to 26 | > complete installation. 27 | 28 | ## Documentation 29 | 30 | Documentation is [in the doc tree](docs/book/), and can be compiled using [mkdocs](http://www.mkdocs.org): 31 | 32 | ```bash 33 | $ mkdocs build 34 | ``` 35 | 36 | ~~You may also [browse the documentation online](https://docs.zendframework.com/zend-datavalidator/).~~ 37 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "zendframework/zend-datavalidator", 3 | "description": "General purpose, stateless data validation for PHP values.", 4 | "type": "library", 5 | "license": "BSD-3-Clause", 6 | "keywords": [ 7 | "validation", 8 | "components", 9 | "zf", 10 | "zendframework" 11 | ], 12 | "support": { 13 | "docs": "https://docs.zendframework.com/zend-datavalidator/", 14 | "issues": "https://github.com/zendframework/zend-datavalidator/issues", 15 | "source": "https://github.com/zendframework/zend-datavalidator", 16 | "slack": "https://zendframework-slack.herokuapp.com", 17 | "forum": "https://discourse.zendframework.com/c/questions/components" 18 | }, 19 | "config": { 20 | "sort-packages": true 21 | }, 22 | "require": { 23 | "php": "^7.1" 24 | }, 25 | "require-dev": { 26 | "phpunit/phpunit": "^7.0.1", 27 | "zendframework/zend-coding-standard": "^1.0", 28 | "zendframework/zend-validator": "^2.10.1" 29 | }, 30 | "autoload": { 31 | "psr-4": { 32 | "Zend\\DataValidator\\": "src/" 33 | } 34 | }, 35 | "autoload-dev": { 36 | "psr-4": { 37 | "ZendTest\\DataValidator\\": "test/" 38 | } 39 | }, 40 | "extra": { 41 | "zf": { 42 | "config-provider": "Zend\\DataValidator\\ConfigProvider" 43 | } 44 | }, 45 | "scripts": { 46 | "check": [ 47 | "@cs-check", 48 | "@test" 49 | ], 50 | "cs-check": "phpcs", 51 | "cs-fix": "phpcbf", 52 | "test": "phpunit --colors=always", 53 | "test-coverage": "phpunit --colors=always --coverage-clover clover.xml" 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /composer.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_readme": [ 3 | "This file locks the dependencies of your project to a known state", 4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", 5 | "This file is @generated automatically" 6 | ], 7 | "content-hash": "aacf2bd6b0a6ed380dcfd340cf854553", 8 | "packages": [], 9 | "packages-dev": [ 10 | { 11 | "name": "container-interop/container-interop", 12 | "version": "1.2.0", 13 | "source": { 14 | "type": "git", 15 | "url": "https://github.com/container-interop/container-interop.git", 16 | "reference": "79cbf1341c22ec75643d841642dd5d6acd83bdb8" 17 | }, 18 | "dist": { 19 | "type": "zip", 20 | "url": "https://api.github.com/repos/container-interop/container-interop/zipball/79cbf1341c22ec75643d841642dd5d6acd83bdb8", 21 | "reference": "79cbf1341c22ec75643d841642dd5d6acd83bdb8", 22 | "shasum": "" 23 | }, 24 | "require": { 25 | "psr/container": "^1.0" 26 | }, 27 | "type": "library", 28 | "autoload": { 29 | "psr-4": { 30 | "Interop\\Container\\": "src/Interop/Container/" 31 | } 32 | }, 33 | "notification-url": "https://packagist.org/downloads/", 34 | "license": [ 35 | "MIT" 36 | ], 37 | "description": "Promoting the interoperability of container objects (DIC, SL, etc.)", 38 | "homepage": "https://github.com/container-interop/container-interop", 39 | "time": "2017-02-14T19:40:03+00:00" 40 | }, 41 | { 42 | "name": "doctrine/instantiator", 43 | "version": "1.1.0", 44 | "source": { 45 | "type": "git", 46 | "url": "https://github.com/doctrine/instantiator.git", 47 | "reference": "185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda" 48 | }, 49 | "dist": { 50 | "type": "zip", 51 | "url": "https://api.github.com/repos/doctrine/instantiator/zipball/185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda", 52 | "reference": "185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda", 53 | "shasum": "" 54 | }, 55 | "require": { 56 | "php": "^7.1" 57 | }, 58 | "require-dev": { 59 | "athletic/athletic": "~0.1.8", 60 | "ext-pdo": "*", 61 | "ext-phar": "*", 62 | "phpunit/phpunit": "^6.2.3", 63 | "squizlabs/php_codesniffer": "^3.0.2" 64 | }, 65 | "type": "library", 66 | "extra": { 67 | "branch-alias": { 68 | "dev-master": "1.2.x-dev" 69 | } 70 | }, 71 | "autoload": { 72 | "psr-4": { 73 | "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" 74 | } 75 | }, 76 | "notification-url": "https://packagist.org/downloads/", 77 | "license": [ 78 | "MIT" 79 | ], 80 | "authors": [ 81 | { 82 | "name": "Marco Pivetta", 83 | "email": "ocramius@gmail.com", 84 | "homepage": "http://ocramius.github.com/" 85 | } 86 | ], 87 | "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", 88 | "homepage": "https://github.com/doctrine/instantiator", 89 | "keywords": [ 90 | "constructor", 91 | "instantiate" 92 | ], 93 | "time": "2017-07-22T11:58:36+00:00" 94 | }, 95 | { 96 | "name": "myclabs/deep-copy", 97 | "version": "1.8.1", 98 | "source": { 99 | "type": "git", 100 | "url": "https://github.com/myclabs/DeepCopy.git", 101 | "reference": "3e01bdad3e18354c3dce54466b7fbe33a9f9f7f8" 102 | }, 103 | "dist": { 104 | "type": "zip", 105 | "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3e01bdad3e18354c3dce54466b7fbe33a9f9f7f8", 106 | "reference": "3e01bdad3e18354c3dce54466b7fbe33a9f9f7f8", 107 | "shasum": "" 108 | }, 109 | "require": { 110 | "php": "^7.1" 111 | }, 112 | "replace": { 113 | "myclabs/deep-copy": "self.version" 114 | }, 115 | "require-dev": { 116 | "doctrine/collections": "^1.0", 117 | "doctrine/common": "^2.6", 118 | "phpunit/phpunit": "^7.1" 119 | }, 120 | "type": "library", 121 | "autoload": { 122 | "psr-4": { 123 | "DeepCopy\\": "src/DeepCopy/" 124 | }, 125 | "files": [ 126 | "src/DeepCopy/deep_copy.php" 127 | ] 128 | }, 129 | "notification-url": "https://packagist.org/downloads/", 130 | "license": [ 131 | "MIT" 132 | ], 133 | "description": "Create deep copies (clones) of your objects", 134 | "keywords": [ 135 | "clone", 136 | "copy", 137 | "duplicate", 138 | "object", 139 | "object graph" 140 | ], 141 | "time": "2018-06-11T23:09:50+00:00" 142 | }, 143 | { 144 | "name": "phar-io/manifest", 145 | "version": "1.0.1", 146 | "source": { 147 | "type": "git", 148 | "url": "https://github.com/phar-io/manifest.git", 149 | "reference": "2df402786ab5368a0169091f61a7c1e0eb6852d0" 150 | }, 151 | "dist": { 152 | "type": "zip", 153 | "url": "https://api.github.com/repos/phar-io/manifest/zipball/2df402786ab5368a0169091f61a7c1e0eb6852d0", 154 | "reference": "2df402786ab5368a0169091f61a7c1e0eb6852d0", 155 | "shasum": "" 156 | }, 157 | "require": { 158 | "ext-dom": "*", 159 | "ext-phar": "*", 160 | "phar-io/version": "^1.0.1", 161 | "php": "^5.6 || ^7.0" 162 | }, 163 | "type": "library", 164 | "extra": { 165 | "branch-alias": { 166 | "dev-master": "1.0.x-dev" 167 | } 168 | }, 169 | "autoload": { 170 | "classmap": [ 171 | "src/" 172 | ] 173 | }, 174 | "notification-url": "https://packagist.org/downloads/", 175 | "license": [ 176 | "BSD-3-Clause" 177 | ], 178 | "authors": [ 179 | { 180 | "name": "Arne Blankerts", 181 | "email": "arne@blankerts.de", 182 | "role": "Developer" 183 | }, 184 | { 185 | "name": "Sebastian Heuer", 186 | "email": "sebastian@phpeople.de", 187 | "role": "Developer" 188 | }, 189 | { 190 | "name": "Sebastian Bergmann", 191 | "email": "sebastian@phpunit.de", 192 | "role": "Developer" 193 | } 194 | ], 195 | "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", 196 | "time": "2017-03-05T18:14:27+00:00" 197 | }, 198 | { 199 | "name": "phar-io/version", 200 | "version": "1.0.1", 201 | "source": { 202 | "type": "git", 203 | "url": "https://github.com/phar-io/version.git", 204 | "reference": "a70c0ced4be299a63d32fa96d9281d03e94041df" 205 | }, 206 | "dist": { 207 | "type": "zip", 208 | "url": "https://api.github.com/repos/phar-io/version/zipball/a70c0ced4be299a63d32fa96d9281d03e94041df", 209 | "reference": "a70c0ced4be299a63d32fa96d9281d03e94041df", 210 | "shasum": "" 211 | }, 212 | "require": { 213 | "php": "^5.6 || ^7.0" 214 | }, 215 | "type": "library", 216 | "autoload": { 217 | "classmap": [ 218 | "src/" 219 | ] 220 | }, 221 | "notification-url": "https://packagist.org/downloads/", 222 | "license": [ 223 | "BSD-3-Clause" 224 | ], 225 | "authors": [ 226 | { 227 | "name": "Arne Blankerts", 228 | "email": "arne@blankerts.de", 229 | "role": "Developer" 230 | }, 231 | { 232 | "name": "Sebastian Heuer", 233 | "email": "sebastian@phpeople.de", 234 | "role": "Developer" 235 | }, 236 | { 237 | "name": "Sebastian Bergmann", 238 | "email": "sebastian@phpunit.de", 239 | "role": "Developer" 240 | } 241 | ], 242 | "description": "Library for handling version information and constraints", 243 | "time": "2017-03-05T17:38:23+00:00" 244 | }, 245 | { 246 | "name": "phpdocumentor/reflection-common", 247 | "version": "1.0.1", 248 | "source": { 249 | "type": "git", 250 | "url": "https://github.com/phpDocumentor/ReflectionCommon.git", 251 | "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6" 252 | }, 253 | "dist": { 254 | "type": "zip", 255 | "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6", 256 | "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6", 257 | "shasum": "" 258 | }, 259 | "require": { 260 | "php": ">=5.5" 261 | }, 262 | "require-dev": { 263 | "phpunit/phpunit": "^4.6" 264 | }, 265 | "type": "library", 266 | "extra": { 267 | "branch-alias": { 268 | "dev-master": "1.0.x-dev" 269 | } 270 | }, 271 | "autoload": { 272 | "psr-4": { 273 | "phpDocumentor\\Reflection\\": [ 274 | "src" 275 | ] 276 | } 277 | }, 278 | "notification-url": "https://packagist.org/downloads/", 279 | "license": [ 280 | "MIT" 281 | ], 282 | "authors": [ 283 | { 284 | "name": "Jaap van Otterdijk", 285 | "email": "opensource@ijaap.nl" 286 | } 287 | ], 288 | "description": "Common reflection classes used by phpdocumentor to reflect the code structure", 289 | "homepage": "http://www.phpdoc.org", 290 | "keywords": [ 291 | "FQSEN", 292 | "phpDocumentor", 293 | "phpdoc", 294 | "reflection", 295 | "static analysis" 296 | ], 297 | "time": "2017-09-11T18:02:19+00:00" 298 | }, 299 | { 300 | "name": "phpdocumentor/reflection-docblock", 301 | "version": "4.3.0", 302 | "source": { 303 | "type": "git", 304 | "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", 305 | "reference": "94fd0001232e47129dd3504189fa1c7225010d08" 306 | }, 307 | "dist": { 308 | "type": "zip", 309 | "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/94fd0001232e47129dd3504189fa1c7225010d08", 310 | "reference": "94fd0001232e47129dd3504189fa1c7225010d08", 311 | "shasum": "" 312 | }, 313 | "require": { 314 | "php": "^7.0", 315 | "phpdocumentor/reflection-common": "^1.0.0", 316 | "phpdocumentor/type-resolver": "^0.4.0", 317 | "webmozart/assert": "^1.0" 318 | }, 319 | "require-dev": { 320 | "doctrine/instantiator": "~1.0.5", 321 | "mockery/mockery": "^1.0", 322 | "phpunit/phpunit": "^6.4" 323 | }, 324 | "type": "library", 325 | "extra": { 326 | "branch-alias": { 327 | "dev-master": "4.x-dev" 328 | } 329 | }, 330 | "autoload": { 331 | "psr-4": { 332 | "phpDocumentor\\Reflection\\": [ 333 | "src/" 334 | ] 335 | } 336 | }, 337 | "notification-url": "https://packagist.org/downloads/", 338 | "license": [ 339 | "MIT" 340 | ], 341 | "authors": [ 342 | { 343 | "name": "Mike van Riel", 344 | "email": "me@mikevanriel.com" 345 | } 346 | ], 347 | "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", 348 | "time": "2017-11-30T07:14:17+00:00" 349 | }, 350 | { 351 | "name": "phpdocumentor/type-resolver", 352 | "version": "0.4.0", 353 | "source": { 354 | "type": "git", 355 | "url": "https://github.com/phpDocumentor/TypeResolver.git", 356 | "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7" 357 | }, 358 | "dist": { 359 | "type": "zip", 360 | "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/9c977708995954784726e25d0cd1dddf4e65b0f7", 361 | "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7", 362 | "shasum": "" 363 | }, 364 | "require": { 365 | "php": "^5.5 || ^7.0", 366 | "phpdocumentor/reflection-common": "^1.0" 367 | }, 368 | "require-dev": { 369 | "mockery/mockery": "^0.9.4", 370 | "phpunit/phpunit": "^5.2||^4.8.24" 371 | }, 372 | "type": "library", 373 | "extra": { 374 | "branch-alias": { 375 | "dev-master": "1.0.x-dev" 376 | } 377 | }, 378 | "autoload": { 379 | "psr-4": { 380 | "phpDocumentor\\Reflection\\": [ 381 | "src/" 382 | ] 383 | } 384 | }, 385 | "notification-url": "https://packagist.org/downloads/", 386 | "license": [ 387 | "MIT" 388 | ], 389 | "authors": [ 390 | { 391 | "name": "Mike van Riel", 392 | "email": "me@mikevanriel.com" 393 | } 394 | ], 395 | "time": "2017-07-14T14:27:02+00:00" 396 | }, 397 | { 398 | "name": "phpspec/prophecy", 399 | "version": "1.7.6", 400 | "source": { 401 | "type": "git", 402 | "url": "https://github.com/phpspec/prophecy.git", 403 | "reference": "33a7e3c4fda54e912ff6338c48823bd5c0f0b712" 404 | }, 405 | "dist": { 406 | "type": "zip", 407 | "url": "https://api.github.com/repos/phpspec/prophecy/zipball/33a7e3c4fda54e912ff6338c48823bd5c0f0b712", 408 | "reference": "33a7e3c4fda54e912ff6338c48823bd5c0f0b712", 409 | "shasum": "" 410 | }, 411 | "require": { 412 | "doctrine/instantiator": "^1.0.2", 413 | "php": "^5.3|^7.0", 414 | "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0", 415 | "sebastian/comparator": "^1.1|^2.0|^3.0", 416 | "sebastian/recursion-context": "^1.0|^2.0|^3.0" 417 | }, 418 | "require-dev": { 419 | "phpspec/phpspec": "^2.5|^3.2", 420 | "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5" 421 | }, 422 | "type": "library", 423 | "extra": { 424 | "branch-alias": { 425 | "dev-master": "1.7.x-dev" 426 | } 427 | }, 428 | "autoload": { 429 | "psr-0": { 430 | "Prophecy\\": "src/" 431 | } 432 | }, 433 | "notification-url": "https://packagist.org/downloads/", 434 | "license": [ 435 | "MIT" 436 | ], 437 | "authors": [ 438 | { 439 | "name": "Konstantin Kudryashov", 440 | "email": "ever.zet@gmail.com", 441 | "homepage": "http://everzet.com" 442 | }, 443 | { 444 | "name": "Marcello Duarte", 445 | "email": "marcello.duarte@gmail.com" 446 | } 447 | ], 448 | "description": "Highly opinionated mocking framework for PHP 5.3+", 449 | "homepage": "https://github.com/phpspec/prophecy", 450 | "keywords": [ 451 | "Double", 452 | "Dummy", 453 | "fake", 454 | "mock", 455 | "spy", 456 | "stub" 457 | ], 458 | "time": "2018-04-18T13:57:24+00:00" 459 | }, 460 | { 461 | "name": "phpunit/php-code-coverage", 462 | "version": "6.0.7", 463 | "source": { 464 | "type": "git", 465 | "url": "https://github.com/sebastianbergmann/php-code-coverage.git", 466 | "reference": "865662550c384bc1db7e51d29aeda1c2c161d69a" 467 | }, 468 | "dist": { 469 | "type": "zip", 470 | "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/865662550c384bc1db7e51d29aeda1c2c161d69a", 471 | "reference": "865662550c384bc1db7e51d29aeda1c2c161d69a", 472 | "shasum": "" 473 | }, 474 | "require": { 475 | "ext-dom": "*", 476 | "ext-xmlwriter": "*", 477 | "php": "^7.1", 478 | "phpunit/php-file-iterator": "^2.0", 479 | "phpunit/php-text-template": "^1.2.1", 480 | "phpunit/php-token-stream": "^3.0", 481 | "sebastian/code-unit-reverse-lookup": "^1.0.1", 482 | "sebastian/environment": "^3.1", 483 | "sebastian/version": "^2.0.1", 484 | "theseer/tokenizer": "^1.1" 485 | }, 486 | "require-dev": { 487 | "phpunit/phpunit": "^7.0" 488 | }, 489 | "suggest": { 490 | "ext-xdebug": "^2.6.0" 491 | }, 492 | "type": "library", 493 | "extra": { 494 | "branch-alias": { 495 | "dev-master": "6.0-dev" 496 | } 497 | }, 498 | "autoload": { 499 | "classmap": [ 500 | "src/" 501 | ] 502 | }, 503 | "notification-url": "https://packagist.org/downloads/", 504 | "license": [ 505 | "BSD-3-Clause" 506 | ], 507 | "authors": [ 508 | { 509 | "name": "Sebastian Bergmann", 510 | "email": "sebastian@phpunit.de", 511 | "role": "lead" 512 | } 513 | ], 514 | "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", 515 | "homepage": "https://github.com/sebastianbergmann/php-code-coverage", 516 | "keywords": [ 517 | "coverage", 518 | "testing", 519 | "xunit" 520 | ], 521 | "time": "2018-06-01T07:51:50+00:00" 522 | }, 523 | { 524 | "name": "phpunit/php-file-iterator", 525 | "version": "2.0.1", 526 | "source": { 527 | "type": "git", 528 | "url": "https://github.com/sebastianbergmann/php-file-iterator.git", 529 | "reference": "cecbc684605bb0cc288828eb5d65d93d5c676d3c" 530 | }, 531 | "dist": { 532 | "type": "zip", 533 | "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/cecbc684605bb0cc288828eb5d65d93d5c676d3c", 534 | "reference": "cecbc684605bb0cc288828eb5d65d93d5c676d3c", 535 | "shasum": "" 536 | }, 537 | "require": { 538 | "php": "^7.1" 539 | }, 540 | "type": "library", 541 | "extra": { 542 | "branch-alias": { 543 | "dev-master": "2.0.x-dev" 544 | } 545 | }, 546 | "autoload": { 547 | "classmap": [ 548 | "src/" 549 | ] 550 | }, 551 | "notification-url": "https://packagist.org/downloads/", 552 | "license": [ 553 | "BSD-3-Clause" 554 | ], 555 | "authors": [ 556 | { 557 | "name": "Sebastian Bergmann", 558 | "email": "sebastian@phpunit.de", 559 | "role": "lead" 560 | } 561 | ], 562 | "description": "FilterIterator implementation that filters files based on a list of suffixes.", 563 | "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", 564 | "keywords": [ 565 | "filesystem", 566 | "iterator" 567 | ], 568 | "time": "2018-06-11T11:44:00+00:00" 569 | }, 570 | { 571 | "name": "phpunit/php-text-template", 572 | "version": "1.2.1", 573 | "source": { 574 | "type": "git", 575 | "url": "https://github.com/sebastianbergmann/php-text-template.git", 576 | "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" 577 | }, 578 | "dist": { 579 | "type": "zip", 580 | "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", 581 | "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", 582 | "shasum": "" 583 | }, 584 | "require": { 585 | "php": ">=5.3.3" 586 | }, 587 | "type": "library", 588 | "autoload": { 589 | "classmap": [ 590 | "src/" 591 | ] 592 | }, 593 | "notification-url": "https://packagist.org/downloads/", 594 | "license": [ 595 | "BSD-3-Clause" 596 | ], 597 | "authors": [ 598 | { 599 | "name": "Sebastian Bergmann", 600 | "email": "sebastian@phpunit.de", 601 | "role": "lead" 602 | } 603 | ], 604 | "description": "Simple template engine.", 605 | "homepage": "https://github.com/sebastianbergmann/php-text-template/", 606 | "keywords": [ 607 | "template" 608 | ], 609 | "time": "2015-06-21T13:50:34+00:00" 610 | }, 611 | { 612 | "name": "phpunit/php-timer", 613 | "version": "2.0.0", 614 | "source": { 615 | "type": "git", 616 | "url": "https://github.com/sebastianbergmann/php-timer.git", 617 | "reference": "8b8454ea6958c3dee38453d3bd571e023108c91f" 618 | }, 619 | "dist": { 620 | "type": "zip", 621 | "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/8b8454ea6958c3dee38453d3bd571e023108c91f", 622 | "reference": "8b8454ea6958c3dee38453d3bd571e023108c91f", 623 | "shasum": "" 624 | }, 625 | "require": { 626 | "php": "^7.1" 627 | }, 628 | "require-dev": { 629 | "phpunit/phpunit": "^7.0" 630 | }, 631 | "type": "library", 632 | "extra": { 633 | "branch-alias": { 634 | "dev-master": "2.0-dev" 635 | } 636 | }, 637 | "autoload": { 638 | "classmap": [ 639 | "src/" 640 | ] 641 | }, 642 | "notification-url": "https://packagist.org/downloads/", 643 | "license": [ 644 | "BSD-3-Clause" 645 | ], 646 | "authors": [ 647 | { 648 | "name": "Sebastian Bergmann", 649 | "email": "sebastian@phpunit.de", 650 | "role": "lead" 651 | } 652 | ], 653 | "description": "Utility class for timing", 654 | "homepage": "https://github.com/sebastianbergmann/php-timer/", 655 | "keywords": [ 656 | "timer" 657 | ], 658 | "time": "2018-02-01T13:07:23+00:00" 659 | }, 660 | { 661 | "name": "phpunit/php-token-stream", 662 | "version": "3.0.0", 663 | "source": { 664 | "type": "git", 665 | "url": "https://github.com/sebastianbergmann/php-token-stream.git", 666 | "reference": "21ad88bbba7c3d93530d93994e0a33cd45f02ace" 667 | }, 668 | "dist": { 669 | "type": "zip", 670 | "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/21ad88bbba7c3d93530d93994e0a33cd45f02ace", 671 | "reference": "21ad88bbba7c3d93530d93994e0a33cd45f02ace", 672 | "shasum": "" 673 | }, 674 | "require": { 675 | "ext-tokenizer": "*", 676 | "php": "^7.1" 677 | }, 678 | "require-dev": { 679 | "phpunit/phpunit": "^7.0" 680 | }, 681 | "type": "library", 682 | "extra": { 683 | "branch-alias": { 684 | "dev-master": "3.0-dev" 685 | } 686 | }, 687 | "autoload": { 688 | "classmap": [ 689 | "src/" 690 | ] 691 | }, 692 | "notification-url": "https://packagist.org/downloads/", 693 | "license": [ 694 | "BSD-3-Clause" 695 | ], 696 | "authors": [ 697 | { 698 | "name": "Sebastian Bergmann", 699 | "email": "sebastian@phpunit.de" 700 | } 701 | ], 702 | "description": "Wrapper around PHP's tokenizer extension.", 703 | "homepage": "https://github.com/sebastianbergmann/php-token-stream/", 704 | "keywords": [ 705 | "tokenizer" 706 | ], 707 | "time": "2018-02-01T13:16:43+00:00" 708 | }, 709 | { 710 | "name": "phpunit/phpunit", 711 | "version": "7.2.4", 712 | "source": { 713 | "type": "git", 714 | "url": "https://github.com/sebastianbergmann/phpunit.git", 715 | "reference": "00bc0b93f0ff4f557e9ea766557fde96da9a03dd" 716 | }, 717 | "dist": { 718 | "type": "zip", 719 | "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/00bc0b93f0ff4f557e9ea766557fde96da9a03dd", 720 | "reference": "00bc0b93f0ff4f557e9ea766557fde96da9a03dd", 721 | "shasum": "" 722 | }, 723 | "require": { 724 | "doctrine/instantiator": "^1.1", 725 | "ext-dom": "*", 726 | "ext-json": "*", 727 | "ext-libxml": "*", 728 | "ext-mbstring": "*", 729 | "ext-xml": "*", 730 | "myclabs/deep-copy": "^1.7", 731 | "phar-io/manifest": "^1.0.1", 732 | "phar-io/version": "^1.0", 733 | "php": "^7.1", 734 | "phpspec/prophecy": "^1.7", 735 | "phpunit/php-code-coverage": "^6.0.7", 736 | "phpunit/php-file-iterator": "^2.0", 737 | "phpunit/php-text-template": "^1.2.1", 738 | "phpunit/php-timer": "^2.0", 739 | "sebastian/comparator": "^3.0", 740 | "sebastian/diff": "^3.0", 741 | "sebastian/environment": "^3.1", 742 | "sebastian/exporter": "^3.1", 743 | "sebastian/global-state": "^2.0", 744 | "sebastian/object-enumerator": "^3.0.3", 745 | "sebastian/resource-operations": "^1.0", 746 | "sebastian/version": "^2.0.1" 747 | }, 748 | "conflict": { 749 | "phpunit/phpunit-mock-objects": "*" 750 | }, 751 | "require-dev": { 752 | "ext-pdo": "*" 753 | }, 754 | "suggest": { 755 | "ext-soap": "*", 756 | "ext-xdebug": "*", 757 | "phpunit/php-invoker": "^2.0" 758 | }, 759 | "bin": [ 760 | "phpunit" 761 | ], 762 | "type": "library", 763 | "extra": { 764 | "branch-alias": { 765 | "dev-master": "7.2-dev" 766 | } 767 | }, 768 | "autoload": { 769 | "classmap": [ 770 | "src/" 771 | ] 772 | }, 773 | "notification-url": "https://packagist.org/downloads/", 774 | "license": [ 775 | "BSD-3-Clause" 776 | ], 777 | "authors": [ 778 | { 779 | "name": "Sebastian Bergmann", 780 | "email": "sebastian@phpunit.de", 781 | "role": "lead" 782 | } 783 | ], 784 | "description": "The PHP Unit Testing framework.", 785 | "homepage": "https://phpunit.de/", 786 | "keywords": [ 787 | "phpunit", 788 | "testing", 789 | "xunit" 790 | ], 791 | "time": "2018-06-05T03:40:05+00:00" 792 | }, 793 | { 794 | "name": "psr/container", 795 | "version": "1.0.0", 796 | "source": { 797 | "type": "git", 798 | "url": "https://github.com/php-fig/container.git", 799 | "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f" 800 | }, 801 | "dist": { 802 | "type": "zip", 803 | "url": "https://api.github.com/repos/php-fig/container/zipball/b7ce3b176482dbbc1245ebf52b181af44c2cf55f", 804 | "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f", 805 | "shasum": "" 806 | }, 807 | "require": { 808 | "php": ">=5.3.0" 809 | }, 810 | "type": "library", 811 | "extra": { 812 | "branch-alias": { 813 | "dev-master": "1.0.x-dev" 814 | } 815 | }, 816 | "autoload": { 817 | "psr-4": { 818 | "Psr\\Container\\": "src/" 819 | } 820 | }, 821 | "notification-url": "https://packagist.org/downloads/", 822 | "license": [ 823 | "MIT" 824 | ], 825 | "authors": [ 826 | { 827 | "name": "PHP-FIG", 828 | "homepage": "http://www.php-fig.org/" 829 | } 830 | ], 831 | "description": "Common Container Interface (PHP FIG PSR-11)", 832 | "homepage": "https://github.com/php-fig/container", 833 | "keywords": [ 834 | "PSR-11", 835 | "container", 836 | "container-interface", 837 | "container-interop", 838 | "psr" 839 | ], 840 | "time": "2017-02-14T16:28:37+00:00" 841 | }, 842 | { 843 | "name": "sebastian/code-unit-reverse-lookup", 844 | "version": "1.0.1", 845 | "source": { 846 | "type": "git", 847 | "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", 848 | "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18" 849 | }, 850 | "dist": { 851 | "type": "zip", 852 | "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/4419fcdb5eabb9caa61a27c7a1db532a6b55dd18", 853 | "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18", 854 | "shasum": "" 855 | }, 856 | "require": { 857 | "php": "^5.6 || ^7.0" 858 | }, 859 | "require-dev": { 860 | "phpunit/phpunit": "^5.7 || ^6.0" 861 | }, 862 | "type": "library", 863 | "extra": { 864 | "branch-alias": { 865 | "dev-master": "1.0.x-dev" 866 | } 867 | }, 868 | "autoload": { 869 | "classmap": [ 870 | "src/" 871 | ] 872 | }, 873 | "notification-url": "https://packagist.org/downloads/", 874 | "license": [ 875 | "BSD-3-Clause" 876 | ], 877 | "authors": [ 878 | { 879 | "name": "Sebastian Bergmann", 880 | "email": "sebastian@phpunit.de" 881 | } 882 | ], 883 | "description": "Looks up which function or method a line of code belongs to", 884 | "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", 885 | "time": "2017-03-04T06:30:41+00:00" 886 | }, 887 | { 888 | "name": "sebastian/comparator", 889 | "version": "3.0.1", 890 | "source": { 891 | "type": "git", 892 | "url": "https://github.com/sebastianbergmann/comparator.git", 893 | "reference": "591a30922f54656695e59b1f39501aec513403da" 894 | }, 895 | "dist": { 896 | "type": "zip", 897 | "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/591a30922f54656695e59b1f39501aec513403da", 898 | "reference": "591a30922f54656695e59b1f39501aec513403da", 899 | "shasum": "" 900 | }, 901 | "require": { 902 | "php": "^7.1", 903 | "sebastian/diff": "^3.0", 904 | "sebastian/exporter": "^3.1" 905 | }, 906 | "require-dev": { 907 | "phpunit/phpunit": "^7.1" 908 | }, 909 | "type": "library", 910 | "extra": { 911 | "branch-alias": { 912 | "dev-master": "3.0-dev" 913 | } 914 | }, 915 | "autoload": { 916 | "classmap": [ 917 | "src/" 918 | ] 919 | }, 920 | "notification-url": "https://packagist.org/downloads/", 921 | "license": [ 922 | "BSD-3-Clause" 923 | ], 924 | "authors": [ 925 | { 926 | "name": "Jeff Welch", 927 | "email": "whatthejeff@gmail.com" 928 | }, 929 | { 930 | "name": "Volker Dusch", 931 | "email": "github@wallbash.com" 932 | }, 933 | { 934 | "name": "Bernhard Schussek", 935 | "email": "bschussek@2bepublished.at" 936 | }, 937 | { 938 | "name": "Sebastian Bergmann", 939 | "email": "sebastian@phpunit.de" 940 | } 941 | ], 942 | "description": "Provides the functionality to compare PHP values for equality", 943 | "homepage": "https://github.com/sebastianbergmann/comparator", 944 | "keywords": [ 945 | "comparator", 946 | "compare", 947 | "equality" 948 | ], 949 | "time": "2018-06-14T15:05:28+00:00" 950 | }, 951 | { 952 | "name": "sebastian/diff", 953 | "version": "3.0.1", 954 | "source": { 955 | "type": "git", 956 | "url": "https://github.com/sebastianbergmann/diff.git", 957 | "reference": "366541b989927187c4ca70490a35615d3fef2dce" 958 | }, 959 | "dist": { 960 | "type": "zip", 961 | "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/366541b989927187c4ca70490a35615d3fef2dce", 962 | "reference": "366541b989927187c4ca70490a35615d3fef2dce", 963 | "shasum": "" 964 | }, 965 | "require": { 966 | "php": "^7.1" 967 | }, 968 | "require-dev": { 969 | "phpunit/phpunit": "^7.0", 970 | "symfony/process": "^2 || ^3.3 || ^4" 971 | }, 972 | "type": "library", 973 | "extra": { 974 | "branch-alias": { 975 | "dev-master": "3.0-dev" 976 | } 977 | }, 978 | "autoload": { 979 | "classmap": [ 980 | "src/" 981 | ] 982 | }, 983 | "notification-url": "https://packagist.org/downloads/", 984 | "license": [ 985 | "BSD-3-Clause" 986 | ], 987 | "authors": [ 988 | { 989 | "name": "Kore Nordmann", 990 | "email": "mail@kore-nordmann.de" 991 | }, 992 | { 993 | "name": "Sebastian Bergmann", 994 | "email": "sebastian@phpunit.de" 995 | } 996 | ], 997 | "description": "Diff implementation", 998 | "homepage": "https://github.com/sebastianbergmann/diff", 999 | "keywords": [ 1000 | "diff", 1001 | "udiff", 1002 | "unidiff", 1003 | "unified diff" 1004 | ], 1005 | "time": "2018-06-10T07:54:39+00:00" 1006 | }, 1007 | { 1008 | "name": "sebastian/environment", 1009 | "version": "3.1.0", 1010 | "source": { 1011 | "type": "git", 1012 | "url": "https://github.com/sebastianbergmann/environment.git", 1013 | "reference": "cd0871b3975fb7fc44d11314fd1ee20925fce4f5" 1014 | }, 1015 | "dist": { 1016 | "type": "zip", 1017 | "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/cd0871b3975fb7fc44d11314fd1ee20925fce4f5", 1018 | "reference": "cd0871b3975fb7fc44d11314fd1ee20925fce4f5", 1019 | "shasum": "" 1020 | }, 1021 | "require": { 1022 | "php": "^7.0" 1023 | }, 1024 | "require-dev": { 1025 | "phpunit/phpunit": "^6.1" 1026 | }, 1027 | "type": "library", 1028 | "extra": { 1029 | "branch-alias": { 1030 | "dev-master": "3.1.x-dev" 1031 | } 1032 | }, 1033 | "autoload": { 1034 | "classmap": [ 1035 | "src/" 1036 | ] 1037 | }, 1038 | "notification-url": "https://packagist.org/downloads/", 1039 | "license": [ 1040 | "BSD-3-Clause" 1041 | ], 1042 | "authors": [ 1043 | { 1044 | "name": "Sebastian Bergmann", 1045 | "email": "sebastian@phpunit.de" 1046 | } 1047 | ], 1048 | "description": "Provides functionality to handle HHVM/PHP environments", 1049 | "homepage": "http://www.github.com/sebastianbergmann/environment", 1050 | "keywords": [ 1051 | "Xdebug", 1052 | "environment", 1053 | "hhvm" 1054 | ], 1055 | "time": "2017-07-01T08:51:00+00:00" 1056 | }, 1057 | { 1058 | "name": "sebastian/exporter", 1059 | "version": "3.1.0", 1060 | "source": { 1061 | "type": "git", 1062 | "url": "https://github.com/sebastianbergmann/exporter.git", 1063 | "reference": "234199f4528de6d12aaa58b612e98f7d36adb937" 1064 | }, 1065 | "dist": { 1066 | "type": "zip", 1067 | "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/234199f4528de6d12aaa58b612e98f7d36adb937", 1068 | "reference": "234199f4528de6d12aaa58b612e98f7d36adb937", 1069 | "shasum": "" 1070 | }, 1071 | "require": { 1072 | "php": "^7.0", 1073 | "sebastian/recursion-context": "^3.0" 1074 | }, 1075 | "require-dev": { 1076 | "ext-mbstring": "*", 1077 | "phpunit/phpunit": "^6.0" 1078 | }, 1079 | "type": "library", 1080 | "extra": { 1081 | "branch-alias": { 1082 | "dev-master": "3.1.x-dev" 1083 | } 1084 | }, 1085 | "autoload": { 1086 | "classmap": [ 1087 | "src/" 1088 | ] 1089 | }, 1090 | "notification-url": "https://packagist.org/downloads/", 1091 | "license": [ 1092 | "BSD-3-Clause" 1093 | ], 1094 | "authors": [ 1095 | { 1096 | "name": "Jeff Welch", 1097 | "email": "whatthejeff@gmail.com" 1098 | }, 1099 | { 1100 | "name": "Volker Dusch", 1101 | "email": "github@wallbash.com" 1102 | }, 1103 | { 1104 | "name": "Bernhard Schussek", 1105 | "email": "bschussek@2bepublished.at" 1106 | }, 1107 | { 1108 | "name": "Sebastian Bergmann", 1109 | "email": "sebastian@phpunit.de" 1110 | }, 1111 | { 1112 | "name": "Adam Harvey", 1113 | "email": "aharvey@php.net" 1114 | } 1115 | ], 1116 | "description": "Provides the functionality to export PHP variables for visualization", 1117 | "homepage": "http://www.github.com/sebastianbergmann/exporter", 1118 | "keywords": [ 1119 | "export", 1120 | "exporter" 1121 | ], 1122 | "time": "2017-04-03T13:19:02+00:00" 1123 | }, 1124 | { 1125 | "name": "sebastian/global-state", 1126 | "version": "2.0.0", 1127 | "source": { 1128 | "type": "git", 1129 | "url": "https://github.com/sebastianbergmann/global-state.git", 1130 | "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4" 1131 | }, 1132 | "dist": { 1133 | "type": "zip", 1134 | "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4", 1135 | "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4", 1136 | "shasum": "" 1137 | }, 1138 | "require": { 1139 | "php": "^7.0" 1140 | }, 1141 | "require-dev": { 1142 | "phpunit/phpunit": "^6.0" 1143 | }, 1144 | "suggest": { 1145 | "ext-uopz": "*" 1146 | }, 1147 | "type": "library", 1148 | "extra": { 1149 | "branch-alias": { 1150 | "dev-master": "2.0-dev" 1151 | } 1152 | }, 1153 | "autoload": { 1154 | "classmap": [ 1155 | "src/" 1156 | ] 1157 | }, 1158 | "notification-url": "https://packagist.org/downloads/", 1159 | "license": [ 1160 | "BSD-3-Clause" 1161 | ], 1162 | "authors": [ 1163 | { 1164 | "name": "Sebastian Bergmann", 1165 | "email": "sebastian@phpunit.de" 1166 | } 1167 | ], 1168 | "description": "Snapshotting of global state", 1169 | "homepage": "http://www.github.com/sebastianbergmann/global-state", 1170 | "keywords": [ 1171 | "global state" 1172 | ], 1173 | "time": "2017-04-27T15:39:26+00:00" 1174 | }, 1175 | { 1176 | "name": "sebastian/object-enumerator", 1177 | "version": "3.0.3", 1178 | "source": { 1179 | "type": "git", 1180 | "url": "https://github.com/sebastianbergmann/object-enumerator.git", 1181 | "reference": "7cfd9e65d11ffb5af41198476395774d4c8a84c5" 1182 | }, 1183 | "dist": { 1184 | "type": "zip", 1185 | "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/7cfd9e65d11ffb5af41198476395774d4c8a84c5", 1186 | "reference": "7cfd9e65d11ffb5af41198476395774d4c8a84c5", 1187 | "shasum": "" 1188 | }, 1189 | "require": { 1190 | "php": "^7.0", 1191 | "sebastian/object-reflector": "^1.1.1", 1192 | "sebastian/recursion-context": "^3.0" 1193 | }, 1194 | "require-dev": { 1195 | "phpunit/phpunit": "^6.0" 1196 | }, 1197 | "type": "library", 1198 | "extra": { 1199 | "branch-alias": { 1200 | "dev-master": "3.0.x-dev" 1201 | } 1202 | }, 1203 | "autoload": { 1204 | "classmap": [ 1205 | "src/" 1206 | ] 1207 | }, 1208 | "notification-url": "https://packagist.org/downloads/", 1209 | "license": [ 1210 | "BSD-3-Clause" 1211 | ], 1212 | "authors": [ 1213 | { 1214 | "name": "Sebastian Bergmann", 1215 | "email": "sebastian@phpunit.de" 1216 | } 1217 | ], 1218 | "description": "Traverses array structures and object graphs to enumerate all referenced objects", 1219 | "homepage": "https://github.com/sebastianbergmann/object-enumerator/", 1220 | "time": "2017-08-03T12:35:26+00:00" 1221 | }, 1222 | { 1223 | "name": "sebastian/object-reflector", 1224 | "version": "1.1.1", 1225 | "source": { 1226 | "type": "git", 1227 | "url": "https://github.com/sebastianbergmann/object-reflector.git", 1228 | "reference": "773f97c67f28de00d397be301821b06708fca0be" 1229 | }, 1230 | "dist": { 1231 | "type": "zip", 1232 | "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/773f97c67f28de00d397be301821b06708fca0be", 1233 | "reference": "773f97c67f28de00d397be301821b06708fca0be", 1234 | "shasum": "" 1235 | }, 1236 | "require": { 1237 | "php": "^7.0" 1238 | }, 1239 | "require-dev": { 1240 | "phpunit/phpunit": "^6.0" 1241 | }, 1242 | "type": "library", 1243 | "extra": { 1244 | "branch-alias": { 1245 | "dev-master": "1.1-dev" 1246 | } 1247 | }, 1248 | "autoload": { 1249 | "classmap": [ 1250 | "src/" 1251 | ] 1252 | }, 1253 | "notification-url": "https://packagist.org/downloads/", 1254 | "license": [ 1255 | "BSD-3-Clause" 1256 | ], 1257 | "authors": [ 1258 | { 1259 | "name": "Sebastian Bergmann", 1260 | "email": "sebastian@phpunit.de" 1261 | } 1262 | ], 1263 | "description": "Allows reflection of object attributes, including inherited and non-public ones", 1264 | "homepage": "https://github.com/sebastianbergmann/object-reflector/", 1265 | "time": "2017-03-29T09:07:27+00:00" 1266 | }, 1267 | { 1268 | "name": "sebastian/recursion-context", 1269 | "version": "3.0.0", 1270 | "source": { 1271 | "type": "git", 1272 | "url": "https://github.com/sebastianbergmann/recursion-context.git", 1273 | "reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8" 1274 | }, 1275 | "dist": { 1276 | "type": "zip", 1277 | "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8", 1278 | "reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8", 1279 | "shasum": "" 1280 | }, 1281 | "require": { 1282 | "php": "^7.0" 1283 | }, 1284 | "require-dev": { 1285 | "phpunit/phpunit": "^6.0" 1286 | }, 1287 | "type": "library", 1288 | "extra": { 1289 | "branch-alias": { 1290 | "dev-master": "3.0.x-dev" 1291 | } 1292 | }, 1293 | "autoload": { 1294 | "classmap": [ 1295 | "src/" 1296 | ] 1297 | }, 1298 | "notification-url": "https://packagist.org/downloads/", 1299 | "license": [ 1300 | "BSD-3-Clause" 1301 | ], 1302 | "authors": [ 1303 | { 1304 | "name": "Jeff Welch", 1305 | "email": "whatthejeff@gmail.com" 1306 | }, 1307 | { 1308 | "name": "Sebastian Bergmann", 1309 | "email": "sebastian@phpunit.de" 1310 | }, 1311 | { 1312 | "name": "Adam Harvey", 1313 | "email": "aharvey@php.net" 1314 | } 1315 | ], 1316 | "description": "Provides functionality to recursively process PHP variables", 1317 | "homepage": "http://www.github.com/sebastianbergmann/recursion-context", 1318 | "time": "2017-03-03T06:23:57+00:00" 1319 | }, 1320 | { 1321 | "name": "sebastian/resource-operations", 1322 | "version": "1.0.0", 1323 | "source": { 1324 | "type": "git", 1325 | "url": "https://github.com/sebastianbergmann/resource-operations.git", 1326 | "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52" 1327 | }, 1328 | "dist": { 1329 | "type": "zip", 1330 | "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", 1331 | "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", 1332 | "shasum": "" 1333 | }, 1334 | "require": { 1335 | "php": ">=5.6.0" 1336 | }, 1337 | "type": "library", 1338 | "extra": { 1339 | "branch-alias": { 1340 | "dev-master": "1.0.x-dev" 1341 | } 1342 | }, 1343 | "autoload": { 1344 | "classmap": [ 1345 | "src/" 1346 | ] 1347 | }, 1348 | "notification-url": "https://packagist.org/downloads/", 1349 | "license": [ 1350 | "BSD-3-Clause" 1351 | ], 1352 | "authors": [ 1353 | { 1354 | "name": "Sebastian Bergmann", 1355 | "email": "sebastian@phpunit.de" 1356 | } 1357 | ], 1358 | "description": "Provides a list of PHP built-in functions that operate on resources", 1359 | "homepage": "https://www.github.com/sebastianbergmann/resource-operations", 1360 | "time": "2015-07-28T20:34:47+00:00" 1361 | }, 1362 | { 1363 | "name": "sebastian/version", 1364 | "version": "2.0.1", 1365 | "source": { 1366 | "type": "git", 1367 | "url": "https://github.com/sebastianbergmann/version.git", 1368 | "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019" 1369 | }, 1370 | "dist": { 1371 | "type": "zip", 1372 | "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/99732be0ddb3361e16ad77b68ba41efc8e979019", 1373 | "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019", 1374 | "shasum": "" 1375 | }, 1376 | "require": { 1377 | "php": ">=5.6" 1378 | }, 1379 | "type": "library", 1380 | "extra": { 1381 | "branch-alias": { 1382 | "dev-master": "2.0.x-dev" 1383 | } 1384 | }, 1385 | "autoload": { 1386 | "classmap": [ 1387 | "src/" 1388 | ] 1389 | }, 1390 | "notification-url": "https://packagist.org/downloads/", 1391 | "license": [ 1392 | "BSD-3-Clause" 1393 | ], 1394 | "authors": [ 1395 | { 1396 | "name": "Sebastian Bergmann", 1397 | "email": "sebastian@phpunit.de", 1398 | "role": "lead" 1399 | } 1400 | ], 1401 | "description": "Library that helps with managing the version number of Git-hosted PHP projects", 1402 | "homepage": "https://github.com/sebastianbergmann/version", 1403 | "time": "2016-10-03T07:35:21+00:00" 1404 | }, 1405 | { 1406 | "name": "squizlabs/php_codesniffer", 1407 | "version": "2.9.1", 1408 | "source": { 1409 | "type": "git", 1410 | "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", 1411 | "reference": "dcbed1074f8244661eecddfc2a675430d8d33f62" 1412 | }, 1413 | "dist": { 1414 | "type": "zip", 1415 | "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/dcbed1074f8244661eecddfc2a675430d8d33f62", 1416 | "reference": "dcbed1074f8244661eecddfc2a675430d8d33f62", 1417 | "shasum": "" 1418 | }, 1419 | "require": { 1420 | "ext-simplexml": "*", 1421 | "ext-tokenizer": "*", 1422 | "ext-xmlwriter": "*", 1423 | "php": ">=5.1.2" 1424 | }, 1425 | "require-dev": { 1426 | "phpunit/phpunit": "~4.0" 1427 | }, 1428 | "bin": [ 1429 | "scripts/phpcs", 1430 | "scripts/phpcbf" 1431 | ], 1432 | "type": "library", 1433 | "extra": { 1434 | "branch-alias": { 1435 | "dev-master": "2.x-dev" 1436 | } 1437 | }, 1438 | "autoload": { 1439 | "classmap": [ 1440 | "CodeSniffer.php", 1441 | "CodeSniffer/CLI.php", 1442 | "CodeSniffer/Exception.php", 1443 | "CodeSniffer/File.php", 1444 | "CodeSniffer/Fixer.php", 1445 | "CodeSniffer/Report.php", 1446 | "CodeSniffer/Reporting.php", 1447 | "CodeSniffer/Sniff.php", 1448 | "CodeSniffer/Tokens.php", 1449 | "CodeSniffer/Reports/", 1450 | "CodeSniffer/Tokenizers/", 1451 | "CodeSniffer/DocGenerators/", 1452 | "CodeSniffer/Standards/AbstractPatternSniff.php", 1453 | "CodeSniffer/Standards/AbstractScopeSniff.php", 1454 | "CodeSniffer/Standards/AbstractVariableSniff.php", 1455 | "CodeSniffer/Standards/IncorrectPatternException.php", 1456 | "CodeSniffer/Standards/Generic/Sniffs/", 1457 | "CodeSniffer/Standards/MySource/Sniffs/", 1458 | "CodeSniffer/Standards/PEAR/Sniffs/", 1459 | "CodeSniffer/Standards/PSR1/Sniffs/", 1460 | "CodeSniffer/Standards/PSR2/Sniffs/", 1461 | "CodeSniffer/Standards/Squiz/Sniffs/", 1462 | "CodeSniffer/Standards/Zend/Sniffs/" 1463 | ] 1464 | }, 1465 | "notification-url": "https://packagist.org/downloads/", 1466 | "license": [ 1467 | "BSD-3-Clause" 1468 | ], 1469 | "authors": [ 1470 | { 1471 | "name": "Greg Sherwood", 1472 | "role": "lead" 1473 | } 1474 | ], 1475 | "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", 1476 | "homepage": "http://www.squizlabs.com/php-codesniffer", 1477 | "keywords": [ 1478 | "phpcs", 1479 | "standards" 1480 | ], 1481 | "time": "2017-05-22T02:43:20+00:00" 1482 | }, 1483 | { 1484 | "name": "theseer/tokenizer", 1485 | "version": "1.1.0", 1486 | "source": { 1487 | "type": "git", 1488 | "url": "https://github.com/theseer/tokenizer.git", 1489 | "reference": "cb2f008f3f05af2893a87208fe6a6c4985483f8b" 1490 | }, 1491 | "dist": { 1492 | "type": "zip", 1493 | "url": "https://api.github.com/repos/theseer/tokenizer/zipball/cb2f008f3f05af2893a87208fe6a6c4985483f8b", 1494 | "reference": "cb2f008f3f05af2893a87208fe6a6c4985483f8b", 1495 | "shasum": "" 1496 | }, 1497 | "require": { 1498 | "ext-dom": "*", 1499 | "ext-tokenizer": "*", 1500 | "ext-xmlwriter": "*", 1501 | "php": "^7.0" 1502 | }, 1503 | "type": "library", 1504 | "autoload": { 1505 | "classmap": [ 1506 | "src/" 1507 | ] 1508 | }, 1509 | "notification-url": "https://packagist.org/downloads/", 1510 | "license": [ 1511 | "BSD-3-Clause" 1512 | ], 1513 | "authors": [ 1514 | { 1515 | "name": "Arne Blankerts", 1516 | "email": "arne@blankerts.de", 1517 | "role": "Developer" 1518 | } 1519 | ], 1520 | "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", 1521 | "time": "2017-04-07T12:08:54+00:00" 1522 | }, 1523 | { 1524 | "name": "webmozart/assert", 1525 | "version": "1.3.0", 1526 | "source": { 1527 | "type": "git", 1528 | "url": "https://github.com/webmozart/assert.git", 1529 | "reference": "0df1908962e7a3071564e857d86874dad1ef204a" 1530 | }, 1531 | "dist": { 1532 | "type": "zip", 1533 | "url": "https://api.github.com/repos/webmozart/assert/zipball/0df1908962e7a3071564e857d86874dad1ef204a", 1534 | "reference": "0df1908962e7a3071564e857d86874dad1ef204a", 1535 | "shasum": "" 1536 | }, 1537 | "require": { 1538 | "php": "^5.3.3 || ^7.0" 1539 | }, 1540 | "require-dev": { 1541 | "phpunit/phpunit": "^4.6", 1542 | "sebastian/version": "^1.0.1" 1543 | }, 1544 | "type": "library", 1545 | "extra": { 1546 | "branch-alias": { 1547 | "dev-master": "1.3-dev" 1548 | } 1549 | }, 1550 | "autoload": { 1551 | "psr-4": { 1552 | "Webmozart\\Assert\\": "src/" 1553 | } 1554 | }, 1555 | "notification-url": "https://packagist.org/downloads/", 1556 | "license": [ 1557 | "MIT" 1558 | ], 1559 | "authors": [ 1560 | { 1561 | "name": "Bernhard Schussek", 1562 | "email": "bschussek@gmail.com" 1563 | } 1564 | ], 1565 | "description": "Assertions to validate method input/output with nice error messages.", 1566 | "keywords": [ 1567 | "assert", 1568 | "check", 1569 | "validate" 1570 | ], 1571 | "time": "2018-01-29T19:49:41+00:00" 1572 | }, 1573 | { 1574 | "name": "zendframework/zend-coding-standard", 1575 | "version": "1.0.0", 1576 | "source": { 1577 | "type": "git", 1578 | "url": "https://github.com/zendframework/zend-coding-standard.git", 1579 | "reference": "893316d2904e93f1c74c1384b6d7d57778299cb6" 1580 | }, 1581 | "dist": { 1582 | "type": "zip", 1583 | "url": "https://api.github.com/repos/zendframework/zend-coding-standard/zipball/893316d2904e93f1c74c1384b6d7d57778299cb6", 1584 | "reference": "893316d2904e93f1c74c1384b6d7d57778299cb6", 1585 | "shasum": "" 1586 | }, 1587 | "require": { 1588 | "squizlabs/php_codesniffer": "^2.7" 1589 | }, 1590 | "type": "library", 1591 | "notification-url": "https://packagist.org/downloads/", 1592 | "license": [ 1593 | "BSD-3-Clause" 1594 | ], 1595 | "description": "Zend Framework coding standard", 1596 | "keywords": [ 1597 | "Coding Standard", 1598 | "zf" 1599 | ], 1600 | "time": "2016-11-09T21:30:43+00:00" 1601 | }, 1602 | { 1603 | "name": "zendframework/zend-stdlib", 1604 | "version": "3.2.0", 1605 | "source": { 1606 | "type": "git", 1607 | "url": "https://github.com/zendframework/zend-stdlib.git", 1608 | "reference": "cd164b4a18b5d1aeb69be2c26db035b5ed6925ae" 1609 | }, 1610 | "dist": { 1611 | "type": "zip", 1612 | "url": "https://api.github.com/repos/zendframework/zend-stdlib/zipball/cd164b4a18b5d1aeb69be2c26db035b5ed6925ae", 1613 | "reference": "cd164b4a18b5d1aeb69be2c26db035b5ed6925ae", 1614 | "shasum": "" 1615 | }, 1616 | "require": { 1617 | "php": "^5.6 || ^7.0" 1618 | }, 1619 | "require-dev": { 1620 | "phpbench/phpbench": "^0.13", 1621 | "phpunit/phpunit": "^5.7.27 || ^6.5.8 || ^7.1.2", 1622 | "zendframework/zend-coding-standard": "~1.0.0" 1623 | }, 1624 | "type": "library", 1625 | "extra": { 1626 | "branch-alias": { 1627 | "dev-master": "3.2.x-dev", 1628 | "dev-develop": "3.3.x-dev" 1629 | } 1630 | }, 1631 | "autoload": { 1632 | "psr-4": { 1633 | "Zend\\Stdlib\\": "src/" 1634 | } 1635 | }, 1636 | "notification-url": "https://packagist.org/downloads/", 1637 | "license": [ 1638 | "BSD-3-Clause" 1639 | ], 1640 | "description": "SPL extensions, array utilities, error handlers, and more", 1641 | "keywords": [ 1642 | "ZendFramework", 1643 | "stdlib", 1644 | "zf" 1645 | ], 1646 | "time": "2018-04-30T13:50:40+00:00" 1647 | }, 1648 | { 1649 | "name": "zendframework/zend-validator", 1650 | "version": "2.10.2", 1651 | "source": { 1652 | "type": "git", 1653 | "url": "https://github.com/zendframework/zend-validator.git", 1654 | "reference": "38109ed7d8e46cfa71bccbe7e6ca80cdd035f8c9" 1655 | }, 1656 | "dist": { 1657 | "type": "zip", 1658 | "url": "https://api.github.com/repos/zendframework/zend-validator/zipball/38109ed7d8e46cfa71bccbe7e6ca80cdd035f8c9", 1659 | "reference": "38109ed7d8e46cfa71bccbe7e6ca80cdd035f8c9", 1660 | "shasum": "" 1661 | }, 1662 | "require": { 1663 | "container-interop/container-interop": "^1.1", 1664 | "php": "^5.6 || ^7.0", 1665 | "zendframework/zend-stdlib": "^2.7.6 || ^3.1" 1666 | }, 1667 | "require-dev": { 1668 | "phpunit/phpunit": "^6.0.8 || ^5.7.15", 1669 | "zendframework/zend-cache": "^2.6.1", 1670 | "zendframework/zend-coding-standard": "~1.0.0", 1671 | "zendframework/zend-config": "^2.6", 1672 | "zendframework/zend-db": "^2.7", 1673 | "zendframework/zend-filter": "^2.6", 1674 | "zendframework/zend-http": "^2.5.4", 1675 | "zendframework/zend-i18n": "^2.6", 1676 | "zendframework/zend-math": "^2.6", 1677 | "zendframework/zend-servicemanager": "^2.7.5 || ^3.0.3", 1678 | "zendframework/zend-session": "^2.8", 1679 | "zendframework/zend-uri": "^2.5" 1680 | }, 1681 | "suggest": { 1682 | "zendframework/zend-db": "Zend\\Db component, required by the (No)RecordExists validator", 1683 | "zendframework/zend-filter": "Zend\\Filter component, required by the Digits validator", 1684 | "zendframework/zend-i18n": "Zend\\I18n component to allow translation of validation error messages", 1685 | "zendframework/zend-i18n-resources": "Translations of validator messages", 1686 | "zendframework/zend-math": "Zend\\Math component, required by the Csrf validator", 1687 | "zendframework/zend-servicemanager": "Zend\\ServiceManager component to allow using the ValidatorPluginManager and validator chains", 1688 | "zendframework/zend-session": "Zend\\Session component, ^2.8; required by the Csrf validator", 1689 | "zendframework/zend-uri": "Zend\\Uri component, required by the Uri and Sitemap\\Loc validators" 1690 | }, 1691 | "type": "library", 1692 | "extra": { 1693 | "branch-alias": { 1694 | "dev-master": "2.10.x-dev", 1695 | "dev-develop": "2.11.x-dev" 1696 | }, 1697 | "zf": { 1698 | "component": "Zend\\Validator", 1699 | "config-provider": "Zend\\Validator\\ConfigProvider" 1700 | } 1701 | }, 1702 | "autoload": { 1703 | "psr-4": { 1704 | "Zend\\Validator\\": "src/" 1705 | } 1706 | }, 1707 | "notification-url": "https://packagist.org/downloads/", 1708 | "license": [ 1709 | "BSD-3-Clause" 1710 | ], 1711 | "description": "provides a set of commonly needed validators", 1712 | "homepage": "https://github.com/zendframework/zend-validator", 1713 | "keywords": [ 1714 | "validator", 1715 | "zf2" 1716 | ], 1717 | "time": "2018-02-01T17:05:33+00:00" 1718 | } 1719 | ], 1720 | "aliases": [], 1721 | "minimum-stability": "stable", 1722 | "stability-flags": [], 1723 | "prefer-stable": false, 1724 | "prefer-lowest": false, 1725 | "platform": { 1726 | "php": "^7.1" 1727 | }, 1728 | "platform-dev": [] 1729 | } 1730 | -------------------------------------------------------------------------------- /src/AbstractValidator.php: -------------------------------------------------------------------------------- 1 | getMessageTemplate($key), 46 | $this->messageVariables 47 | ); 48 | }, $messageKeys); 49 | 50 | return Result::createInvalidResult($value, $messages); 51 | } 52 | 53 | /** 54 | * Returns the message templates from the validator 55 | * 56 | * @return string[] 57 | */ 58 | public function getMessageTemplates() : array 59 | { 60 | return $this->messageTemplates; 61 | } 62 | 63 | /** 64 | * Sets the validation failure message template for a particular key 65 | */ 66 | public function setMessageTemplate(string $messageKey, string $messageString) : void 67 | { 68 | $this->messageTemplates[$messageKey] = $messageString; 69 | } 70 | 71 | /** 72 | * Finds and returns the message template associated with the given message key. 73 | */ 74 | protected function getMessageTemplate(string $messageKey) : string 75 | { 76 | return $this->messageTemplates[$messageKey] ?? ''; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/Barcode.php: -------------------------------------------------------------------------------- 1 | "The input failed checksum validation", 29 | self::INVALID_CHARS => "The input contains invalid characters", 30 | self::INVALID_LENGTH => "The input should have a length of %length% characters", 31 | self::INVALID => "Invalid type given. String expected", 32 | ]; 33 | 34 | /** 35 | * @var AdapterInterface 36 | */ 37 | private $adapter; 38 | 39 | public function __construct(AdapterInterface $adapter) 40 | { 41 | $this->adapter = $adapter; 42 | 43 | $this->messageVariables = [ 44 | 'length' => null, 45 | ]; 46 | } 47 | 48 | /** 49 | * Returns the set adapter 50 | * 51 | * @return AdapterInterface 52 | */ 53 | public function getAdapter() : AdapterInterface 54 | { 55 | return $this->adapter; 56 | } 57 | 58 | /** 59 | * Validate the value is a correct barcode. 60 | * 61 | * @return ResultInterface 62 | */ 63 | public function validate($value, $context = null) : ResultInterface 64 | { 65 | if (! is_string($value)) { 66 | return $this->createInvalidResult($value, [self::INVALID]); 67 | } 68 | 69 | $adapter = $this->getAdapter(); 70 | if (! $adapter->hasValidLength($value)) { 71 | $this->messageVariables['length'] = $this->getAllowedLength($adapter); 72 | return $this->createInvalidResult($value, [self::INVALID_LENGTH]); 73 | } 74 | 75 | if (! $adapter->hasValidCharacters($value)) { 76 | return $this->createInvalidResult($value, [self::INVALID_CHARS]); 77 | } 78 | 79 | if ($adapter instanceof Barcode\ChecksummableInterface 80 | && $adapter->useChecksum($value) 81 | && ! $adapter->hasValidChecksum($value) 82 | ) { 83 | return $this->createInvalidResult($value, [self::FAILED]); 84 | } 85 | 86 | return Result::createValidResult($value); 87 | } 88 | 89 | /** 90 | * @return int|string If the adapter returns an array of values for the 91 | * length, they will be imploded with a "/" character and returned 92 | * as a string. 93 | */ 94 | private function getAllowedLength(AdapterInterface $adapter) 95 | { 96 | $length = $adapter->getLength(); 97 | if (! is_array($length)) { 98 | return $length; 99 | } 100 | 101 | return implode('/', $length); 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/Barcode/AbstractAdapter.php: -------------------------------------------------------------------------------- 1 | getLength(); 33 | 34 | if ($allowedLength === -1) { 35 | return true; 36 | } 37 | 38 | $valueLength = strlen($value); 39 | 40 | if ($valueLength === $allowedLength) { 41 | return true; 42 | } 43 | 44 | if ($allowedLength === 'even') { 45 | $count = $valueLength % 2; 46 | return 0 === $count; 47 | } 48 | 49 | if ($allowedLength === 'odd') { 50 | $count = $valueLength % 2; 51 | return 1 === $count; 52 | } 53 | 54 | if (is_array($allowedLength)) { 55 | return array_reduce($allowedLength, function ($allowed, $test) use ($valueLength) { 56 | return $allowed 57 | || $test === -1 58 | || $valueLength === $test; 59 | }, false); 60 | } 61 | 62 | return false; 63 | } 64 | 65 | /** 66 | * Checks for allowed characters within the barcode 67 | */ 68 | public function hasValidCharacters(string $value) : bool 69 | { 70 | $characters = $this->getCharacters(); 71 | $value = $characters === 128 72 | ? $this->replaceViaChr($value) 73 | : $this->replaceViaCharMap($value, (string) $characters); 74 | 75 | return strlen($value) === 0; 76 | } 77 | 78 | /** 79 | * Returns the allowed barcode length 80 | * 81 | * @return int|string|array 82 | */ 83 | public function getLength() 84 | { 85 | return $this->length; 86 | } 87 | 88 | /** 89 | * Returns the allowed characters 90 | * 91 | * @return int 92 | */ 93 | public function getCharacters() 94 | { 95 | return $this->characters; 96 | } 97 | 98 | /** 99 | * Sets the length of this barcode 100 | * 101 | * @param int|string|array $length 102 | */ 103 | protected function setLength($length) : void 104 | { 105 | $this->length = $length; 106 | } 107 | 108 | /** 109 | * Sets the allowed characters of this barcode 110 | * 111 | * @param int|array|string $characters 112 | */ 113 | protected function setCharacters($characters) : void 114 | { 115 | $this->characters = $characters; 116 | } 117 | 118 | private function replaceViaChr(string $value) : string 119 | { 120 | for ($x = 0; $x < 128; $x += 1) { 121 | $value = str_replace(chr($x), '', $value); 122 | } 123 | return $value; 124 | } 125 | 126 | private function replaceViaCharMap(string $value, string $characters) : string 127 | { 128 | foreach (str_split($characters) as $char) { 129 | $value = str_replace($char, '', $value); 130 | } 131 | return $value; 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /src/Barcode/AdapterInterface.php: -------------------------------------------------------------------------------- 1 | useChecksum; 35 | } 36 | 37 | /** 38 | * Whether or not the checksum of the value is valid. 39 | * 40 | * @param mixed $value 41 | */ 42 | public function hasValidChecksum(string $value) : bool 43 | { 44 | if (! is_callable($this->checksumCallback)) { 45 | return false; 46 | } 47 | 48 | $validator = $this->checksumCallback; 49 | 50 | return $validator($value); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/Barcode/ChecksummableInterface.php: -------------------------------------------------------------------------------- 1 | setLength(-1); 20 | $this->setCharacters('0123456789-$:/.+ABCDTN*E'); 21 | } 22 | 23 | /** 24 | * Checks for allowed characters 25 | * @see Zend\DataValidator\Barcode\AbstractAdapter::checkChars() 26 | */ 27 | public function hasValidCharacters(string $value) : bool 28 | { 29 | if (strpbrk($value, 'ABCD')) { 30 | $first = $value[0]; 31 | if (! strpbrk($first, 'ABCD')) { 32 | // Missing start char 33 | return false; 34 | } 35 | 36 | $last = substr($value, -1, 1); 37 | if (! strpbrk($last, 'ABCD')) { 38 | // Missing stop char 39 | return false; 40 | } 41 | 42 | $value = substr($value, 1, -1); 43 | } elseif (strpbrk($value, 'TN*E')) { 44 | $first = $value[0]; 45 | if (! strpbrk($first, 'TN*E')) { 46 | // Missing start char 47 | return false; 48 | } 49 | 50 | $last = substr($value, -1, 1); 51 | if (! strpbrk($last, 'TN*E')) { 52 | // Missing stop char 53 | return false; 54 | } 55 | 56 | $value = substr($value, 1, -1); 57 | } 58 | 59 | $chars = $this->getCharacters(); 60 | $this->setCharacters('0123456789-$:/.+'); 61 | $result = parent::hasValidCharacters($value); 62 | $this->setCharacters($chars); 63 | return $result; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/Barcode/Code128.php: -------------------------------------------------------------------------------- 1 | useChecksum = $useChecksum; 33 | $this->checksumCallback = [$this, 'validateCode128Checksum']; 34 | 35 | if ($utf8StringWrapper && ! $utf8StringWrapper->isSupported('UTF-8')) { 36 | throw new Exception\InvalidArgumentException( 37 | 'The string wrapper needs to support UTF-8 character encoding' 38 | ); 39 | } 40 | $this->utf8StringWrapper = $utf8StringWrapper ?: StringUtils::getWrapper('UTF-8'); 41 | 42 | $this->setLength(-1); 43 | $this->setCharacters([ 44 | 'A' => [ 45 | 0 => ' ', 1 => '!', 2 => '"', 3 => '#', 4 => '$', 5 => '%', 6 => '&', 7 => "'", 46 | 8 => '(', 9 => ')', 10 => '*', 11 => '+', 12 => ',', 13 => '-', 14 => '.', 15 => '/', 47 | 16 => '0', 17 => '1', 18 => '2', 19 => '3', 20 => '4', 21 => '5', 22 => '6', 23 => '7', 48 | 24 => '8', 25 => '9', 26 => ':', 27 => ';', 28 => '<', 29 => '=', 30 => '>', 31 => '?', 49 | 32 => '@', 33 => 'A', 34 => 'B', 35 => 'C', 36 => 'D', 37 => 'E', 38 => 'F', 39 => 'G', 50 | 40 => 'H', 41 => 'I', 42 => 'J', 43 => 'K', 44 => 'L', 45 => 'M', 46 => 'N', 47 => 'O', 51 | 48 => 'P', 49 => 'Q', 50 => 'R', 51 => 'S', 52 => 'T', 53 => 'U', 54 => 'V', 55 => 'W', 52 | 56 => 'X', 57 => 'Y', 58 => 'Z', 59 => '[', 60 => '\\', 61 => ']', 62 => '^', 63 => '_', 53 | 64 => 0x00, 65 => 0x01, 66 => 0x02, 67 => 0x03, 68 => 0x04, 69 => 0x05, 70 => 0x06, 71 => 0x07, 54 | 72 => 0x08, 73 => 0x09, 74 => 0x0A, 75 => 0x0B, 76 => 0x0C, 77 => 0x0D, 78 => 0x0E, 79 => 0x0F, 55 | 80 => 0x10, 81 => 0x11, 82 => 0x12, 83 => 0x13, 84 => 0x14, 85 => 0x15, 86 => 0x16, 87 => 0x17, 56 | 88 => 0x18, 89 => 0x19, 90 => 0x1A, 91 => 0x1B, 92 => 0x1C, 93 => 0x1D, 94 => 0x1E, 95 => 0x1F, 57 | 96 => 'Ç', 97 => 'ü', 98 => 'é', 99 => 'â', 100 => 'ä', 101 => 'à', 102 => 'å', 103 => '‡', 58 | 104 => 'ˆ', 105 => '‰', 106 => 'Š'], 59 | 'B' => [ 60 | 0 => ' ', 1 => '!', 2 => '"', 3 => '#', 4 => '$', 5 => '%', 6 => '&', 7 => "'", 61 | 8 => '(', 9 => ')', 10 => '*', 11 => '+', 12 => ',', 13 => '-', 14 => '.', 15 => '/', 62 | 16 => '0', 17 => '1', 18 => '2', 19 => '3', 20 => '4', 21 => '5', 22 => '6', 23 => '7', 63 | 24 => '8', 25 => '9', 26 => ':', 27 => ';', 28 => '<', 29 => '=', 30 => '>', 31 => '?', 64 | 32 => '@', 33 => 'A', 34 => 'B', 35 => 'C', 36 => 'D', 37 => 'E', 38 => 'F', 39 => 'G', 65 | 40 => 'H', 41 => 'I', 42 => 'J', 43 => 'K', 44 => 'L', 45 => 'M', 46 => 'N', 47 => 'O', 66 | 48 => 'P', 49 => 'Q', 50 => 'R', 51 => 'S', 52 => 'T', 53 => 'U', 54 => 'V', 55 => 'W', 67 | 56 => 'X', 57 => 'Y', 58 => 'Z', 59 => '[', 60 => '\\', 61 => ']', 62 => '^', 63 => '_', 68 | 64 => '`', 65 => 'a', 66 => 'b', 67 => 'c', 68 => 'd', 69 => 'e', 70 => 'f', 71 => 'g', 69 | 72 => 'h', 73 => 'i', 74 => 'j', 75 => 'k', 76 => 'l', 77 => 'm', 78 => 'n', 79 => 'o', 70 | 80 => 'p', 81 => 'q', 82 => 'r', 83 => 's', 84 => 't', 85 => 'u', 86 => 'v', 87 => 'w', 71 | 88 => 'x', 89 => 'y', 90 => 'z', 91 => '{', 92 => '|', 93 => '}', 94 => '~', 95 => 0x7F, 72 | 96 => 'Ç', 97 => 'ü', 98 => 'é', 99 => 'â', 100 => 'ä', 101 => 'à', 102 => 'å', 103 => '‡', 73 | 104 => 'ˆ', 105 => '‰', 106 => 'Š'], 74 | 'C' => [ 75 | 0 => '00', 1 => '01', 2 => '02', 3 => '03', 4 => '04', 5 => '05', 6 => '06', 7 => '07', 76 | 8 => '08', 9 => '09', 10 => '10', 11 => '11', 12 => '12', 13 => '13', 14 => '14', 15 => '15', 77 | 16 => '16', 17 => '17', 18 => '18', 19 => '19', 20 => '20', 21 => '21', 22 => '22', 23 => '23', 78 | 24 => '24', 25 => '25', 26 => '26', 27 => '27', 28 => '28', 29 => '29', 30 => '30', 31 => '31', 79 | 32 => '32', 33 => '33', 34 => '34', 35 => '35', 36 => '36', 37 => '37', 38 => '38', 39 => '39', 80 | 40 => '40', 41 => '41', 42 => '42', 43 => '43', 44 => '44', 45 => '45', 46 => '46', 47 => '47', 81 | 48 => '48', 49 => '49', 50 => '50', 51 => '51', 52 => '52', 53 => '53', 54 => '54', 55 => '55', 82 | 56 => '56', 57 => '57', 58 => '58', 59 => '59', 60 => '60', 61 => '61', 62 => '62', 63 => '63', 83 | 64 => '64', 65 => '65', 66 => '66', 67 => '67', 68 => '68', 69 => '69', 70 => '70', 71 => '71', 84 | 72 => '72', 73 => '73', 74 => '74', 75 => '75', 76 => '76', 77 => '77', 78 => '78', 79 => '79', 85 | 80 => '80', 81 => '81', 82 => '82', 83 => '83', 84 => '84', 85 => '85', 86 => '86', 87 => '87', 86 | 88 => '88', 89 => '89', 90 => '90', 91 => '91', 92 => '92', 93 => '93', 94 => '94', 95 => '95', 87 | 96 => '96', 97 => '97', 98 => '98', 99 => '99', 100 => 'ä', 101 => 'à', 102 => 'å', 103 => '‡', 88 | 104 => 'ˆ', 105 => '‰', 106 => 'Š'] 89 | ]); 90 | } 91 | 92 | public function setUtf8StringWrapper(StringWrapperInterface $utf8StringWrapper) : void 93 | { 94 | if (! $utf8StringWrapper->isSupported('UTF-8')) { 95 | throw new Exception\InvalidArgumentException( 96 | "The string wrapper needs to support UTF-8 character encoding" 97 | ); 98 | } 99 | $this->utf8StringWrapper = $utf8StringWrapper; 100 | } 101 | 102 | /** 103 | * Checks for allowed characters within the barcode 104 | * 105 | * @param string $value The barcode to check for allowed characters. If 106 | * not a string, the method returns false immediately. 107 | * @return bool 108 | */ 109 | public function hasValidCharacters($value) : bool 110 | { 111 | if (! is_string($value)) { 112 | return false; 113 | } 114 | 115 | // detect starting charset 116 | $set = $this->getCodingSet($value); 117 | $read = $set; 118 | $value = $set === '' ? $value : $this->utf8StringWrapper->substr($value, 1, null); 119 | 120 | // process barcode 121 | while ($value !== '') { 122 | $char = $this->utf8StringWrapper->substr($value, 0, 1); 123 | 124 | switch ($char) { 125 | // Function definition 126 | case 'Ç': 127 | case 'ü': 128 | case 'å': 129 | break; 130 | 131 | // Switch 1 char between A and B 132 | case 'é': 133 | if ($set === 'A') { 134 | $read = 'B'; 135 | break; 136 | } 137 | 138 | if ($set === 'B') { 139 | $read = 'A'; 140 | break; 141 | } 142 | 143 | break; 144 | 145 | // Switch to C 146 | case 'â': 147 | $set = 'C'; 148 | $read = 'C'; 149 | break; 150 | 151 | // Switch to B 152 | case 'ä': 153 | $set = 'B'; 154 | $read = 'B'; 155 | break; 156 | 157 | // Switch to A 158 | case 'à': 159 | $set = 'A'; 160 | $read = 'A'; 161 | break; 162 | 163 | // Doubled start character 164 | case '‡': 165 | case 'ˆ': 166 | case '‰': 167 | return false; 168 | 169 | // Chars after the stop character 170 | case 'Š': 171 | break 2; 172 | 173 | default: 174 | // Does the char exist within the charset to read? 175 | if ($this->ord128($char, $read) === -1) { 176 | return false; 177 | } 178 | 179 | break; 180 | } 181 | 182 | $value = $this->utf8StringWrapper->substr($value, 1, null); 183 | $value = $value === false ? '' : $value; 184 | $read = $set; 185 | } 186 | 187 | return $value === '' || $this->utf8StringWrapper->strlen($value) === 1; 188 | } 189 | 190 | /** 191 | * Validates the checksum 192 | */ 193 | private function validateCode128Checksum(string $value) : bool 194 | { 195 | $sum = 0; 196 | $pos = 1; 197 | $set = $this->getCodingSet($value); 198 | $read = $set; 199 | $char = $this->utf8StringWrapper->substr($value, 0, 1); 200 | 201 | if ($char === '‡') { 202 | $sum = 103; 203 | } elseif ($char === 'ˆ') { 204 | $sum = 104; 205 | } elseif ($char === '‰') { 206 | $sum = 105; 207 | } elseif ($this->useChecksum === true) { 208 | // no start value, unable to detect a proper checksum 209 | return false; 210 | } 211 | 212 | $value = $this->utf8StringWrapper->substr($value, 1, null); 213 | $value = $value === false ? '' : $value; 214 | while ($this->utf8StringWrapper->strpos($value, 'Š') || $value !== '') { 215 | $char = $this->utf8StringWrapper->substr($value, 0, 1); 216 | if ($read === 'C') { 217 | $char = $this->utf8StringWrapper->substr($value, 0, 2); 218 | } 219 | 220 | switch ($char) { 221 | // Function definition 222 | case 'Ç': 223 | case 'ü': 224 | case 'å': 225 | $sum += ($pos * $this->ord128($char, $set)); 226 | break; 227 | 228 | case 'é': 229 | $sum += ($pos * $this->ord128($char, $set)); 230 | if ($set === 'A') { 231 | $read = 'B'; 232 | break; 233 | } 234 | 235 | if ($set === 'B') { 236 | $read = 'A'; 237 | break; 238 | } 239 | 240 | break; 241 | 242 | // Switch to C 243 | case 'â': 244 | $sum += ($pos * $this->ord128($char, $set)); 245 | $set = 'C'; 246 | $read = 'C'; 247 | break; 248 | 249 | // Switch to B 250 | case 'ä': 251 | $sum += ($pos * $this->ord128($char, $set)); 252 | $set = 'B'; 253 | $read = 'B'; 254 | break; 255 | 256 | // Switch to A 257 | case 'à': 258 | $sum += ($pos * $this->ord128($char, $set)); 259 | $set = 'A'; 260 | $read = 'A'; 261 | break; 262 | 263 | // Duplicated start value detected 264 | case '‡': 265 | case 'ˆ': 266 | case '‰': 267 | return false; 268 | 269 | default: 270 | // Does the char exist within the charset to read? 271 | if ($this->ord128($char, $read) == -1) { 272 | return false; 273 | } 274 | 275 | $sum += ($pos * $this->ord128($char, $set)); 276 | break; 277 | } 278 | 279 | $value = $this->utf8StringWrapper->substr($value, 1); 280 | $value = $value === false ? '' : $value; 281 | $pos += 1; 282 | 283 | if ($this->utf8StringWrapper->strpos($value, 'Š') === 1 284 | && $this->utf8StringWrapper->strlen($value) === 2 285 | ) { 286 | // break by stop and checksum char 287 | break; 288 | } 289 | 290 | $read = $set; 291 | } 292 | 293 | if ($this->utf8StringWrapper->strpos($value, 'Š') !== 1 294 | || $this->utf8StringWrapper->strlen($value) !== 2 295 | ) { 296 | // return false if checksum is not readable and true if no 297 | // startvalue is detected 298 | return ! $this->useChecksum; 299 | } 300 | 301 | $mod = $sum % 103; 302 | return $this->utf8StringWrapper->substr($value, 0, 1) === $this->chr128($mod, $set); 303 | } 304 | 305 | /** 306 | * Returns the coding set for a barcode 307 | */ 308 | private function getCodingSet(string $value) : string 309 | { 310 | $value = $this->utf8StringWrapper->substr($value, 0, 1); 311 | switch ($value) { 312 | case '‡': 313 | return 'A'; 314 | case 'ˆ': 315 | return 'B'; 316 | case '‰': 317 | return 'C'; 318 | default: 319 | return ''; 320 | } 321 | } 322 | 323 | /** 324 | * Internal method to return the code128 integer from an ascii value 325 | * 326 | * Table A 327 | * ASCII CODE128 328 | * 32 to 95 == 0 to 63 329 | * 0 to 31 == 64 to 95 330 | * 128 to 138 == 96 to 106 331 | * 332 | * Table B 333 | * ASCII CODE128 334 | * 32 to 138 == 0 to 106 335 | * 336 | * Table C 337 | * ASCII CODE128 338 | * "00" to "99" == 0 to 99 339 | * 132 to 138 == 100 to 106 340 | */ 341 | private function ord128(string $value, string $set) : int 342 | { 343 | $ord = ord($value); 344 | 345 | if ($set === 'B') { 346 | if ($ord < 32) { 347 | return -1; 348 | } 349 | 350 | if ($ord <= 138) { 351 | return ($ord - 32); 352 | } 353 | 354 | return -1; 355 | } 356 | 357 | if ($set === 'C') { 358 | $val = (int) $value; 359 | 360 | if ($val >= 0 && $val <= 99) { 361 | return $val; 362 | } 363 | 364 | if ($ord >= 132 && $ord <= 138) { 365 | return ($ord - 32); 366 | } 367 | 368 | return -1; 369 | } 370 | 371 | // Set A (default) 372 | if ($ord < 32) { 373 | return ($ord + 64); 374 | } 375 | 376 | if ($ord > 138) { 377 | return -1; 378 | } 379 | 380 | return ($ord - 32); 381 | } 382 | 383 | /** 384 | * Internal Method to return the ascii value from a code128 integer 385 | * 386 | * Table A 387 | * ASCII CODE128 388 | * 32 to 95 == 0 to 63 389 | * 0 to 31 == 64 to 95 390 | * 128 to 138 == 96 to 106 391 | * 392 | * Table B 393 | * ASCII CODE128 394 | * 32 to 138 == 0 to 106 395 | * 396 | * Table C 397 | * ASCII CODE128 398 | * "00" to "99" == 0 to 99 399 | * 132 to 138 == 100 to 106 400 | */ 401 | private function chr128(int $value, string $set) : string 402 | { 403 | if ($set === 'A') { 404 | if ($value < 64) { 405 | return chr($value + 32); 406 | } 407 | 408 | if ($value < 96) { 409 | return chr($value - 64); 410 | } 411 | 412 | if ($value > 106) { 413 | return -1; 414 | } 415 | 416 | return chr($value + 32); 417 | } 418 | 419 | if ($set === 'B') { 420 | if ($value > 106) { 421 | return -1; 422 | } 423 | 424 | return chr($value + 32); 425 | } 426 | 427 | if ($set === 'C') { 428 | if ($value >= 0 && $value <= 9) { 429 | return '0' . (string) $value; 430 | } 431 | 432 | if ($value <= 99) { 433 | return (string) $value; 434 | } 435 | 436 | if ($value <= 106) { 437 | return chr($value + 32); 438 | } 439 | 440 | return -1; 441 | } 442 | 443 | // Default 444 | if ($value <= 106) { 445 | return ($value + 32); 446 | } 447 | 448 | return -1; 449 | } 450 | } 451 | -------------------------------------------------------------------------------- /src/Barcode/Code25.php: -------------------------------------------------------------------------------- 1 | useChecksum = $useChecksum; 23 | $this->checksumCallback = [$this, 'validateCode25Checksum']; 24 | $this->setLength(-1); 25 | $this->setCharacters('0123456789'); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Barcode/Code25ChecksumTrait.php: -------------------------------------------------------------------------------- 1 | useChecksum = $useChecksum; 25 | $this->checksumCallback = [$this, 'validateCode25Checksum']; 26 | $this->setLength('even'); 27 | $this->setCharacters('0123456789'); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Barcode/Code39.php: -------------------------------------------------------------------------------- 1 | checksumCallback = [$this, 'validateCode39Checksum']; 23 | $this->useChecksum = $useChecksum; 24 | $this->setLength(-1); 25 | $this->setCharacters('0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ -.$/+%'); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Barcode/Code39ChecksumTrait.php: -------------------------------------------------------------------------------- 1 | 0, '1' => 1, '2' => 2, '3' => 3, '4' => 4, '5' => 5, '6' => 6, 19 | '7' => 7, '8' => 8, '9' => 9, 'A' => 10, 'B' => 11, 'C' => 12, 'D' => 13, 20 | 'E' => 14, 'F' => 15, 'G' => 16, 'H' => 17, 'I' => 18, 'J' => 19, 'K' => 20, 21 | 'L' => 21, 'M' => 22, 'N' => 23, 'O' => 24, 'P' => 25, 'Q' => 26, 'R' => 27, 22 | 'S' => 28, 'T' => 29, 'U' => 30, 'V' => 31, 'W' => 32, 'X' => 33, 'Y' => 34, 23 | 'Z' => 35, '-' => 36, '.' => 37, ' ' => 38, '$' => 39, '/' => 40, '+' => 41, 24 | '%' => 42, 25 | ]; 26 | 27 | /** 28 | * Validates the checksum (Modulo 43) 29 | */ 30 | private function validateCode39Checksum(string $value) : bool 31 | { 32 | $checksum = substr($value, -1, 1); 33 | $value = str_split(substr($value, 0, -1)); 34 | $count = 0; 35 | foreach ($value as $char) { 36 | $count += $this->check[$char]; 37 | } 38 | 39 | $mod = $count % 43; 40 | if ($mod == $this->check[$checksum]) { 41 | return true; 42 | } 43 | 44 | return false; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/Barcode/Code39ext.php: -------------------------------------------------------------------------------- 1 | checksumCallback = [$this, 'validateCode39Checksum']; 23 | $this->useChecksum = $useChecksum; 24 | $this->setLength(-1); 25 | $this->setCharacters(128); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Barcode/Code93.php: -------------------------------------------------------------------------------- 1 | useChecksum = $useChecksum; 23 | $this->checksumCallback = [$this, 'validateCode93Checksum']; 24 | $this->setLength(-1); 25 | $this->setCharacters('0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ -.$/+%'); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Barcode/Code93ChecksumTrait.php: -------------------------------------------------------------------------------- 1 | 0, '1' => 1, '2' => 2, '3' => 3, '4' => 4, '5' => 5, '6' => 6, 20 | '7' => 7, '8' => 8, '9' => 9, 'A' => 10, 'B' => 11, 'C' => 12, 'D' => 13, 21 | 'E' => 14, 'F' => 15, 'G' => 16, 'H' => 17, 'I' => 18, 'J' => 19, 'K' => 20, 22 | 'L' => 21, 'M' => 22, 'N' => 23, 'O' => 24, 'P' => 25, 'Q' => 26, 'R' => 27, 23 | 'S' => 28, 'T' => 29, 'U' => 30, 'V' => 31, 'W' => 32, 'X' => 33, 'Y' => 34, 24 | 'Z' => 35, '-' => 36, '.' => 37, ' ' => 38, '$' => 39, '/' => 40, '+' => 41, 25 | '%' => 42, '!' => 43, '"' => 44, '§' => 45, '&' => 46, 26 | ]; 27 | 28 | /** 29 | * Validates the checksum (Modulo CK) 30 | */ 31 | private function validateCode93Checksum(string $value) : bool 32 | { 33 | $checksum = substr($value, -2, 2); 34 | $value = str_split(substr($value, 0, -2)); 35 | $count = 0; 36 | $length = count($value) % 20; 37 | 38 | foreach ($value as $char) { 39 | if ($length == 0) { 40 | $length = 20; 41 | } 42 | 43 | $count += $this->check[$char] * $length; 44 | $length -= 1; 45 | } 46 | 47 | $check = array_search(($count % 47), $this->check); 48 | $value[] = $check; 49 | $count = 0; 50 | $length = count($value) % 15; 51 | 52 | foreach ($value as $char) { 53 | if ($length == 0) { 54 | $length = 15; 55 | } 56 | 57 | $count += $this->check[$char] * $length; 58 | $length -= 1; 59 | } 60 | $check .= array_search(($count % 47), $this->check); 61 | 62 | return $check === $checksum; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/Barcode/Code93ext.php: -------------------------------------------------------------------------------- 1 | useChecksum = $useChecksum; 23 | $this->checksumCallback = [$this, 'validateCode93Checksum']; 24 | $this->setLength(-1); 25 | $this->setCharacters(128); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Barcode/Ean12.php: -------------------------------------------------------------------------------- 1 | useChecksum = $useChecksum; 23 | $this->checksumCallback = [$this, 'validateGtinChecksum']; 24 | $this->setLength(12); 25 | $this->setCharacters('0123456789'); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Barcode/Ean13.php: -------------------------------------------------------------------------------- 1 | useChecksum = $useChecksum; 23 | $this->checksumCallback = [$this, 'validateGtinChecksum']; 24 | $this->setLength(13); 25 | $this->setCharacters('0123456789'); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Barcode/Ean14.php: -------------------------------------------------------------------------------- 1 | useChecksum = $useChecksum; 23 | $this->checksumCallback = [$this, 'validateGtinChecksum']; 24 | $this->setLength(14); 25 | $this->setCharacters('0123456789'); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Barcode/Ean18.php: -------------------------------------------------------------------------------- 1 | useChecksum = $useChecksum; 23 | $this->checksumCallback = [$this, 'validateGtinChecksum']; 24 | $this->setLength(18); 25 | $this->setCharacters('0123456789'); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Barcode/Ean2.php: -------------------------------------------------------------------------------- 1 | setLength(2); 20 | $this->setCharacters('0123456789'); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/Barcode/Ean5.php: -------------------------------------------------------------------------------- 1 | setLength(5); 17 | $this->setCharacters('0123456789'); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/Barcode/Ean8.php: -------------------------------------------------------------------------------- 1 | setLength([7, 8]); 23 | $this->setCharacters('0123456789'); 24 | $this->checksumCallback = [$this, 'validateGtinChecksum']; 25 | } 26 | 27 | /** 28 | * Implements ChecksummableInterface::useChecksum and overrides 29 | * ChecksumTrait::useChecksum 30 | */ 31 | public function useChecksum(string $value = null) : bool 32 | { 33 | return strlen($value) !== 7; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/Barcode/Gtin12.php: -------------------------------------------------------------------------------- 1 | useChecksum = $useChecksum; 23 | $this->checksumCallback = [$this, 'validateGtinChecksum']; 24 | $this->setLength(12); 25 | $this->setCharacters('0123456789'); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Barcode/Gtin13.php: -------------------------------------------------------------------------------- 1 | useChecksum = $useChecksum; 23 | $this->checksumCallback = [$this, 'validateGtinChecksum']; 24 | $this->setLength(13); 25 | $this->setCharacters('0123456789'); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Barcode/Gtin14.php: -------------------------------------------------------------------------------- 1 | useChecksum = $useChecksum; 23 | $this->checksumCallback = [$this, 'validateGtinChecksum']; 24 | $this->setLength(14); 25 | $this->setCharacters('0123456789'); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Barcode/GtinChecksumTrait.php: -------------------------------------------------------------------------------- 1 | useChecksum = $useChecksum; 23 | $this->checksumCallback = [$this, 'validateIdentcodeChecksum']; 24 | $this->setLength(12); 25 | $this->setCharacters('0123456789'); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Barcode/IdentcodeChecksumTrait.php: -------------------------------------------------------------------------------- 1 | setLength([20, 25, 29, 31]); 17 | $this->setCharacters('0123456789'); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/Barcode/Issn.php: -------------------------------------------------------------------------------- 1 | useChecksum = $useChecksum; 23 | $this->setLength([8, 13]); 24 | $this->setCharacters('0123456789X'); 25 | } 26 | 27 | /** 28 | * Allows X on length of 8 chars 29 | */ 30 | public function hasValidCharacters(string $value) : bool 31 | { 32 | if (strlen($value) !== 8 33 | && strpos($value, 'X') !== false 34 | ) { 35 | return false; 36 | } 37 | 38 | return parent::hasValidCharacters($value); 39 | } 40 | 41 | /** 42 | * Validates the checksum 43 | * 44 | * Implements ChecksummableInterface::hasValidChecksum, and overrides 45 | * ChecksumTrait::hasValidChecksum. 46 | */ 47 | public function hasValidChecksum(string $value) : bool 48 | { 49 | if (strlen($value) == 8) { 50 | return $this->validateIssnChecksum($value); 51 | } 52 | 53 | return $this->validateGtinChecksum($value); 54 | } 55 | 56 | /** 57 | * Validates the checksum () 58 | * ISSN implementation (reversed mod11) 59 | */ 60 | private function validateIssnChecksum(string $value) : bool 61 | { 62 | $checksum = substr($value, -1, 1); 63 | $values = str_split(substr($value, 0, -1)); 64 | $check = 0; 65 | $multi = 8; 66 | foreach ($values as $token) { 67 | if ($token === 'X') { 68 | $token = 10; 69 | } 70 | 71 | $check += (int) $token * $multi; 72 | $multi -= 1; 73 | } 74 | 75 | $check %= 11; 76 | $check = $check === 0 ? 0 : 11 - $check; 77 | 78 | return $check === (int) $checksum 79 | || ($check === 10 && $checksum === 'X'); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/Barcode/Itf14.php: -------------------------------------------------------------------------------- 1 | useChecksum = $useChecksum; 23 | $this->checksumCallback = [$this, 'validateGtinChecksum']; 24 | $this->setLength(14); 25 | $this->setCharacters('0123456789'); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Barcode/Leitcode.php: -------------------------------------------------------------------------------- 1 | useChecksum = $useChecksum; 23 | $this->checksumCallback = [$this, 'validateIdentcodeChecksum']; 24 | $this->setLength(14); 25 | $this->setCharacters('0123456789'); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Barcode/Planet.php: -------------------------------------------------------------------------------- 1 | useChecksum = $useChecksum; 23 | $this->checksumCallback = [$this, 'validatePostnetChecksum']; 24 | $this->setLength([12, 14]); 25 | $this->setCharacters('0123456789'); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Barcode/Postnet.php: -------------------------------------------------------------------------------- 1 | useChecksum = $useChecksum; 23 | $this->checksumCallback = [$this, 'validatePostnetChecksum']; 24 | $this->setLength([6, 7, 10, 12]); 25 | $this->setCharacters('0123456789'); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Barcode/PostnetChecksumTrait.php: -------------------------------------------------------------------------------- 1 | 1, '1' => 1, '2' => 1, '3' => 1, '4' => 1, '5' => 1, 21 | '6' => 2, '7' => 2, '8' => 2, '9' => 2, 'A' => 2, 'B' => 2, 22 | 'C' => 3, 'D' => 3, 'E' => 3, 'F' => 3, 'G' => 3, 'H' => 3, 23 | 'I' => 4, 'J' => 4, 'K' => 4, 'L' => 4, 'M' => 4, 'N' => 4, 24 | 'O' => 5, 'P' => 5, 'Q' => 5, 'R' => 5, 'S' => 5, 'T' => 5, 25 | 'U' => 0, 'V' => 0, 'W' => 0, 'X' => 0, 'Y' => 0, 'Z' => 0, 26 | ]; 27 | 28 | /** 29 | * @var int[] 30 | */ 31 | private $columns = [ 32 | '0' => 1, '1' => 2, '2' => 3, '3' => 4, '4' => 5, '5' => 0, 33 | '6' => 1, '7' => 2, '8' => 3, '9' => 4, 'A' => 5, 'B' => 0, 34 | 'C' => 1, 'D' => 2, 'E' => 3, 'F' => 4, 'G' => 5, 'H' => 0, 35 | 'I' => 1, 'J' => 2, 'K' => 3, 'L' => 4, 'M' => 5, 'N' => 0, 36 | 'O' => 1, 'P' => 2, 'Q' => 3, 'R' => 4, 'S' => 5, 'T' => 0, 37 | 'U' => 1, 'V' => 2, 'W' => 3, 'X' => 4, 'Y' => 5, 'Z' => 0, 38 | ]; 39 | 40 | /** 41 | * Constructor for this barcode adapter 42 | */ 43 | public function __construct(bool $useChecksum = true) 44 | { 45 | $this->useChecksum = $useChecksum; 46 | $this->checksumCallback = [$this, 'validateRoyalmailChecksum']; 47 | $this->setLength(-1); 48 | $this->setCharacters('0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'); 49 | } 50 | 51 | /** 52 | * Allows start and stop tag within checked chars 53 | */ 54 | public function hasValidCharacters(string $value) : bool 55 | { 56 | if ($value[0] === '(') { 57 | if ($value[strlen($value) - 1] !== ')') { 58 | return false; 59 | } 60 | 61 | $value = substr($value, 1, -1); 62 | } 63 | 64 | return parent::hasValidCharacters($value); 65 | } 66 | 67 | /** 68 | * Validates the checksum 69 | */ 70 | private function validateRoyalmailChecksum(string $value) : bool 71 | { 72 | $checksum = substr($value, -1, 1); 73 | $values = str_split(substr($value, 0, -1)); 74 | $rowvalue = 0; 75 | $colvalue = 0; 76 | foreach ($values as $row) { 77 | $rowvalue += $this->rows[$row]; 78 | $colvalue += $this->columns[$row]; 79 | } 80 | 81 | $rowvalue %= 6; 82 | $colvalue %= 6; 83 | 84 | $rowchkvalue = array_keys($this->rows, $rowvalue); 85 | $colchkvalue = array_keys($this->columns, $colvalue); 86 | $intersect = array_intersect($rowchkvalue, $colchkvalue); 87 | $chkvalue = current($intersect); 88 | return $chkvalue === $checksum; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/Barcode/Sscc.php: -------------------------------------------------------------------------------- 1 | useChecksum = $useChecksum; 23 | $this->checksumCallback = [$this, 'validateGtinChecksum']; 24 | $this->setLength(18); 25 | $this->setCharacters('0123456789'); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Barcode/Upca.php: -------------------------------------------------------------------------------- 1 | useChecksum = $useChecksum; 23 | $this->checksumCallback = [$this, 'validateGtinChecksum']; 24 | $this->setLength(12); 25 | $this->setCharacters('0123456789'); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Barcode/Upce.php: -------------------------------------------------------------------------------- 1 | checksumCallback = [$this, 'validateGtinChecksum']; 23 | $this->setLength([6, 7, 8]); 24 | $this->setCharacters('0123456789'); 25 | } 26 | 27 | /** 28 | * Implements ChecksummableInterface::useChecksum, and overrides 29 | * ChecksumTrait::useChecksum 30 | */ 31 | public function useChecksum(string $value = null) : bool 32 | { 33 | return strlen($value) === 8; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/Between.php: -------------------------------------------------------------------------------- 1 | 'The input is not between "%min%" and "%max%", inclusively', 24 | self::NOT_BETWEEN_STRICT => 'The input is not strictly between "%min%" and "%max%"', 25 | ]; 26 | 27 | /** 28 | * @var bool 29 | */ 30 | private $inclusive; 31 | 32 | /** 33 | * @var int|float 34 | */ 35 | private $max; 36 | 37 | /** 38 | * @var int|float 39 | */ 40 | private $min; 41 | 42 | /** 43 | * Sets validator options 44 | * Accepts the following option keys: 45 | * 'min' => scalar, minimum border 46 | * 'max' => scalar, maximum border 47 | * 'inclusive' => boolean, inclusive border values 48 | * 49 | * @param int|float $min 50 | * @param int|float $max 51 | * @throws Exception\InvalidArgumentException if $min is not numeric 52 | * @throws Exception\InvalidArgumentException if $max is not numeric 53 | */ 54 | public function __construct($min = 0, $max = PHP_INT_MAX, bool $inclusive = true) 55 | { 56 | if (! is_numeric($min)) { 57 | throw new Exception\InvalidArgumentException(sprintf( 58 | 'Invalid value for "min"; must be numeric, received %s', 59 | is_object($min) ? get_class($min) : gettype($min) 60 | )); 61 | } 62 | if (! is_numeric($max)) { 63 | throw new Exception\InvalidArgumentException(sprintf( 64 | 'Invalid value for "max"; must be numeric, received %s', 65 | is_object($max) ? get_class($max) : gettype($max) 66 | )); 67 | } 68 | 69 | $this->min = $min; 70 | $this->max = $max; 71 | $this->inclusive = $inclusive; 72 | 73 | $this->messageVariables = [ 74 | 'min' => $min, 75 | 'max' => $max, 76 | ]; 77 | } 78 | 79 | /** 80 | * Returns the min option 81 | * 82 | * @return int|float 83 | */ 84 | public function getMin() 85 | { 86 | return $this->min; 87 | } 88 | 89 | /** 90 | * Returns the max option 91 | * 92 | * @return int|float 93 | */ 94 | public function getMax() 95 | { 96 | return $this->max; 97 | } 98 | 99 | public function isInclusive() : bool 100 | { 101 | return $this->inclusive; 102 | } 103 | 104 | /** 105 | * Returns true if and only if $value is between min and max options, inclusively 106 | * if inclusive option is true. 107 | */ 108 | public function validate($value, $context = null) : ResultInterface 109 | { 110 | return $this->isInclusive() 111 | ? $this->validateInclusive($value, $context) 112 | : $this->validateExclusive($value, $context); 113 | } 114 | 115 | private function validateInclusive($value, $context) : Result 116 | { 117 | if ($value < $this->getMin() || $value > $this->getMax()) { 118 | return $this->createInvalidResult($value, [self::NOT_BETWEEN]); 119 | } 120 | return Result::createValidResult($value); 121 | } 122 | 123 | private function validateExclusive($value, $context) : Result 124 | { 125 | if ($value <= $this->getMin() || $value >= $this->getMax()) { 126 | return $this->createInvalidResult($value, [self::NOT_BETWEEN_STRICT]); 127 | } 128 | return Result::createValidResult($value); 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /src/Callback.php: -------------------------------------------------------------------------------- 1 | 'Value does not pass custom validation', 31 | ]; 32 | 33 | /** 34 | * @var callable 35 | */ 36 | private $callback; 37 | 38 | public function __construct(callable $callback) 39 | { 40 | $this->callback = $callback; 41 | } 42 | 43 | public function validate($value, $context = null) : ResultInterface 44 | { 45 | $result = ($this->callback)($value, $context); 46 | 47 | if ($result instanceof ResultInterface) { 48 | return $result; 49 | } 50 | 51 | if (! is_bool($result)) { 52 | throw Exception\InvalidCallbackResultException::forType($result); 53 | } 54 | 55 | return $result 56 | ? Result::createValidResult($value) 57 | : $this->createInvalidResult($value, [self::INVALID]); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/ConfigProvider.php: -------------------------------------------------------------------------------- 1 | $this->getDependencies(), 18 | ]; 19 | } 20 | 21 | public function getDependencies() : array 22 | { 23 | return [ 24 | ]; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/Date.php: -------------------------------------------------------------------------------- 1 | "Invalid type given. String, integer, array or DateTime expected", 45 | self::INVALID_DATE => "The input does not appear to be a valid date", 46 | self::FALSEFORMAT => "The input does not fit the date format '%format%'", 47 | ]; 48 | 49 | /** 50 | * @var string 51 | */ 52 | private $format = self::FORMAT_DEFAULT; 53 | 54 | public function __construct(string $format = null) 55 | { 56 | $this->format = $format ?: self::FORMAT_DEFAULT; 57 | 58 | $this->messageVariables = [ 59 | 'format' => $this->format, 60 | ]; 61 | } 62 | 63 | /** 64 | * Returns the format option 65 | * 66 | * @return string 67 | */ 68 | public function getFormat() 69 | { 70 | return $this->format; 71 | } 72 | 73 | /** 74 | * Returns a successful validation result if $value is a DateTimeImmutable 75 | * instance or can be converted into one using the format provided during 76 | * instantiation. 77 | * 78 | * @param string|array|int|float|DateTimeImmutable $value 79 | */ 80 | public function validate($value, $context = null) : ResultInterface 81 | { 82 | if ($value instanceof DateTimeInterface) { 83 | return Result::createValidResult($value); 84 | } 85 | 86 | switch (gettype($value)) { 87 | case 'string': 88 | $result = $this->convertString($value); 89 | break; 90 | case 'integer': 91 | $result = $this->convertInteger($value); 92 | break; 93 | case 'double': 94 | $result = $this->convertDouble($value); 95 | break; 96 | case 'array': 97 | $result = $this->convertArray($value); 98 | break; 99 | default: 100 | return $this->createInvalidResult($value, [self::INVALID]); 101 | } 102 | 103 | if ($result instanceof ResultInterface) { 104 | return $result; 105 | } 106 | 107 | if (false === $result) { 108 | return $this->createInvalidResult($value, [self::INVALID_DATE]); 109 | } 110 | 111 | return Result::createValidResult($value); 112 | } 113 | 114 | /** 115 | * Attempts to convert an integer into a DateTime object 116 | * 117 | * @return false|DateTime 118 | */ 119 | private function convertInteger(int $value) 120 | { 121 | return date_create("@$value"); 122 | } 123 | 124 | /** 125 | * Attempts to convert an double into a DateTime object 126 | * 127 | * @return false|DateTime 128 | */ 129 | private function convertDouble(float $value) 130 | { 131 | return DateTime::createFromFormat('U', (string) $value); 132 | } 133 | 134 | /** 135 | * Attempts to convert a string into a DateTime object 136 | * 137 | * @param string $value 138 | * @return false|ResultInterface|DateTime 139 | */ 140 | private function convertString(string $value) 141 | { 142 | $date = DateTime::createFromFormat($this->format, $value); 143 | 144 | // Invalid dates can show up as warnings (ie. "2007-02-99") 145 | // and still return a DateTime object. 146 | $errors = DateTime::getLastErrors(); 147 | if ($errors['warning_count'] > 0) { 148 | return $this->createInvalidResult($value, [self::FALSEFORMAT]); 149 | } 150 | 151 | return $date; 152 | } 153 | 154 | /** 155 | * Implodes the array into a string and proxies to {@link convertString()}. 156 | * 157 | * @return false|ResultInterface|DateTime 158 | * @todo enhance the implosion 159 | */ 160 | private function convertArray(array $value) 161 | { 162 | return $this->convertString(implode('-', $value)); 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /src/Exception/ExceptionInterface.php: -------------------------------------------------------------------------------- 1 | legacyValidator = $legacyValidator; 38 | } 39 | 40 | public function validate($value, $context = null) : ResultInterface 41 | { 42 | if ($this->legacyValidator->isValid($value, $context)) { 43 | return Result::createValidResult($value); 44 | } 45 | 46 | if ($this->legacyValidator instanceof AbstractLegacyValidator) { 47 | return $this->marshalResultFromAbstractValidator($value); 48 | } 49 | 50 | return $this->marshalResultFromLegacyValidator($value); 51 | } 52 | 53 | private function marshalResultFromAbstractValidator($value) : ResultInterface 54 | { 55 | $r = new ReflectionProperty($this->legacyValidator, 'abstractOptions'); 56 | $r->setAccessible(true); 57 | $options = $r->getValue($this->legacyValidator); 58 | 59 | $messageVariables = array_merge( 60 | $options['messageVariables'], 61 | ['value' => $value] 62 | ); 63 | 64 | $messages = []; 65 | foreach (array_keys($options['messages']) as $messageKey) { 66 | $template = $options['messageTemplates'][$messageKey]; 67 | $messages[] = new ValidationFailureMessage($messageKey, $template, $messageVariables); 68 | } 69 | return Result::createInvalidResult($value, $messages); 70 | } 71 | 72 | private function marshalResultFromLegacyValidator($value) : ResultInterface 73 | { 74 | $messages = []; 75 | foreach ($this->legacyValidator->getMessages() as $code => $message) { 76 | $messages[] = new ValidationFailureMessage($code, $message); 77 | } 78 | return Result::createInvalidResult($value, $messages); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/LegacyValidatorTrait.php: -------------------------------------------------------------------------------- 1 | isValid($value, $context)) { 24 | return Result::createValidResult($value); 25 | } 26 | 27 | $messageVariables = array_merge( 28 | $this->abstractOptions['messageVariables'], 29 | ['value' => $value] 30 | ); 31 | 32 | $messages = []; 33 | foreach (array_keys($this->abstractOptions['messages']) as $messageKey) { 34 | $template = $this->abstractOptions['messageTemplates'][$messageKey]; 35 | $messages[] = new ValidationFailureMessage($messageKey, $template, $messageVariables); 36 | } 37 | return Result::createInvalidResult($value, $messages); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/NotEmpty.php: -------------------------------------------------------------------------------- 1 | 'Value is required and can\'t be empty', 50 | self::INVALID => 'Invalid type given. String, integer, float, boolean or array expected', 51 | ]; 52 | 53 | private $constants = [ 54 | self::BOOLEAN => 'boolean', 55 | self::INTEGER => 'integer', 56 | self::FLOAT => 'float', 57 | self::STRING => 'string', 58 | self::ZERO => 'zero', 59 | self::EMPTY_ARRAY => 'array', 60 | self::NULL => 'null', 61 | self::PHP => 'php', 62 | self::SPACE => 'space', 63 | self::OBJECT => 'object', 64 | self::OBJECT_STRING => 'objectstring', 65 | self::OBJECT_COUNT => 'objectcount', 66 | self::ALL => 'all', 67 | ]; 68 | 69 | /** 70 | * Default types allowed; value = 0b000111101001 71 | * 72 | * @var int 73 | */ 74 | private $defaultTypeMask = self::OBJECT 75 | | self::SPACE 76 | | self::NULL 77 | | self::EMPTY_ARRAY 78 | | self::STRING 79 | | self::BOOLEAN; 80 | 81 | /** 82 | * Mask of all object types; value = 0b011100000000; 83 | * 84 | * @var int 85 | */ 86 | private $objectMask = self::OBJECT | self::OBJECT_COUNT | self::OBJECT_STRING; 87 | 88 | /** 89 | * @var int Type mask of allowed types that can represent empty values. 90 | */ 91 | private $typeMask; 92 | 93 | /** 94 | * @param null|array|int|string $typeMask Allowed type(s) for representing 95 | * not-empty values. Defaults to the mask OBJECT|SPACE|NULL|EMPTY_ARRAY|STRING|BOOLEAN. 96 | * @throws Exception\InvalidArgumentException if $typeMask is not null, an 97 | * integer, a string, or an array. 98 | */ 99 | public function __construct($typeMask = null) 100 | { 101 | if (null !== $typeMask 102 | && ! (is_int($typeMask) || is_string($typeMask) || is_array($typeMask)) 103 | ) { 104 | throw new Exception\InvalidArgumentException(sprintf( 105 | '$typeMask argument to %s MUST be an integer corresponding to one of' 106 | . ' the type constants (or a mask of them), a string representation' 107 | . ' of one of those constants, or an array of such values; received %s', 108 | __CLASS__, 109 | is_object($typeMask) ? get_class($typeMask) : gettype($typeMask) 110 | )); 111 | } 112 | 113 | $this->typeMask = $this->calculateTypeMask($typeMask ?: $this->defaultTypeMask); 114 | } 115 | 116 | /** 117 | * {@inheritdoc} 118 | */ 119 | public function validate($value, $context = null) : ResultInterface 120 | { 121 | if ($value !== null 122 | && ! is_string($value) 123 | && ! is_int($value) 124 | && ! is_float($value) 125 | && ! is_bool($value) 126 | && ! is_array($value) 127 | && ! is_object($value) 128 | ) { 129 | return $this->createInvalidResult($value, [self::INVALID]); 130 | } 131 | 132 | // SPACE|ZERO|STRING (' ', '0', '') 133 | if (is_string($value)) { 134 | return $this->validateStringValue($value); 135 | } 136 | 137 | // OBJECT|OBJECT_STRING|OBJECT_INT 138 | if (is_object($value)) { 139 | return $this->validateObjectValue($value); 140 | } 141 | 142 | // NULL (null) 143 | if ($this->typeMask & self::NULL 144 | && null === $value 145 | ) { 146 | return $this->createInvalidResult($value, [self::IS_EMPTY]); 147 | } 148 | 149 | // BOOLEAN (false) 150 | if ($this->typeMask & self::BOOLEAN 151 | && $value === false 152 | ) { 153 | return $this->createInvalidResult($value, [self::IS_EMPTY]); 154 | } 155 | 156 | // EMPTY_ARRAY ([]) 157 | if ($this->typeMask & self::EMPTY_ARRAY 158 | && $value === [] 159 | ) { 160 | return $this->createInvalidResult($value, [self::IS_EMPTY]); 161 | } 162 | 163 | // FLOAT (0.0) 164 | if ($this->typeMask & self::FLOAT 165 | && $value === 0.0 166 | ) { 167 | return $this->createInvalidResult($value, [self::IS_EMPTY]); 168 | } 169 | 170 | // INTEGER (0) 171 | if ($this->typeMask & self::INTEGER 172 | && $value === 0 173 | ) { 174 | return $this->createInvalidResult($value, [self::IS_EMPTY]); 175 | } 176 | 177 | return Result::createValidResult($value); 178 | } 179 | 180 | /** 181 | * @param array|int|string $typeMask 182 | */ 183 | private function calculateTypeMask($typeMask) : int 184 | { 185 | if (is_array($typeMask)) { 186 | return $this->calculateTypeMaskFromArray($typeMask); 187 | } 188 | 189 | if (is_string($typeMask) && in_array($typeMask, $this->constants, true)) { 190 | return array_search($typeMask, $this->constants, true); 191 | } 192 | 193 | return $typeMask; 194 | } 195 | 196 | private function calculateTypeMaskFromArray(array $types) : int 197 | { 198 | $typeMask = 0; 199 | foreach ($types as $type) { 200 | if (is_int($type)) { 201 | $typeMask |= $type; 202 | continue; 203 | } 204 | 205 | if (in_array($type, $this->constants, true)) { 206 | $typeMask |= array_search($type, $this->constants, true); 207 | continue; 208 | } 209 | } 210 | return $typeMask; 211 | } 212 | 213 | /** 214 | * @param object $value 215 | */ 216 | private function validateObjectValue($value) : ResultInterface 217 | { 218 | // Object-as-integer, but object is not countable, 219 | // or counting results in zero. 220 | if ($this->typeMask & self::OBJECT_COUNT 221 | && (! $value instanceof Countable 222 | || count($value) === 0 223 | ) 224 | ) { 225 | return $this->createInvalidResult($value, [self::IS_EMPTY]); 226 | } 227 | 228 | // Object-as-string, but object is not string serializable, 229 | // or serialization results in empty string. 230 | if ($this->typeMask & self::OBJECT_STRING 231 | && (! method_exists($value, '__toString') 232 | || (string) $value === '' 233 | ) 234 | ) { 235 | return $this->createInvalidResult($value, [self::IS_EMPTY]); 236 | } 237 | 238 | // Object, object-as-integer, or object-as-string: objects 239 | // are never considered empty on their own, so these are valid: 240 | if ($this->typeMask & $this->objectMask) { 241 | return Result::createValidResult($value); 242 | } 243 | 244 | // Objects are not allowed, but we have one; invalid. 245 | return $this->createInvalidResult($value, [self::IS_EMPTY]); 246 | } 247 | 248 | private function validateStringValue(string $value) : ResultInterface 249 | { 250 | if ($this->typeMask & self::SPACE 251 | && preg_match('/^\s+$/s', $value) 252 | ) { 253 | return $this->createInvalidResult($value, [self::IS_EMPTY]); 254 | } 255 | 256 | if ($this->typeMask & self::ZERO 257 | && $value === '0' 258 | ) { 259 | return $this->createInvalidResult($value, [self::IS_EMPTY]); 260 | } 261 | 262 | if ($this->typeMask & self::STRING 263 | && $value === '' 264 | ) { 265 | return $this->createInvalidResult($value, [self::IS_EMPTY]); 266 | } 267 | 268 | return Result::createValidResult($value); 269 | } 270 | } 271 | -------------------------------------------------------------------------------- /src/Result.php: -------------------------------------------------------------------------------- 1 | isValid = $isValid; 36 | $this->value = $value; 37 | 38 | array_walk($messages, function ($message) { 39 | if (! $message instanceof ValidationFailureMessage) { 40 | throw new Exception\InvalidArgumentException(sprintf( 41 | 'All validation failure messages must be of type %s; received %s', 42 | ValidationFailureMessage::class, 43 | is_object($message) ? get_class($message) : gettype($message) 44 | )); 45 | } 46 | }); 47 | $this->messages = $messages; 48 | } 49 | 50 | public function isValid() : bool 51 | { 52 | return $this->isValid; 53 | } 54 | 55 | /** 56 | * @return ValidationFailureMessage[] 57 | */ 58 | public function getMessages() : array 59 | { 60 | return $this->messages; 61 | } 62 | 63 | /** 64 | * @return mixed 65 | */ 66 | public function getValue() 67 | { 68 | return $this->value; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/ResultAggregate.php: -------------------------------------------------------------------------------- 1 | value = $value; 29 | } 30 | 31 | public function push(ResultInterface $result) : void 32 | { 33 | $this->results[] = $result; 34 | } 35 | 36 | public function isValid() : bool 37 | { 38 | $this->assertAggregateNotEmpty(); 39 | 40 | return array_reduce($this->results, function ($isValid, $result) { 41 | return $isValid === false ? false : $result->isValid(); 42 | }, null); 43 | } 44 | 45 | /** 46 | * @return ValidationFailureMessage[] 47 | */ 48 | public function getMessages() : array 49 | { 50 | $this->assertAggregateNotEmpty(); 51 | 52 | return array_reduce($this->results, function ($messages, $result) { 53 | return $result->isValid() 54 | ? $messages 55 | : array_merge($messages, $result->getMessages()); 56 | }, []); 57 | } 58 | 59 | /** 60 | * @return mixed 61 | */ 62 | public function getValue() 63 | { 64 | return $this->value; 65 | } 66 | 67 | private function assertAggregateNotEmpty() : void 68 | { 69 | if (empty($this->results)) { 70 | throw MissingResultsException::forClass(self::class); 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/ResultInterface.php: -------------------------------------------------------------------------------- 1 | 'Invalid type given; string expected', 25 | self::INVALID => 'Invalid UUID format', 26 | ]; 27 | 28 | /** 29 | * Matches Uuid's versions 1 to 5. 30 | */ 31 | private const REGEX_UUID = '/^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}$/'; 32 | 33 | /** 34 | * Returns true if and only if $value is between min and max options, inclusively 35 | * if inclusive option is true. 36 | */ 37 | public function validate($value, $context = null) : ResultInterface 38 | { 39 | if (! is_string($value)) { 40 | return $this->createInvalidResult($value, [self::NOT_STRING]); 41 | } 42 | 43 | if (empty($value) 44 | || $value !== '00000000-0000-0000-0000-000000000000' 45 | && ! preg_match(self::REGEX_UUID, $value) 46 | ) { 47 | return $this->createInvalidResult($value, [self::INVALID]); 48 | } 49 | 50 | return Result::createValidResult($value); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/ValidationFailureMessage.php: -------------------------------------------------------------------------------- 1 | code = $code; 29 | $this->template = $template; 30 | $this->variables = $variables; 31 | } 32 | 33 | public function getCode() : string 34 | { 35 | return $this->code; 36 | } 37 | 38 | public function getTemplate() : string 39 | { 40 | return $this->template; 41 | } 42 | 43 | public function getVariables() : array 44 | { 45 | return $this->variables; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/ValidatorChain.php: -------------------------------------------------------------------------------- 1 | validators[] = [ 39 | 'instance' => $validator, 40 | 'breakChainOnFailure' => $breakChainOnFailure, 41 | ]; 42 | } 43 | 44 | /** 45 | * Returns true if and only if $value passes all validations in the chain 46 | * 47 | * Validators are run in the order in which they were added to the chain (FIFO). 48 | * 49 | * {@inheritDoc} 50 | */ 51 | public function validate($value, $context = null) : ResultInterface 52 | { 53 | $results = new ResultAggregate($value); 54 | 55 | foreach ($this->iterateValidators($value, $context) as $result) { 56 | $results->push($result); 57 | } 58 | 59 | return $results; 60 | } 61 | 62 | /** 63 | * Iterate through each validator and validate the value against its context. 64 | * 65 | * Yields ResultInterface instances. 66 | * 67 | * @param mixed $value Value to validate 68 | * @param object|array|mixed $context Validation context (e.g., set of 69 | * other form elements) 70 | */ 71 | private function iterateValidators($value, $context) : iterable 72 | { 73 | foreach ($this->validators as $element) { 74 | $validator = $element['instance']; 75 | $result = $validator->validate($value, $context); 76 | yield $result; 77 | 78 | if (! $result->isValid() && $element['breakChainOnFailure']) { 79 | return; 80 | } 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/ValidatorInterface.php: -------------------------------------------------------------------------------- 1 |