├── .coveralls.yml ├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── composer.json ├── composer.lock ├── phpunit.xml.dist ├── resources ├── backgrounds │ ├── bg1.png │ ├── bg2.png │ ├── bg3.png │ ├── bg4.png │ ├── bg5.png │ ├── bg6.png │ ├── bg7.png │ └── bg8.png ├── fonts │ └── capsmall_clean.ttf └── img │ ├── sample1.png │ ├── sample2.png │ ├── sample3.png │ └── sample4.png ├── sample ├── login.php └── validate-login.php ├── src ├── Captcha.php ├── Exception │ ├── CaptchaException.php │ └── Utility │ │ └── HexToRGB.php ├── Facade │ └── Captcha.php └── Utility │ └── HexToRGB.php └── tests ├── Unit ├── CaptchaTest.php ├── Facade │ └── CaptchaTest.php └── Utility │ └── HexToRGBTest.php └── bootstrap.php /.coveralls.yml: -------------------------------------------------------------------------------- 1 | service_name: travis-ci 2 | coverage_clover: build/logs/clover.xml 3 | json_path: build/logs/coveralls-upload.json 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | vendor/ 2 | build/ 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # Required to run your project under the correct environment. 2 | language: php 3 | 4 | # Versions of PHP you want your project run with. 5 | php: 6 | - 7.2 7 | - 7.1 8 | - 7.0 9 | - 5.6 10 | 11 | # Commands to be run before your environment runs. 12 | before_script: 13 | 14 | # Commands you want to run that will verify your build. 15 | script: 16 | - rm composer.lock 17 | - composer install 18 | - composer require php-coveralls/php-coveralls 19 | - mkdir -p build/logs 20 | - vendor/bin/phpunit 21 | 22 | # Execute another command after success of the script. 23 | after_success: 24 | - vendor/bin/php-coveralls -v 25 | 26 | # Customize when the notification emails are sent. 27 | notifications: 28 | on_success: never 29 | on_failure: always 30 | 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2018 - 2020 Joshua Clifford Reyes 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PHP Simple Captcha 2 | 3 | A simple captcha package that fit to any type of web application built on php. 4 | 5 | [![Latest Stable Version](https://img.shields.io/packagist/v/lorddashme/php-simple-captcha.svg?style=flat-square)](https://packagist.org/packages/lorddashme/php-simple-captcha) [![Minimum PHP Version](https://img.shields.io/badge/php-%3E%3D%205.6-8892BF.svg?style=flat-square)](https://php.net/) [![Coverage Status](https://img.shields.io/coveralls/LordDashMe/php-simple-captcha/master.svg?style=flat-square)](https://coveralls.io/github/LordDashMe/php-simple-captcha?branch=master) 6 | 7 | ## Sample 8 | 9 | ![PHP Simple Captcha Sample 1](resources/img/sample1.png) ![PHP Simple Captcha Sample 2](resources/img/sample2.png) ![PHP Simple Captcha Sample 3](resources/img/sample3.png) ![PHP Simple Captcha Sample 4](resources/img/sample4.png) 10 | 11 | ## Requirement(s) 12 | 13 | - PHP version from 5.6.* up to latest. 14 | 15 | ## Install 16 | 17 | - Recommended to install using Composer. Use the command below to install the package: 18 | 19 | ```txt 20 | composer require lorddashme/php-simple-captcha 21 | ``` 22 | 23 | ## Usage 24 | 25 | ### List of Available Functions 26 | 27 | | Function | Description | 28 | | -------- | ----------- | 29 | | ```code(length);``` | Execute the generation of random code base on the given length.
The default length is 5. | 30 | | ```image();``` | Execute the generation of image and the content will be base on the ```code(length);``` function. | 31 | | ```getCode();``` | To get the current code generated by the ```code(length);``` method.
Ex. return value ```QwErTyx...``` | 32 | | ```getImage();``` | To get the current image generated by the ```image();``` function.
Ex. return value ```data:image/png;base64,iVBORw0KGgoAA...``` | 33 | | ```storeSession();``` | Use to store the generated values in the captcha session. | 34 | | ```getSession();``` | Use to get the current stored session generated values in the captcha session. This is use to validate the generated code against the user organic inputed code.
Ex. return value ```array('code' => '...')``` | 35 | 36 | - Basic usage: 37 | 38 | ```php 39 | code(); 49 | // Execute the image captcha rendering. 50 | $captcha->image(); 51 | 52 | // The generated captcha code, something like "QwErTyx..." 53 | echo $captcha->getCode(); 54 | // The generated captcha image that include the code above. 55 | // The output is base64 data image "data:image/png;base64,iVBORw0KGgoAA..." 56 | echo $captcha->getImage(); 57 | ``` 58 | 59 | - Also can be done by using the code below: 60 | 61 | ```php 62 | code(); 105 | $captcha->image(); 106 | $captcha->storeSession(); 107 | 108 | ?> 109 | 110 |
111 | 112 | ... 113 | 114 | 115 | 116 | 117 | 118 | 119 |
120 | ``` 121 | - Validation Route: 122 | 123 | - We need to initialize again the Captcha class but now we don't need to initialize the code and image generation. 124 | 125 | - Validate the user inputed captcha code. 126 | 127 | ```php 128 | getSession(); // return array( 'code' => 'QwErTyx...' ) 138 | 139 | if ($_POST['user_captcha_code'] === $data['code']) { 140 | return 'Code is valid!'; 141 | } else { 142 | return 'Code is invalid!'; 143 | } 144 | ``` 145 | 146 | - You may also check the [sample](sample) in the root directory of the package that will show you the actual example of implementing captcha class. 147 | 148 | ### Captcha Configuration 149 | 150 | - To change the default config of the class: 151 | 152 | ```php 153 | 'ldm-simple-captcha', 162 | 'session_index_name' => 'LDM_SIMPLE_CAPTCHA', 163 | 'session_https' => false, 164 | 'session_http_only' => true, 165 | 'font_color' => '#000', 166 | 'font_size_min' => 26, 167 | 'font_size_max' => 28, 168 | 'angle_min' => 0, 169 | 'angle_max' => 9, 170 | 'shadow' => true, 171 | 'shadow_color' => '#fff', 172 | 'shadow_offset_x' => -3, 173 | 'shadow_offset_y' => 1, 174 | 'backgrounds' => array( 175 | 'bg1.png', 176 | 'bg2.png', 177 | 'bg3.png', 178 | 'bg4.png', 179 | 'bg5.png', 180 | 'bg6.png', 181 | 'bg7.png', 182 | 'bg8.png' 183 | ), 184 | 'fonts' => array( 185 | 'capsmall_clean.ttf' 186 | ) 187 | ); 188 | 189 | $captcha = new Captcha($config); 190 | 191 | // Or you can use this style. 192 | 193 | CaptchaFacade::init($config); 194 | ``` 195 | 196 | ### Tips 197 | 198 | - Overriding the default config: 199 | 200 | - The ```backgrounds``` and ```fonts``` are tightly coupled in the directory structure of the package. 201 | 202 | - If you want to override the ```backgrounds``` and ```fonts``` you need to extends the Captcha class with your new sub class and override the protected methods of Captcha class for resources directory, ```backgroundsDirectoryPath()``` and ```fontsDirectoryPath```. 203 | 204 | ```php 205 | =5.6 || >=7.0 || >=7.1 || >=7.2", 23 | "lorddashme/php-static-class-interface": "1.*" 24 | }, 25 | "require-dev": { 26 | "mockery/mockery": "1.*", 27 | "phpunit/phpunit": "5.* || 6.* || 7.*" 28 | }, 29 | "autoload": { 30 | "psr-4": { 31 | "LordDashMe\\SimpleCaptcha\\": "src/" 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /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": "ccb24b7fad13f0aed80fa53d545b7d4e", 8 | "packages": [ 9 | { 10 | "name": "lorddashme/php-static-class-interface", 11 | "version": "1.1.0", 12 | "source": { 13 | "type": "git", 14 | "url": "https://github.com/LordDashMe/php-static-class-interface.git", 15 | "reference": "2310db22da2351bd6e85294b0c7990b9af86acee" 16 | }, 17 | "dist": { 18 | "type": "zip", 19 | "url": "https://api.github.com/repos/LordDashMe/php-static-class-interface/zipball/2310db22da2351bd6e85294b0c7990b9af86acee", 20 | "reference": "2310db22da2351bd6e85294b0c7990b9af86acee", 21 | "shasum": "" 22 | }, 23 | "require": { 24 | "php": ">=5.6 || >=7.0 || >=7.1 || >=7.2" 25 | }, 26 | "require-dev": { 27 | "mockery/mockery": "1.*", 28 | "phpunit/phpunit": "5.* || 6.* || 7.*" 29 | }, 30 | "type": "library", 31 | "autoload": { 32 | "psr-4": { 33 | "LordDashMe\\StaticClassInterface\\": "src/" 34 | } 35 | }, 36 | "notification-url": "https://packagist.org/downloads/", 37 | "license": [ 38 | "MIT" 39 | ], 40 | "authors": [ 41 | { 42 | "name": "Joshua Clifford Reyes", 43 | "email": "reyesjoshuaclifford@gmail.com", 44 | "homepage": "https://lorddashme.github.io/" 45 | } 46 | ], 47 | "description": "A simple package that convert a service class into a static-like class.", 48 | "homepage": "https://github.com/lorddashme/php-static-class-interface", 49 | "keywords": [ 50 | "facade", 51 | "github", 52 | "php", 53 | "static", 54 | "static-interface" 55 | ], 56 | "time": "2018-09-27T09:01:23+00:00" 57 | } 58 | ], 59 | "packages-dev": [ 60 | { 61 | "name": "doctrine/instantiator", 62 | "version": "1.0.5", 63 | "source": { 64 | "type": "git", 65 | "url": "https://github.com/doctrine/instantiator.git", 66 | "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d" 67 | }, 68 | "dist": { 69 | "type": "zip", 70 | "url": "https://api.github.com/repos/doctrine/instantiator/zipball/8e884e78f9f0eb1329e445619e04456e64d8051d", 71 | "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d", 72 | "shasum": "" 73 | }, 74 | "require": { 75 | "php": ">=5.3,<8.0-DEV" 76 | }, 77 | "require-dev": { 78 | "athletic/athletic": "~0.1.8", 79 | "ext-pdo": "*", 80 | "ext-phar": "*", 81 | "phpunit/phpunit": "~4.0", 82 | "squizlabs/php_codesniffer": "~2.0" 83 | }, 84 | "type": "library", 85 | "extra": { 86 | "branch-alias": { 87 | "dev-master": "1.0.x-dev" 88 | } 89 | }, 90 | "autoload": { 91 | "psr-4": { 92 | "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" 93 | } 94 | }, 95 | "notification-url": "https://packagist.org/downloads/", 96 | "license": [ 97 | "MIT" 98 | ], 99 | "authors": [ 100 | { 101 | "name": "Marco Pivetta", 102 | "email": "ocramius@gmail.com", 103 | "homepage": "http://ocramius.github.com/" 104 | } 105 | ], 106 | "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", 107 | "homepage": "https://github.com/doctrine/instantiator", 108 | "keywords": [ 109 | "constructor", 110 | "instantiate" 111 | ], 112 | "time": "2015-06-14T21:17:01+00:00" 113 | }, 114 | { 115 | "name": "hamcrest/hamcrest-php", 116 | "version": "v2.0.0", 117 | "source": { 118 | "type": "git", 119 | "url": "https://github.com/hamcrest/hamcrest-php.git", 120 | "reference": "776503d3a8e85d4f9a1148614f95b7a608b046ad" 121 | }, 122 | "dist": { 123 | "type": "zip", 124 | "url": "https://api.github.com/repos/hamcrest/hamcrest-php/zipball/776503d3a8e85d4f9a1148614f95b7a608b046ad", 125 | "reference": "776503d3a8e85d4f9a1148614f95b7a608b046ad", 126 | "shasum": "" 127 | }, 128 | "require": { 129 | "php": "^5.3|^7.0" 130 | }, 131 | "replace": { 132 | "cordoval/hamcrest-php": "*", 133 | "davedevelopment/hamcrest-php": "*", 134 | "kodova/hamcrest-php": "*" 135 | }, 136 | "require-dev": { 137 | "phpunit/php-file-iterator": "1.3.3", 138 | "phpunit/phpunit": "~4.0", 139 | "satooshi/php-coveralls": "^1.0" 140 | }, 141 | "type": "library", 142 | "extra": { 143 | "branch-alias": { 144 | "dev-master": "2.0-dev" 145 | } 146 | }, 147 | "autoload": { 148 | "classmap": [ 149 | "hamcrest" 150 | ] 151 | }, 152 | "notification-url": "https://packagist.org/downloads/", 153 | "license": [ 154 | "BSD" 155 | ], 156 | "description": "This is the PHP port of Hamcrest Matchers", 157 | "keywords": [ 158 | "test" 159 | ], 160 | "time": "2016-01-20T08:20:44+00:00" 161 | }, 162 | { 163 | "name": "mockery/mockery", 164 | "version": "1.1.0", 165 | "source": { 166 | "type": "git", 167 | "url": "https://github.com/mockery/mockery.git", 168 | "reference": "99e29d3596b16dabe4982548527d5ddf90232e99" 169 | }, 170 | "dist": { 171 | "type": "zip", 172 | "url": "https://api.github.com/repos/mockery/mockery/zipball/99e29d3596b16dabe4982548527d5ddf90232e99", 173 | "reference": "99e29d3596b16dabe4982548527d5ddf90232e99", 174 | "shasum": "" 175 | }, 176 | "require": { 177 | "hamcrest/hamcrest-php": "~2.0", 178 | "lib-pcre": ">=7.0", 179 | "php": ">=5.6.0" 180 | }, 181 | "require-dev": { 182 | "phpdocumentor/phpdocumentor": "^2.9", 183 | "phpunit/phpunit": "~5.7.10|~6.5" 184 | }, 185 | "type": "library", 186 | "extra": { 187 | "branch-alias": { 188 | "dev-master": "1.0.x-dev" 189 | } 190 | }, 191 | "autoload": { 192 | "psr-0": { 193 | "Mockery": "library/" 194 | } 195 | }, 196 | "notification-url": "https://packagist.org/downloads/", 197 | "license": [ 198 | "BSD-3-Clause" 199 | ], 200 | "authors": [ 201 | { 202 | "name": "Pádraic Brady", 203 | "email": "padraic.brady@gmail.com", 204 | "homepage": "http://blog.astrumfutura.com" 205 | }, 206 | { 207 | "name": "Dave Marshall", 208 | "email": "dave.marshall@atstsolutions.co.uk", 209 | "homepage": "http://davedevelopment.co.uk" 210 | } 211 | ], 212 | "description": "Mockery is a simple yet flexible PHP mock object framework", 213 | "homepage": "https://github.com/mockery/mockery", 214 | "keywords": [ 215 | "BDD", 216 | "TDD", 217 | "library", 218 | "mock", 219 | "mock objects", 220 | "mockery", 221 | "stub", 222 | "test", 223 | "test double", 224 | "testing" 225 | ], 226 | "time": "2018-05-08T08:54:48+00:00" 227 | }, 228 | { 229 | "name": "myclabs/deep-copy", 230 | "version": "1.7.0", 231 | "source": { 232 | "type": "git", 233 | "url": "https://github.com/myclabs/DeepCopy.git", 234 | "reference": "3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e" 235 | }, 236 | "dist": { 237 | "type": "zip", 238 | "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e", 239 | "reference": "3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e", 240 | "shasum": "" 241 | }, 242 | "require": { 243 | "php": "^5.6 || ^7.0" 244 | }, 245 | "require-dev": { 246 | "doctrine/collections": "^1.0", 247 | "doctrine/common": "^2.6", 248 | "phpunit/phpunit": "^4.1" 249 | }, 250 | "type": "library", 251 | "autoload": { 252 | "psr-4": { 253 | "DeepCopy\\": "src/DeepCopy/" 254 | }, 255 | "files": [ 256 | "src/DeepCopy/deep_copy.php" 257 | ] 258 | }, 259 | "notification-url": "https://packagist.org/downloads/", 260 | "license": [ 261 | "MIT" 262 | ], 263 | "description": "Create deep copies (clones) of your objects", 264 | "keywords": [ 265 | "clone", 266 | "copy", 267 | "duplicate", 268 | "object", 269 | "object graph" 270 | ], 271 | "time": "2017-10-19T19:58:43+00:00" 272 | }, 273 | { 274 | "name": "phpdocumentor/reflection-common", 275 | "version": "1.0.1", 276 | "source": { 277 | "type": "git", 278 | "url": "https://github.com/phpDocumentor/ReflectionCommon.git", 279 | "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6" 280 | }, 281 | "dist": { 282 | "type": "zip", 283 | "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6", 284 | "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6", 285 | "shasum": "" 286 | }, 287 | "require": { 288 | "php": ">=5.5" 289 | }, 290 | "require-dev": { 291 | "phpunit/phpunit": "^4.6" 292 | }, 293 | "type": "library", 294 | "extra": { 295 | "branch-alias": { 296 | "dev-master": "1.0.x-dev" 297 | } 298 | }, 299 | "autoload": { 300 | "psr-4": { 301 | "phpDocumentor\\Reflection\\": [ 302 | "src" 303 | ] 304 | } 305 | }, 306 | "notification-url": "https://packagist.org/downloads/", 307 | "license": [ 308 | "MIT" 309 | ], 310 | "authors": [ 311 | { 312 | "name": "Jaap van Otterdijk", 313 | "email": "opensource@ijaap.nl" 314 | } 315 | ], 316 | "description": "Common reflection classes used by phpdocumentor to reflect the code structure", 317 | "homepage": "http://www.phpdoc.org", 318 | "keywords": [ 319 | "FQSEN", 320 | "phpDocumentor", 321 | "phpdoc", 322 | "reflection", 323 | "static analysis" 324 | ], 325 | "time": "2017-09-11T18:02:19+00:00" 326 | }, 327 | { 328 | "name": "phpdocumentor/reflection-docblock", 329 | "version": "3.3.2", 330 | "source": { 331 | "type": "git", 332 | "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", 333 | "reference": "bf329f6c1aadea3299f08ee804682b7c45b326a2" 334 | }, 335 | "dist": { 336 | "type": "zip", 337 | "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/bf329f6c1aadea3299f08ee804682b7c45b326a2", 338 | "reference": "bf329f6c1aadea3299f08ee804682b7c45b326a2", 339 | "shasum": "" 340 | }, 341 | "require": { 342 | "php": "^5.6 || ^7.0", 343 | "phpdocumentor/reflection-common": "^1.0.0", 344 | "phpdocumentor/type-resolver": "^0.4.0", 345 | "webmozart/assert": "^1.0" 346 | }, 347 | "require-dev": { 348 | "mockery/mockery": "^0.9.4", 349 | "phpunit/phpunit": "^4.4" 350 | }, 351 | "type": "library", 352 | "autoload": { 353 | "psr-4": { 354 | "phpDocumentor\\Reflection\\": [ 355 | "src/" 356 | ] 357 | } 358 | }, 359 | "notification-url": "https://packagist.org/downloads/", 360 | "license": [ 361 | "MIT" 362 | ], 363 | "authors": [ 364 | { 365 | "name": "Mike van Riel", 366 | "email": "me@mikevanriel.com" 367 | } 368 | ], 369 | "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", 370 | "time": "2017-11-10T14:09:06+00:00" 371 | }, 372 | { 373 | "name": "phpdocumentor/type-resolver", 374 | "version": "0.4.0", 375 | "source": { 376 | "type": "git", 377 | "url": "https://github.com/phpDocumentor/TypeResolver.git", 378 | "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7" 379 | }, 380 | "dist": { 381 | "type": "zip", 382 | "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/9c977708995954784726e25d0cd1dddf4e65b0f7", 383 | "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7", 384 | "shasum": "" 385 | }, 386 | "require": { 387 | "php": "^5.5 || ^7.0", 388 | "phpdocumentor/reflection-common": "^1.0" 389 | }, 390 | "require-dev": { 391 | "mockery/mockery": "^0.9.4", 392 | "phpunit/phpunit": "^5.2||^4.8.24" 393 | }, 394 | "type": "library", 395 | "extra": { 396 | "branch-alias": { 397 | "dev-master": "1.0.x-dev" 398 | } 399 | }, 400 | "autoload": { 401 | "psr-4": { 402 | "phpDocumentor\\Reflection\\": [ 403 | "src/" 404 | ] 405 | } 406 | }, 407 | "notification-url": "https://packagist.org/downloads/", 408 | "license": [ 409 | "MIT" 410 | ], 411 | "authors": [ 412 | { 413 | "name": "Mike van Riel", 414 | "email": "me@mikevanriel.com" 415 | } 416 | ], 417 | "time": "2017-07-14T14:27:02+00:00" 418 | }, 419 | { 420 | "name": "phpspec/prophecy", 421 | "version": "1.8.0", 422 | "source": { 423 | "type": "git", 424 | "url": "https://github.com/phpspec/prophecy.git", 425 | "reference": "4ba436b55987b4bf311cb7c6ba82aa528aac0a06" 426 | }, 427 | "dist": { 428 | "type": "zip", 429 | "url": "https://api.github.com/repos/phpspec/prophecy/zipball/4ba436b55987b4bf311cb7c6ba82aa528aac0a06", 430 | "reference": "4ba436b55987b4bf311cb7c6ba82aa528aac0a06", 431 | "shasum": "" 432 | }, 433 | "require": { 434 | "doctrine/instantiator": "^1.0.2", 435 | "php": "^5.3|^7.0", 436 | "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0", 437 | "sebastian/comparator": "^1.1|^2.0|^3.0", 438 | "sebastian/recursion-context": "^1.0|^2.0|^3.0" 439 | }, 440 | "require-dev": { 441 | "phpspec/phpspec": "^2.5|^3.2", 442 | "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5 || ^7.1" 443 | }, 444 | "type": "library", 445 | "extra": { 446 | "branch-alias": { 447 | "dev-master": "1.8.x-dev" 448 | } 449 | }, 450 | "autoload": { 451 | "psr-0": { 452 | "Prophecy\\": "src/" 453 | } 454 | }, 455 | "notification-url": "https://packagist.org/downloads/", 456 | "license": [ 457 | "MIT" 458 | ], 459 | "authors": [ 460 | { 461 | "name": "Konstantin Kudryashov", 462 | "email": "ever.zet@gmail.com", 463 | "homepage": "http://everzet.com" 464 | }, 465 | { 466 | "name": "Marcello Duarte", 467 | "email": "marcello.duarte@gmail.com" 468 | } 469 | ], 470 | "description": "Highly opinionated mocking framework for PHP 5.3+", 471 | "homepage": "https://github.com/phpspec/prophecy", 472 | "keywords": [ 473 | "Double", 474 | "Dummy", 475 | "fake", 476 | "mock", 477 | "spy", 478 | "stub" 479 | ], 480 | "time": "2018-08-05T17:53:17+00:00" 481 | }, 482 | { 483 | "name": "phpunit/php-code-coverage", 484 | "version": "4.0.8", 485 | "source": { 486 | "type": "git", 487 | "url": "https://github.com/sebastianbergmann/php-code-coverage.git", 488 | "reference": "ef7b2f56815df854e66ceaee8ebe9393ae36a40d" 489 | }, 490 | "dist": { 491 | "type": "zip", 492 | "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/ef7b2f56815df854e66ceaee8ebe9393ae36a40d", 493 | "reference": "ef7b2f56815df854e66ceaee8ebe9393ae36a40d", 494 | "shasum": "" 495 | }, 496 | "require": { 497 | "ext-dom": "*", 498 | "ext-xmlwriter": "*", 499 | "php": "^5.6 || ^7.0", 500 | "phpunit/php-file-iterator": "^1.3", 501 | "phpunit/php-text-template": "^1.2", 502 | "phpunit/php-token-stream": "^1.4.2 || ^2.0", 503 | "sebastian/code-unit-reverse-lookup": "^1.0", 504 | "sebastian/environment": "^1.3.2 || ^2.0", 505 | "sebastian/version": "^1.0 || ^2.0" 506 | }, 507 | "require-dev": { 508 | "ext-xdebug": "^2.1.4", 509 | "phpunit/phpunit": "^5.7" 510 | }, 511 | "suggest": { 512 | "ext-xdebug": "^2.5.1" 513 | }, 514 | "type": "library", 515 | "extra": { 516 | "branch-alias": { 517 | "dev-master": "4.0.x-dev" 518 | } 519 | }, 520 | "autoload": { 521 | "classmap": [ 522 | "src/" 523 | ] 524 | }, 525 | "notification-url": "https://packagist.org/downloads/", 526 | "license": [ 527 | "BSD-3-Clause" 528 | ], 529 | "authors": [ 530 | { 531 | "name": "Sebastian Bergmann", 532 | "email": "sb@sebastian-bergmann.de", 533 | "role": "lead" 534 | } 535 | ], 536 | "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", 537 | "homepage": "https://github.com/sebastianbergmann/php-code-coverage", 538 | "keywords": [ 539 | "coverage", 540 | "testing", 541 | "xunit" 542 | ], 543 | "time": "2017-04-02T07:44:40+00:00" 544 | }, 545 | { 546 | "name": "phpunit/php-file-iterator", 547 | "version": "1.4.5", 548 | "source": { 549 | "type": "git", 550 | "url": "https://github.com/sebastianbergmann/php-file-iterator.git", 551 | "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4" 552 | }, 553 | "dist": { 554 | "type": "zip", 555 | "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/730b01bc3e867237eaac355e06a36b85dd93a8b4", 556 | "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4", 557 | "shasum": "" 558 | }, 559 | "require": { 560 | "php": ">=5.3.3" 561 | }, 562 | "type": "library", 563 | "extra": { 564 | "branch-alias": { 565 | "dev-master": "1.4.x-dev" 566 | } 567 | }, 568 | "autoload": { 569 | "classmap": [ 570 | "src/" 571 | ] 572 | }, 573 | "notification-url": "https://packagist.org/downloads/", 574 | "license": [ 575 | "BSD-3-Clause" 576 | ], 577 | "authors": [ 578 | { 579 | "name": "Sebastian Bergmann", 580 | "email": "sb@sebastian-bergmann.de", 581 | "role": "lead" 582 | } 583 | ], 584 | "description": "FilterIterator implementation that filters files based on a list of suffixes.", 585 | "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", 586 | "keywords": [ 587 | "filesystem", 588 | "iterator" 589 | ], 590 | "time": "2017-11-27T13:52:08+00:00" 591 | }, 592 | { 593 | "name": "phpunit/php-text-template", 594 | "version": "1.2.1", 595 | "source": { 596 | "type": "git", 597 | "url": "https://github.com/sebastianbergmann/php-text-template.git", 598 | "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" 599 | }, 600 | "dist": { 601 | "type": "zip", 602 | "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", 603 | "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", 604 | "shasum": "" 605 | }, 606 | "require": { 607 | "php": ">=5.3.3" 608 | }, 609 | "type": "library", 610 | "autoload": { 611 | "classmap": [ 612 | "src/" 613 | ] 614 | }, 615 | "notification-url": "https://packagist.org/downloads/", 616 | "license": [ 617 | "BSD-3-Clause" 618 | ], 619 | "authors": [ 620 | { 621 | "name": "Sebastian Bergmann", 622 | "email": "sebastian@phpunit.de", 623 | "role": "lead" 624 | } 625 | ], 626 | "description": "Simple template engine.", 627 | "homepage": "https://github.com/sebastianbergmann/php-text-template/", 628 | "keywords": [ 629 | "template" 630 | ], 631 | "time": "2015-06-21T13:50:34+00:00" 632 | }, 633 | { 634 | "name": "phpunit/php-timer", 635 | "version": "1.0.9", 636 | "source": { 637 | "type": "git", 638 | "url": "https://github.com/sebastianbergmann/php-timer.git", 639 | "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f" 640 | }, 641 | "dist": { 642 | "type": "zip", 643 | "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", 644 | "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", 645 | "shasum": "" 646 | }, 647 | "require": { 648 | "php": "^5.3.3 || ^7.0" 649 | }, 650 | "require-dev": { 651 | "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" 652 | }, 653 | "type": "library", 654 | "extra": { 655 | "branch-alias": { 656 | "dev-master": "1.0-dev" 657 | } 658 | }, 659 | "autoload": { 660 | "classmap": [ 661 | "src/" 662 | ] 663 | }, 664 | "notification-url": "https://packagist.org/downloads/", 665 | "license": [ 666 | "BSD-3-Clause" 667 | ], 668 | "authors": [ 669 | { 670 | "name": "Sebastian Bergmann", 671 | "email": "sb@sebastian-bergmann.de", 672 | "role": "lead" 673 | } 674 | ], 675 | "description": "Utility class for timing", 676 | "homepage": "https://github.com/sebastianbergmann/php-timer/", 677 | "keywords": [ 678 | "timer" 679 | ], 680 | "time": "2017-02-26T11:10:40+00:00" 681 | }, 682 | { 683 | "name": "phpunit/php-token-stream", 684 | "version": "1.4.12", 685 | "source": { 686 | "type": "git", 687 | "url": "https://github.com/sebastianbergmann/php-token-stream.git", 688 | "reference": "1ce90ba27c42e4e44e6d8458241466380b51fa16" 689 | }, 690 | "dist": { 691 | "type": "zip", 692 | "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/1ce90ba27c42e4e44e6d8458241466380b51fa16", 693 | "reference": "1ce90ba27c42e4e44e6d8458241466380b51fa16", 694 | "shasum": "" 695 | }, 696 | "require": { 697 | "ext-tokenizer": "*", 698 | "php": ">=5.3.3" 699 | }, 700 | "require-dev": { 701 | "phpunit/phpunit": "~4.2" 702 | }, 703 | "type": "library", 704 | "extra": { 705 | "branch-alias": { 706 | "dev-master": "1.4-dev" 707 | } 708 | }, 709 | "autoload": { 710 | "classmap": [ 711 | "src/" 712 | ] 713 | }, 714 | "notification-url": "https://packagist.org/downloads/", 715 | "license": [ 716 | "BSD-3-Clause" 717 | ], 718 | "authors": [ 719 | { 720 | "name": "Sebastian Bergmann", 721 | "email": "sebastian@phpunit.de" 722 | } 723 | ], 724 | "description": "Wrapper around PHP's tokenizer extension.", 725 | "homepage": "https://github.com/sebastianbergmann/php-token-stream/", 726 | "keywords": [ 727 | "tokenizer" 728 | ], 729 | "time": "2017-12-04T08:55:13+00:00" 730 | }, 731 | { 732 | "name": "phpunit/phpunit", 733 | "version": "5.7.27", 734 | "source": { 735 | "type": "git", 736 | "url": "https://github.com/sebastianbergmann/phpunit.git", 737 | "reference": "b7803aeca3ccb99ad0a506fa80b64cd6a56bbc0c" 738 | }, 739 | "dist": { 740 | "type": "zip", 741 | "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/b7803aeca3ccb99ad0a506fa80b64cd6a56bbc0c", 742 | "reference": "b7803aeca3ccb99ad0a506fa80b64cd6a56bbc0c", 743 | "shasum": "" 744 | }, 745 | "require": { 746 | "ext-dom": "*", 747 | "ext-json": "*", 748 | "ext-libxml": "*", 749 | "ext-mbstring": "*", 750 | "ext-xml": "*", 751 | "myclabs/deep-copy": "~1.3", 752 | "php": "^5.6 || ^7.0", 753 | "phpspec/prophecy": "^1.6.2", 754 | "phpunit/php-code-coverage": "^4.0.4", 755 | "phpunit/php-file-iterator": "~1.4", 756 | "phpunit/php-text-template": "~1.2", 757 | "phpunit/php-timer": "^1.0.6", 758 | "phpunit/phpunit-mock-objects": "^3.2", 759 | "sebastian/comparator": "^1.2.4", 760 | "sebastian/diff": "^1.4.3", 761 | "sebastian/environment": "^1.3.4 || ^2.0", 762 | "sebastian/exporter": "~2.0", 763 | "sebastian/global-state": "^1.1", 764 | "sebastian/object-enumerator": "~2.0", 765 | "sebastian/resource-operations": "~1.0", 766 | "sebastian/version": "^1.0.6|^2.0.1", 767 | "symfony/yaml": "~2.1|~3.0|~4.0" 768 | }, 769 | "conflict": { 770 | "phpdocumentor/reflection-docblock": "3.0.2" 771 | }, 772 | "require-dev": { 773 | "ext-pdo": "*" 774 | }, 775 | "suggest": { 776 | "ext-xdebug": "*", 777 | "phpunit/php-invoker": "~1.1" 778 | }, 779 | "bin": [ 780 | "phpunit" 781 | ], 782 | "type": "library", 783 | "extra": { 784 | "branch-alias": { 785 | "dev-master": "5.7.x-dev" 786 | } 787 | }, 788 | "autoload": { 789 | "classmap": [ 790 | "src/" 791 | ] 792 | }, 793 | "notification-url": "https://packagist.org/downloads/", 794 | "license": [ 795 | "BSD-3-Clause" 796 | ], 797 | "authors": [ 798 | { 799 | "name": "Sebastian Bergmann", 800 | "email": "sebastian@phpunit.de", 801 | "role": "lead" 802 | } 803 | ], 804 | "description": "The PHP Unit Testing framework.", 805 | "homepage": "https://phpunit.de/", 806 | "keywords": [ 807 | "phpunit", 808 | "testing", 809 | "xunit" 810 | ], 811 | "time": "2018-02-01T05:50:59+00:00" 812 | }, 813 | { 814 | "name": "phpunit/phpunit-mock-objects", 815 | "version": "3.4.4", 816 | "source": { 817 | "type": "git", 818 | "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", 819 | "reference": "a23b761686d50a560cc56233b9ecf49597cc9118" 820 | }, 821 | "dist": { 822 | "type": "zip", 823 | "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/a23b761686d50a560cc56233b9ecf49597cc9118", 824 | "reference": "a23b761686d50a560cc56233b9ecf49597cc9118", 825 | "shasum": "" 826 | }, 827 | "require": { 828 | "doctrine/instantiator": "^1.0.2", 829 | "php": "^5.6 || ^7.0", 830 | "phpunit/php-text-template": "^1.2", 831 | "sebastian/exporter": "^1.2 || ^2.0" 832 | }, 833 | "conflict": { 834 | "phpunit/phpunit": "<5.4.0" 835 | }, 836 | "require-dev": { 837 | "phpunit/phpunit": "^5.4" 838 | }, 839 | "suggest": { 840 | "ext-soap": "*" 841 | }, 842 | "type": "library", 843 | "extra": { 844 | "branch-alias": { 845 | "dev-master": "3.2.x-dev" 846 | } 847 | }, 848 | "autoload": { 849 | "classmap": [ 850 | "src/" 851 | ] 852 | }, 853 | "notification-url": "https://packagist.org/downloads/", 854 | "license": [ 855 | "BSD-3-Clause" 856 | ], 857 | "authors": [ 858 | { 859 | "name": "Sebastian Bergmann", 860 | "email": "sb@sebastian-bergmann.de", 861 | "role": "lead" 862 | } 863 | ], 864 | "description": "Mock Object library for PHPUnit", 865 | "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", 866 | "keywords": [ 867 | "mock", 868 | "xunit" 869 | ], 870 | "time": "2017-06-30T09:13:00+00:00" 871 | }, 872 | { 873 | "name": "sebastian/code-unit-reverse-lookup", 874 | "version": "1.0.1", 875 | "source": { 876 | "type": "git", 877 | "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", 878 | "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18" 879 | }, 880 | "dist": { 881 | "type": "zip", 882 | "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/4419fcdb5eabb9caa61a27c7a1db532a6b55dd18", 883 | "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18", 884 | "shasum": "" 885 | }, 886 | "require": { 887 | "php": "^5.6 || ^7.0" 888 | }, 889 | "require-dev": { 890 | "phpunit/phpunit": "^5.7 || ^6.0" 891 | }, 892 | "type": "library", 893 | "extra": { 894 | "branch-alias": { 895 | "dev-master": "1.0.x-dev" 896 | } 897 | }, 898 | "autoload": { 899 | "classmap": [ 900 | "src/" 901 | ] 902 | }, 903 | "notification-url": "https://packagist.org/downloads/", 904 | "license": [ 905 | "BSD-3-Clause" 906 | ], 907 | "authors": [ 908 | { 909 | "name": "Sebastian Bergmann", 910 | "email": "sebastian@phpunit.de" 911 | } 912 | ], 913 | "description": "Looks up which function or method a line of code belongs to", 914 | "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", 915 | "time": "2017-03-04T06:30:41+00:00" 916 | }, 917 | { 918 | "name": "sebastian/comparator", 919 | "version": "1.2.4", 920 | "source": { 921 | "type": "git", 922 | "url": "https://github.com/sebastianbergmann/comparator.git", 923 | "reference": "2b7424b55f5047b47ac6e5ccb20b2aea4011d9be" 924 | }, 925 | "dist": { 926 | "type": "zip", 927 | "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/2b7424b55f5047b47ac6e5ccb20b2aea4011d9be", 928 | "reference": "2b7424b55f5047b47ac6e5ccb20b2aea4011d9be", 929 | "shasum": "" 930 | }, 931 | "require": { 932 | "php": ">=5.3.3", 933 | "sebastian/diff": "~1.2", 934 | "sebastian/exporter": "~1.2 || ~2.0" 935 | }, 936 | "require-dev": { 937 | "phpunit/phpunit": "~4.4" 938 | }, 939 | "type": "library", 940 | "extra": { 941 | "branch-alias": { 942 | "dev-master": "1.2.x-dev" 943 | } 944 | }, 945 | "autoload": { 946 | "classmap": [ 947 | "src/" 948 | ] 949 | }, 950 | "notification-url": "https://packagist.org/downloads/", 951 | "license": [ 952 | "BSD-3-Clause" 953 | ], 954 | "authors": [ 955 | { 956 | "name": "Jeff Welch", 957 | "email": "whatthejeff@gmail.com" 958 | }, 959 | { 960 | "name": "Volker Dusch", 961 | "email": "github@wallbash.com" 962 | }, 963 | { 964 | "name": "Bernhard Schussek", 965 | "email": "bschussek@2bepublished.at" 966 | }, 967 | { 968 | "name": "Sebastian Bergmann", 969 | "email": "sebastian@phpunit.de" 970 | } 971 | ], 972 | "description": "Provides the functionality to compare PHP values for equality", 973 | "homepage": "http://www.github.com/sebastianbergmann/comparator", 974 | "keywords": [ 975 | "comparator", 976 | "compare", 977 | "equality" 978 | ], 979 | "time": "2017-01-29T09:50:25+00:00" 980 | }, 981 | { 982 | "name": "sebastian/diff", 983 | "version": "1.4.3", 984 | "source": { 985 | "type": "git", 986 | "url": "https://github.com/sebastianbergmann/diff.git", 987 | "reference": "7f066a26a962dbe58ddea9f72a4e82874a3975a4" 988 | }, 989 | "dist": { 990 | "type": "zip", 991 | "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/7f066a26a962dbe58ddea9f72a4e82874a3975a4", 992 | "reference": "7f066a26a962dbe58ddea9f72a4e82874a3975a4", 993 | "shasum": "" 994 | }, 995 | "require": { 996 | "php": "^5.3.3 || ^7.0" 997 | }, 998 | "require-dev": { 999 | "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" 1000 | }, 1001 | "type": "library", 1002 | "extra": { 1003 | "branch-alias": { 1004 | "dev-master": "1.4-dev" 1005 | } 1006 | }, 1007 | "autoload": { 1008 | "classmap": [ 1009 | "src/" 1010 | ] 1011 | }, 1012 | "notification-url": "https://packagist.org/downloads/", 1013 | "license": [ 1014 | "BSD-3-Clause" 1015 | ], 1016 | "authors": [ 1017 | { 1018 | "name": "Kore Nordmann", 1019 | "email": "mail@kore-nordmann.de" 1020 | }, 1021 | { 1022 | "name": "Sebastian Bergmann", 1023 | "email": "sebastian@phpunit.de" 1024 | } 1025 | ], 1026 | "description": "Diff implementation", 1027 | "homepage": "https://github.com/sebastianbergmann/diff", 1028 | "keywords": [ 1029 | "diff" 1030 | ], 1031 | "time": "2017-05-22T07:24:03+00:00" 1032 | }, 1033 | { 1034 | "name": "sebastian/environment", 1035 | "version": "2.0.0", 1036 | "source": { 1037 | "type": "git", 1038 | "url": "https://github.com/sebastianbergmann/environment.git", 1039 | "reference": "5795ffe5dc5b02460c3e34222fee8cbe245d8fac" 1040 | }, 1041 | "dist": { 1042 | "type": "zip", 1043 | "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/5795ffe5dc5b02460c3e34222fee8cbe245d8fac", 1044 | "reference": "5795ffe5dc5b02460c3e34222fee8cbe245d8fac", 1045 | "shasum": "" 1046 | }, 1047 | "require": { 1048 | "php": "^5.6 || ^7.0" 1049 | }, 1050 | "require-dev": { 1051 | "phpunit/phpunit": "^5.0" 1052 | }, 1053 | "type": "library", 1054 | "extra": { 1055 | "branch-alias": { 1056 | "dev-master": "2.0.x-dev" 1057 | } 1058 | }, 1059 | "autoload": { 1060 | "classmap": [ 1061 | "src/" 1062 | ] 1063 | }, 1064 | "notification-url": "https://packagist.org/downloads/", 1065 | "license": [ 1066 | "BSD-3-Clause" 1067 | ], 1068 | "authors": [ 1069 | { 1070 | "name": "Sebastian Bergmann", 1071 | "email": "sebastian@phpunit.de" 1072 | } 1073 | ], 1074 | "description": "Provides functionality to handle HHVM/PHP environments", 1075 | "homepage": "http://www.github.com/sebastianbergmann/environment", 1076 | "keywords": [ 1077 | "Xdebug", 1078 | "environment", 1079 | "hhvm" 1080 | ], 1081 | "time": "2016-11-26T07:53:53+00:00" 1082 | }, 1083 | { 1084 | "name": "sebastian/exporter", 1085 | "version": "2.0.0", 1086 | "source": { 1087 | "type": "git", 1088 | "url": "https://github.com/sebastianbergmann/exporter.git", 1089 | "reference": "ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4" 1090 | }, 1091 | "dist": { 1092 | "type": "zip", 1093 | "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4", 1094 | "reference": "ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4", 1095 | "shasum": "" 1096 | }, 1097 | "require": { 1098 | "php": ">=5.3.3", 1099 | "sebastian/recursion-context": "~2.0" 1100 | }, 1101 | "require-dev": { 1102 | "ext-mbstring": "*", 1103 | "phpunit/phpunit": "~4.4" 1104 | }, 1105 | "type": "library", 1106 | "extra": { 1107 | "branch-alias": { 1108 | "dev-master": "2.0.x-dev" 1109 | } 1110 | }, 1111 | "autoload": { 1112 | "classmap": [ 1113 | "src/" 1114 | ] 1115 | }, 1116 | "notification-url": "https://packagist.org/downloads/", 1117 | "license": [ 1118 | "BSD-3-Clause" 1119 | ], 1120 | "authors": [ 1121 | { 1122 | "name": "Jeff Welch", 1123 | "email": "whatthejeff@gmail.com" 1124 | }, 1125 | { 1126 | "name": "Volker Dusch", 1127 | "email": "github@wallbash.com" 1128 | }, 1129 | { 1130 | "name": "Bernhard Schussek", 1131 | "email": "bschussek@2bepublished.at" 1132 | }, 1133 | { 1134 | "name": "Sebastian Bergmann", 1135 | "email": "sebastian@phpunit.de" 1136 | }, 1137 | { 1138 | "name": "Adam Harvey", 1139 | "email": "aharvey@php.net" 1140 | } 1141 | ], 1142 | "description": "Provides the functionality to export PHP variables for visualization", 1143 | "homepage": "http://www.github.com/sebastianbergmann/exporter", 1144 | "keywords": [ 1145 | "export", 1146 | "exporter" 1147 | ], 1148 | "time": "2016-11-19T08:54:04+00:00" 1149 | }, 1150 | { 1151 | "name": "sebastian/global-state", 1152 | "version": "1.1.1", 1153 | "source": { 1154 | "type": "git", 1155 | "url": "https://github.com/sebastianbergmann/global-state.git", 1156 | "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4" 1157 | }, 1158 | "dist": { 1159 | "type": "zip", 1160 | "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bc37d50fea7d017d3d340f230811c9f1d7280af4", 1161 | "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4", 1162 | "shasum": "" 1163 | }, 1164 | "require": { 1165 | "php": ">=5.3.3" 1166 | }, 1167 | "require-dev": { 1168 | "phpunit/phpunit": "~4.2" 1169 | }, 1170 | "suggest": { 1171 | "ext-uopz": "*" 1172 | }, 1173 | "type": "library", 1174 | "extra": { 1175 | "branch-alias": { 1176 | "dev-master": "1.0-dev" 1177 | } 1178 | }, 1179 | "autoload": { 1180 | "classmap": [ 1181 | "src/" 1182 | ] 1183 | }, 1184 | "notification-url": "https://packagist.org/downloads/", 1185 | "license": [ 1186 | "BSD-3-Clause" 1187 | ], 1188 | "authors": [ 1189 | { 1190 | "name": "Sebastian Bergmann", 1191 | "email": "sebastian@phpunit.de" 1192 | } 1193 | ], 1194 | "description": "Snapshotting of global state", 1195 | "homepage": "http://www.github.com/sebastianbergmann/global-state", 1196 | "keywords": [ 1197 | "global state" 1198 | ], 1199 | "time": "2015-10-12T03:26:01+00:00" 1200 | }, 1201 | { 1202 | "name": "sebastian/object-enumerator", 1203 | "version": "2.0.1", 1204 | "source": { 1205 | "type": "git", 1206 | "url": "https://github.com/sebastianbergmann/object-enumerator.git", 1207 | "reference": "1311872ac850040a79c3c058bea3e22d0f09cbb7" 1208 | }, 1209 | "dist": { 1210 | "type": "zip", 1211 | "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/1311872ac850040a79c3c058bea3e22d0f09cbb7", 1212 | "reference": "1311872ac850040a79c3c058bea3e22d0f09cbb7", 1213 | "shasum": "" 1214 | }, 1215 | "require": { 1216 | "php": ">=5.6", 1217 | "sebastian/recursion-context": "~2.0" 1218 | }, 1219 | "require-dev": { 1220 | "phpunit/phpunit": "~5" 1221 | }, 1222 | "type": "library", 1223 | "extra": { 1224 | "branch-alias": { 1225 | "dev-master": "2.0.x-dev" 1226 | } 1227 | }, 1228 | "autoload": { 1229 | "classmap": [ 1230 | "src/" 1231 | ] 1232 | }, 1233 | "notification-url": "https://packagist.org/downloads/", 1234 | "license": [ 1235 | "BSD-3-Clause" 1236 | ], 1237 | "authors": [ 1238 | { 1239 | "name": "Sebastian Bergmann", 1240 | "email": "sebastian@phpunit.de" 1241 | } 1242 | ], 1243 | "description": "Traverses array structures and object graphs to enumerate all referenced objects", 1244 | "homepage": "https://github.com/sebastianbergmann/object-enumerator/", 1245 | "time": "2017-02-18T15:18:39+00:00" 1246 | }, 1247 | { 1248 | "name": "sebastian/recursion-context", 1249 | "version": "2.0.0", 1250 | "source": { 1251 | "type": "git", 1252 | "url": "https://github.com/sebastianbergmann/recursion-context.git", 1253 | "reference": "2c3ba150cbec723aa057506e73a8d33bdb286c9a" 1254 | }, 1255 | "dist": { 1256 | "type": "zip", 1257 | "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/2c3ba150cbec723aa057506e73a8d33bdb286c9a", 1258 | "reference": "2c3ba150cbec723aa057506e73a8d33bdb286c9a", 1259 | "shasum": "" 1260 | }, 1261 | "require": { 1262 | "php": ">=5.3.3" 1263 | }, 1264 | "require-dev": { 1265 | "phpunit/phpunit": "~4.4" 1266 | }, 1267 | "type": "library", 1268 | "extra": { 1269 | "branch-alias": { 1270 | "dev-master": "2.0.x-dev" 1271 | } 1272 | }, 1273 | "autoload": { 1274 | "classmap": [ 1275 | "src/" 1276 | ] 1277 | }, 1278 | "notification-url": "https://packagist.org/downloads/", 1279 | "license": [ 1280 | "BSD-3-Clause" 1281 | ], 1282 | "authors": [ 1283 | { 1284 | "name": "Jeff Welch", 1285 | "email": "whatthejeff@gmail.com" 1286 | }, 1287 | { 1288 | "name": "Sebastian Bergmann", 1289 | "email": "sebastian@phpunit.de" 1290 | }, 1291 | { 1292 | "name": "Adam Harvey", 1293 | "email": "aharvey@php.net" 1294 | } 1295 | ], 1296 | "description": "Provides functionality to recursively process PHP variables", 1297 | "homepage": "http://www.github.com/sebastianbergmann/recursion-context", 1298 | "time": "2016-11-19T07:33:16+00:00" 1299 | }, 1300 | { 1301 | "name": "sebastian/resource-operations", 1302 | "version": "1.0.0", 1303 | "source": { 1304 | "type": "git", 1305 | "url": "https://github.com/sebastianbergmann/resource-operations.git", 1306 | "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52" 1307 | }, 1308 | "dist": { 1309 | "type": "zip", 1310 | "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", 1311 | "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", 1312 | "shasum": "" 1313 | }, 1314 | "require": { 1315 | "php": ">=5.6.0" 1316 | }, 1317 | "type": "library", 1318 | "extra": { 1319 | "branch-alias": { 1320 | "dev-master": "1.0.x-dev" 1321 | } 1322 | }, 1323 | "autoload": { 1324 | "classmap": [ 1325 | "src/" 1326 | ] 1327 | }, 1328 | "notification-url": "https://packagist.org/downloads/", 1329 | "license": [ 1330 | "BSD-3-Clause" 1331 | ], 1332 | "authors": [ 1333 | { 1334 | "name": "Sebastian Bergmann", 1335 | "email": "sebastian@phpunit.de" 1336 | } 1337 | ], 1338 | "description": "Provides a list of PHP built-in functions that operate on resources", 1339 | "homepage": "https://www.github.com/sebastianbergmann/resource-operations", 1340 | "time": "2015-07-28T20:34:47+00:00" 1341 | }, 1342 | { 1343 | "name": "sebastian/version", 1344 | "version": "2.0.1", 1345 | "source": { 1346 | "type": "git", 1347 | "url": "https://github.com/sebastianbergmann/version.git", 1348 | "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019" 1349 | }, 1350 | "dist": { 1351 | "type": "zip", 1352 | "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/99732be0ddb3361e16ad77b68ba41efc8e979019", 1353 | "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019", 1354 | "shasum": "" 1355 | }, 1356 | "require": { 1357 | "php": ">=5.6" 1358 | }, 1359 | "type": "library", 1360 | "extra": { 1361 | "branch-alias": { 1362 | "dev-master": "2.0.x-dev" 1363 | } 1364 | }, 1365 | "autoload": { 1366 | "classmap": [ 1367 | "src/" 1368 | ] 1369 | }, 1370 | "notification-url": "https://packagist.org/downloads/", 1371 | "license": [ 1372 | "BSD-3-Clause" 1373 | ], 1374 | "authors": [ 1375 | { 1376 | "name": "Sebastian Bergmann", 1377 | "email": "sebastian@phpunit.de", 1378 | "role": "lead" 1379 | } 1380 | ], 1381 | "description": "Library that helps with managing the version number of Git-hosted PHP projects", 1382 | "homepage": "https://github.com/sebastianbergmann/version", 1383 | "time": "2016-10-03T07:35:21+00:00" 1384 | }, 1385 | { 1386 | "name": "symfony/polyfill-ctype", 1387 | "version": "v1.9.0", 1388 | "source": { 1389 | "type": "git", 1390 | "url": "https://github.com/symfony/polyfill-ctype.git", 1391 | "reference": "e3d826245268269cd66f8326bd8bc066687b4a19" 1392 | }, 1393 | "dist": { 1394 | "type": "zip", 1395 | "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/e3d826245268269cd66f8326bd8bc066687b4a19", 1396 | "reference": "e3d826245268269cd66f8326bd8bc066687b4a19", 1397 | "shasum": "" 1398 | }, 1399 | "require": { 1400 | "php": ">=5.3.3" 1401 | }, 1402 | "suggest": { 1403 | "ext-ctype": "For best performance" 1404 | }, 1405 | "type": "library", 1406 | "extra": { 1407 | "branch-alias": { 1408 | "dev-master": "1.9-dev" 1409 | } 1410 | }, 1411 | "autoload": { 1412 | "psr-4": { 1413 | "Symfony\\Polyfill\\Ctype\\": "" 1414 | }, 1415 | "files": [ 1416 | "bootstrap.php" 1417 | ] 1418 | }, 1419 | "notification-url": "https://packagist.org/downloads/", 1420 | "license": [ 1421 | "MIT" 1422 | ], 1423 | "authors": [ 1424 | { 1425 | "name": "Symfony Community", 1426 | "homepage": "https://symfony.com/contributors" 1427 | }, 1428 | { 1429 | "name": "Gert de Pagter", 1430 | "email": "BackEndTea@gmail.com" 1431 | } 1432 | ], 1433 | "description": "Symfony polyfill for ctype functions", 1434 | "homepage": "https://symfony.com", 1435 | "keywords": [ 1436 | "compatibility", 1437 | "ctype", 1438 | "polyfill", 1439 | "portable" 1440 | ], 1441 | "time": "2018-08-06T14:22:27+00:00" 1442 | }, 1443 | { 1444 | "name": "symfony/yaml", 1445 | "version": "v3.4.15", 1446 | "source": { 1447 | "type": "git", 1448 | "url": "https://github.com/symfony/yaml.git", 1449 | "reference": "c2f4812ead9f847cb69e90917ca7502e6892d6b8" 1450 | }, 1451 | "dist": { 1452 | "type": "zip", 1453 | "url": "https://api.github.com/repos/symfony/yaml/zipball/c2f4812ead9f847cb69e90917ca7502e6892d6b8", 1454 | "reference": "c2f4812ead9f847cb69e90917ca7502e6892d6b8", 1455 | "shasum": "" 1456 | }, 1457 | "require": { 1458 | "php": "^5.5.9|>=7.0.8", 1459 | "symfony/polyfill-ctype": "~1.8" 1460 | }, 1461 | "conflict": { 1462 | "symfony/console": "<3.4" 1463 | }, 1464 | "require-dev": { 1465 | "symfony/console": "~3.4|~4.0" 1466 | }, 1467 | "suggest": { 1468 | "symfony/console": "For validating YAML files using the lint command" 1469 | }, 1470 | "type": "library", 1471 | "extra": { 1472 | "branch-alias": { 1473 | "dev-master": "3.4-dev" 1474 | } 1475 | }, 1476 | "autoload": { 1477 | "psr-4": { 1478 | "Symfony\\Component\\Yaml\\": "" 1479 | }, 1480 | "exclude-from-classmap": [ 1481 | "/Tests/" 1482 | ] 1483 | }, 1484 | "notification-url": "https://packagist.org/downloads/", 1485 | "license": [ 1486 | "MIT" 1487 | ], 1488 | "authors": [ 1489 | { 1490 | "name": "Fabien Potencier", 1491 | "email": "fabien@symfony.com" 1492 | }, 1493 | { 1494 | "name": "Symfony Community", 1495 | "homepage": "https://symfony.com/contributors" 1496 | } 1497 | ], 1498 | "description": "Symfony Yaml Component", 1499 | "homepage": "https://symfony.com", 1500 | "time": "2018-08-10T07:34:36+00:00" 1501 | }, 1502 | { 1503 | "name": "webmozart/assert", 1504 | "version": "1.3.0", 1505 | "source": { 1506 | "type": "git", 1507 | "url": "https://github.com/webmozart/assert.git", 1508 | "reference": "0df1908962e7a3071564e857d86874dad1ef204a" 1509 | }, 1510 | "dist": { 1511 | "type": "zip", 1512 | "url": "https://api.github.com/repos/webmozart/assert/zipball/0df1908962e7a3071564e857d86874dad1ef204a", 1513 | "reference": "0df1908962e7a3071564e857d86874dad1ef204a", 1514 | "shasum": "" 1515 | }, 1516 | "require": { 1517 | "php": "^5.3.3 || ^7.0" 1518 | }, 1519 | "require-dev": { 1520 | "phpunit/phpunit": "^4.6", 1521 | "sebastian/version": "^1.0.1" 1522 | }, 1523 | "type": "library", 1524 | "extra": { 1525 | "branch-alias": { 1526 | "dev-master": "1.3-dev" 1527 | } 1528 | }, 1529 | "autoload": { 1530 | "psr-4": { 1531 | "Webmozart\\Assert\\": "src/" 1532 | } 1533 | }, 1534 | "notification-url": "https://packagist.org/downloads/", 1535 | "license": [ 1536 | "MIT" 1537 | ], 1538 | "authors": [ 1539 | { 1540 | "name": "Bernhard Schussek", 1541 | "email": "bschussek@gmail.com" 1542 | } 1543 | ], 1544 | "description": "Assertions to validate method input/output with nice error messages.", 1545 | "keywords": [ 1546 | "assert", 1547 | "check", 1548 | "validate" 1549 | ], 1550 | "time": "2018-01-29T19:49:41+00:00" 1551 | } 1552 | ], 1553 | "aliases": [], 1554 | "minimum-stability": "stable", 1555 | "stability-flags": [], 1556 | "prefer-stable": false, 1557 | "prefer-lowest": false, 1558 | "platform": { 1559 | "php": ">=5.6 || >=7.0 || >=7.1 || >=7.2" 1560 | }, 1561 | "platform-dev": [] 1562 | } 1563 | -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 20 | 21 | 22 | 23 | 24 | 25 | src 26 | 27 | 28 | 29 | 30 | tests 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /resources/backgrounds/bg1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LordDashMe/php-simple-captcha/256fa094ad6a8f205623f5ebda8ad8065e31bd64/resources/backgrounds/bg1.png -------------------------------------------------------------------------------- /resources/backgrounds/bg2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LordDashMe/php-simple-captcha/256fa094ad6a8f205623f5ebda8ad8065e31bd64/resources/backgrounds/bg2.png -------------------------------------------------------------------------------- /resources/backgrounds/bg3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LordDashMe/php-simple-captcha/256fa094ad6a8f205623f5ebda8ad8065e31bd64/resources/backgrounds/bg3.png -------------------------------------------------------------------------------- /resources/backgrounds/bg4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LordDashMe/php-simple-captcha/256fa094ad6a8f205623f5ebda8ad8065e31bd64/resources/backgrounds/bg4.png -------------------------------------------------------------------------------- /resources/backgrounds/bg5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LordDashMe/php-simple-captcha/256fa094ad6a8f205623f5ebda8ad8065e31bd64/resources/backgrounds/bg5.png -------------------------------------------------------------------------------- /resources/backgrounds/bg6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LordDashMe/php-simple-captcha/256fa094ad6a8f205623f5ebda8ad8065e31bd64/resources/backgrounds/bg6.png -------------------------------------------------------------------------------- /resources/backgrounds/bg7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LordDashMe/php-simple-captcha/256fa094ad6a8f205623f5ebda8ad8065e31bd64/resources/backgrounds/bg7.png -------------------------------------------------------------------------------- /resources/backgrounds/bg8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LordDashMe/php-simple-captcha/256fa094ad6a8f205623f5ebda8ad8065e31bd64/resources/backgrounds/bg8.png -------------------------------------------------------------------------------- /resources/fonts/capsmall_clean.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LordDashMe/php-simple-captcha/256fa094ad6a8f205623f5ebda8ad8065e31bd64/resources/fonts/capsmall_clean.ttf -------------------------------------------------------------------------------- /resources/img/sample1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LordDashMe/php-simple-captcha/256fa094ad6a8f205623f5ebda8ad8065e31bd64/resources/img/sample1.png -------------------------------------------------------------------------------- /resources/img/sample2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LordDashMe/php-simple-captcha/256fa094ad6a8f205623f5ebda8ad8065e31bd64/resources/img/sample2.png -------------------------------------------------------------------------------- /resources/img/sample3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LordDashMe/php-simple-captcha/256fa094ad6a8f205623f5ebda8ad8065e31bd64/resources/img/sample3.png -------------------------------------------------------------------------------- /resources/img/sample4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LordDashMe/php-simple-captcha/256fa094ad6a8f205623f5ebda8ad8065e31bd64/resources/img/sample4.png -------------------------------------------------------------------------------- /sample/login.php: -------------------------------------------------------------------------------- 1 | code(); 9 | $captcha->image(); 10 | $captcha->storeSession(); 11 | 12 | ?> 13 | 14 | 15 | 16 | PHP Simple Captcha 17 | 18 | 19 |
20 | 21 | 22 |
23 |
24 | 25 | 26 |
27 |
28 | 29 |
30 | 31 |
32 |
33 | 34 |
35 | 36 | 37 | -------------------------------------------------------------------------------- /sample/validate-login.php: -------------------------------------------------------------------------------- 1 | getSession(); 13 | 14 | if ($_POST['user_captcha_code'] === $data['code']) { 15 | echo 'Code is valid!'; 16 | } else { 17 | echo 'Code is invalid!'; 18 | } 19 | -------------------------------------------------------------------------------- /src/Captcha.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace LordDashMe\SimpleCaptcha; 13 | 14 | use LordDashMe\SimpleCaptcha\Utility\HexToRGB; 15 | 16 | /** 17 | * Captcha Class. 18 | * 19 | * A simple captcha package that suite to any type of web application built on php. 20 | * 21 | * @author Joshua Clifford Reyes 22 | */ 23 | class Captcha 24 | { 25 | /** 26 | * The default config for the simple captcha. 27 | * This can be override by passing an array of config 28 | * in the initialization process of the class. 29 | * 30 | * @return array 31 | */ 32 | protected $config = array( 33 | 'session_name' => 'ldm-simple-captcha', 34 | 'session_index_name' => 'LDM_SIMPLE_CAPTCHA', 35 | 'session_https' => false, 36 | 'session_http_only' => true, 37 | 'font_color' => '#000', 38 | 'font_size_min' => 26, 39 | 'font_size_max' => 28, 40 | 'angle_min' => 0, 41 | 'angle_max' => 9, 42 | 'shadow' => true, 43 | 'shadow_color' => '#fff', 44 | 'shadow_offset_x' => -3, 45 | 'shadow_offset_y' => 1, 46 | 'backgrounds' => array( 47 | 'bg1.png', 48 | 'bg2.png', 49 | 'bg3.png', 50 | 'bg4.png', 51 | 'bg5.png', 52 | 'bg6.png', 53 | 'bg7.png', 54 | 'bg8.png' 55 | ), 56 | 'fonts' => array( 57 | 'capsmall_clean.ttf' 58 | ) 59 | ); 60 | 61 | /** 62 | * The captcha generated unique code. 63 | * 64 | * @return string 65 | */ 66 | protected $code = ''; 67 | 68 | /** 69 | * The captcha generated image code. 70 | * 71 | * @return string 72 | */ 73 | protected $image = ''; 74 | 75 | /** 76 | * The class constructor. 77 | * 78 | * @param array $config Override the default config of the captcha when 79 | * the class initialized. 80 | * 81 | * @return void 82 | */ 83 | public function __construct($config = array()) 84 | { 85 | $this->init($config); 86 | } 87 | 88 | /** 89 | * The sub method for the class constructor. 90 | * 91 | * @param array $config To override the default config of the captcha. 92 | * 93 | * @return void 94 | */ 95 | public function init($config = array()) 96 | { 97 | $this->config = \array_merge($this->config, $this->configRestriction($config)); 98 | } 99 | 100 | /** 101 | * The configuration restriction, this will reset the input config into 102 | * default values to avoid any conflicts in the process later on. 103 | * 104 | * @param array $config The unfiltered input config. 105 | * 106 | * @return array 107 | */ 108 | protected function configRestriction($config) 109 | { 110 | return $this->configAngleRestriction( 111 | $this->configFontSizeRestriction($config) 112 | ); 113 | } 114 | 115 | /** 116 | * Config restriction for the angle setup. This restrict important values 117 | * and restore to default value if detected a violation. 118 | * 119 | * @param array $config 120 | * 121 | * @return array 122 | */ 123 | protected function configAngleRestriction($config) 124 | { 125 | if(isset($config['angle_min']) && $config['angle_min'] < 0) { 126 | $config['angle_min'] = 0; 127 | } 128 | 129 | if(isset($config['angle_max']) && $config['angle_max'] > 10) { 130 | $config['angle_max'] = 10; 131 | } 132 | 133 | if (isset($config['angle_max']) && isset($config['angle_min'])) { 134 | if ($config['angle_max'] < $config['angle_min']) { 135 | $config['angle_max'] = $config['angle_min']; 136 | } 137 | } 138 | 139 | return $config; 140 | } 141 | 142 | /** 143 | * Config restriction for the font size setup. This restrict important values 144 | * and restore to default value if detected a violation. 145 | * 146 | * @param array $config 147 | * 148 | * @return array 149 | */ 150 | protected function configFontSizeRestriction($config) 151 | { 152 | if(isset($config['font_size_min']) && $config['font_size_min'] < 10) { 153 | $config['font_size_min'] = 10; 154 | } 155 | 156 | if (isset($config['font_size_max']) && isset($config['font_size_min'])) { 157 | if ($config['font_size_max'] < $config['font_size_min']) { 158 | $config['font_size_max'] = $config['font_size_min']; 159 | } 160 | } 161 | 162 | return $config; 163 | } 164 | 165 | /** 166 | * The code generated by the generate unique code method base 167 | * on the given length. The code generated will be pass to the 168 | * code property that will be use to print an image of captcha code. 169 | * 170 | * @param int $length The given length for the captcha code. 171 | * 172 | * @return $this 173 | */ 174 | public function code($length = 5) 175 | { 176 | // When the length value is lower than 177 | // the minimum which is 5 then we must enforce to 178 | // use the default value of 5 to avoid short code. 179 | if ($length < 5) { 180 | $length = 5; 181 | } 182 | 183 | $this->code = $this->generateUniqueCode($length); 184 | 185 | return $this; 186 | } 187 | 188 | /** 189 | * The getter method for the code property class. 190 | * 191 | * @return string 192 | */ 193 | public function getCode() 194 | { 195 | return $this->code; 196 | } 197 | 198 | /** 199 | * Generate unique code base on the given length and 200 | * the allowed code characters. 201 | * 202 | * @param int $length The code max length to be generate. 203 | * 204 | * @return string 205 | */ 206 | protected function generateUniqueCode($length) 207 | { 208 | $characters = $this->allowedCodeCharacters(); 209 | $charactersLength = (\strlen($characters) - 1); 210 | 211 | $code = ''; 212 | 213 | for ($x = 0; $x < $length; $x++) { 214 | $number = \rand(0, $charactersLength); 215 | $jumbleNumber = \rand(0, $number); 216 | $code .= $characters[$jumbleNumber]; 217 | } 218 | 219 | return $code; 220 | } 221 | 222 | /** 223 | * The allowed code characters that can be generated 224 | * by the generated unique code method. 225 | * 226 | * @return string 227 | */ 228 | protected function allowedCodeCharacters() 229 | { 230 | return 'ABCDEFGHJKLMNPRSTUVWXYZabcdefghjkmnprstuvwxyz23456789'; 231 | } 232 | 233 | /** 234 | * The trigger for the generate image base on the current 235 | * property code values. This will generate an base64 data image 236 | * that can be use to output in the front facing. 237 | * 238 | * @return $this 239 | */ 240 | public function image() 241 | { 242 | $this->image = $this->generateBase64Image(); 243 | } 244 | 245 | /** 246 | * The getter method for the image property class. 247 | * 248 | * @return string 249 | */ 250 | public function getImage() 251 | { 252 | return $this->image; 253 | } 254 | 255 | /** 256 | * The generate process of the base64 image. This will be the captcha 257 | * image, the content of the image will be base on the code generated. 258 | * Mainly used the default config property of the class to provide the default 259 | * setup of the captcha image. 260 | * 261 | * @return string 262 | */ 263 | protected function generateBase64Image() 264 | { 265 | // Create the canvas of the image and providing 266 | // the size base on the background image picked randomly 267 | // in the list of the config. 268 | $background = $this->backgrounds(); 269 | $backgroundSize = $this->backgroundSize($background); 270 | $imageCanvas = $this->imageCanvas($background); 271 | 272 | // Prepare all the setup for the text content. The text 273 | // content will be base on the generated code string. 274 | // The position of the text content will be determine 275 | // base on the random min and max setup. 276 | $fontColor = $this->fontColor($imageCanvas); 277 | $textAngle = $this->textAngle(); 278 | $font = $this->fonts(); 279 | $fontSize = $this->fontSize(); 280 | $textBoxSize = $this->textBoxSize($textAngle, $font, $fontSize, $this->getCode()); 281 | $textPosition = $this->textPosition($textBoxSize, $backgroundSize); 282 | 283 | // Generating the actual text content and combining with the created 284 | // canvas base on the selected background image. This is the heavy part 285 | // of the code image processing. 286 | $imageCanvas = $this->drawShadow( 287 | $imageCanvas, $textAngle, $font, $fontSize, $textPosition, $this->getCode() 288 | ); 289 | 290 | $imageCanvas = $this->drawText( 291 | $imageCanvas, $textAngle, $font, $fontSize, $textPosition, $fontColor, $this->getCode() 292 | ); 293 | 294 | $imageCanvas = $this->drawTextCrossLine( 295 | $imageCanvas, $backgroundSize, $textAngle, $textPosition 296 | ); 297 | 298 | // Output the generated image using output buffer of PHP and 299 | // convert the image value to base64 that will be concat to image data url header. 300 | // This process is very nasty because of the linear execution in the memory, the 301 | // string value of the base64 will depends on the generated image. To make sure 302 | // a free space of memory in one single request we must unset the unused variable(s). 303 | $image = $this->imageExportContents($imageCanvas); 304 | 305 | unset($imageCanvas); 306 | 307 | $data = 'data:image/png;base64,'; 308 | $data .= \base64_encode($image); 309 | 310 | unset($image); 311 | 312 | return $data; 313 | } 314 | 315 | /** 316 | * Prepare the background that will be use in the image canvas. 317 | * This return the path of the background images. 318 | * 319 | * @return string 320 | */ 321 | protected function backgrounds() 322 | { 323 | $index = \mt_rand(0, \count($this->config['backgrounds']) -1); 324 | 325 | return $this->backgroundsDirectoryPath() . $this->config['backgrounds'][$index]; 326 | } 327 | 328 | /** 329 | * Base on the prepared background image, we must determine the 330 | * dimension of that image. 331 | * 332 | * @param string $background 333 | * 334 | * @return array 335 | */ 336 | protected function backgroundSize($background) 337 | { 338 | list($bgWidth, $bgHeight, $bgType, $bgAttr) = \getimagesize($background); 339 | 340 | return array( 341 | 'bg_width' => $bgWidth, 342 | 'bg_height' => $bgHeight, 343 | 'bg_type' => $bgType, 344 | 'bg_attr' => $bgAttr 345 | ); 346 | } 347 | 348 | /** 349 | * Create the image canvas base on the given background image. 350 | * The canvas enforce the use of png image type only. 351 | * 352 | * @param string $background 353 | * 354 | * @return mixed 355 | */ 356 | protected function imageCanvas($background) 357 | { 358 | return \imagecreatefrompng($background); 359 | } 360 | 361 | /** 362 | * Prepare the font color base on the config setup value. 363 | * The value generated will be pass on the image canvas. 364 | * 365 | * @param mixed $imageCanvas 366 | * 367 | * @return mixed 368 | */ 369 | protected function fontColor($imageCanvas) 370 | { 371 | $rgb = $this->convertHexToRGB($this->config['font_color']); 372 | 373 | return \imagecolorallocate($imageCanvas, $rgb['r'], $rgb['g'], $rgb['b']); 374 | } 375 | 376 | /** 377 | * Prepare the text angle that will be use of text content 378 | * in the image canvas. 379 | * 380 | * @return int 381 | */ 382 | protected function textAngle() 383 | { 384 | $textAngleRandom = \mt_rand( 385 | $this->config['angle_min'], $this->config['angle_max'] 386 | ); 387 | 388 | return $textAngleRandom * (\mt_rand(0, 1) == 1 ? -1 : 1); 389 | } 390 | 391 | /** 392 | * Prepare the font style base on the list of config setup. 393 | * This return the path of the font styles. 394 | * 395 | * @return string 396 | */ 397 | protected function fonts() 398 | { 399 | $index = \mt_rand(0, \count($this->config['fonts']) - 1); 400 | 401 | return $this->fontsDirectoryPath() . $this->config['fonts'][$index]; 402 | } 403 | 404 | 405 | /** 406 | * Prepare the font size that will be use in the created image canvas. 407 | * The value will be randomly picked base on the given range min and max. 408 | * 409 | * @return int 410 | */ 411 | protected function fontSize() 412 | { 413 | return \mt_rand($this->config['font_size_min'], $this->config['font_size_max']); 414 | } 415 | 416 | /** 417 | * Prepare the text box size that will be use of the text content. 418 | * 419 | * @param int $textAngle 420 | * @param string $font 421 | * @param int $fontSize 422 | * @param string $code 423 | * 424 | * @return mixed 425 | */ 426 | protected function textBoxSize($textAngle, $font, $fontSize, $code) 427 | { 428 | return \imagettfbbox($fontSize, $textAngle, $font, $code); 429 | } 430 | 431 | /** 432 | * The random computation of the text position of the provided code content. 433 | * 434 | * @param mixed $textBoxSize 435 | * @param array $backgroundSize 436 | * 437 | * @return array 438 | */ 439 | protected function textPosition($textBoxSize, $backgroundSize) 440 | { 441 | $boxWidth = \abs($textBoxSize[6] - $textBoxSize[2]); 442 | $boxHeight = \abs($textBoxSize[5] - $textBoxSize[1]); 443 | 444 | $textPositionXMin = 0; 445 | $textPositionXMax = $backgroundSize['bg_width'] - $boxWidth; 446 | 447 | if ($textPositionXMin > $textPositionXMax) { 448 | $textPositionXMax = $textPositionXMin; 449 | } 450 | 451 | $textPositionX = \mt_rand($textPositionXMin, $textPositionXMax); 452 | 453 | $textPositionYMin = $boxHeight; 454 | $textPositionYMax = ($backgroundSize['bg_height'] - ($boxHeight / 2) - 5); 455 | 456 | if ($textPositionYMin > $textPositionYMax) { 457 | $temp_textPositionY = $textPositionYMin; 458 | $textPositionYMin = $textPositionYMax; 459 | $textPositionYMax = $temp_textPositionY; 460 | } 461 | 462 | $textPositionY = \mt_rand($textPositionYMin, $textPositionYMax); 463 | 464 | if ($textPositionX < 30 && $textPositionY < 40) { 465 | return array( 466 | 'text_position_x' => 30, 467 | 'text_position_y' => 45 468 | ); 469 | } 470 | 471 | return array( 472 | 'text_position_x' => $textPositionX, 473 | 'text_position_y' => $textPositionY 474 | ); 475 | } 476 | 477 | /** 478 | * The draw process in the image canvas generated before. 479 | * This requires the final setup of image canvas, also the draw shadow 480 | * will be executed base on the config setup if allowed or not. 481 | * 482 | * @param mixed $imageCanvas 483 | * @param int $textAngle 484 | * @param string $font 485 | * @param int $fontSize 486 | * @param array $textPosition 487 | * @param string $code 488 | * 489 | * @return $imageCanvas 490 | */ 491 | protected function drawShadow($imageCanvas, $textAngle, $font, $fontSize, $textPosition, $code) 492 | { 493 | if (! $this->config['shadow']) { 494 | return $imageCanvas; 495 | } 496 | 497 | $shadowColor = $this->convertHexToRGB($this->config['shadow_color']); 498 | 499 | $shadowColor = \imagecolorallocate( 500 | $imageCanvas, 501 | $shadowColor['r'], $shadowColor['g'], $shadowColor['b'] 502 | ); 503 | 504 | \imagettftext( 505 | $imageCanvas, $fontSize, $textAngle, 506 | $textPosition['text_position_x'] + $this->config['shadow_offset_x'], 507 | $textPosition['text_position_y'] + $this->config['shadow_offset_y'], 508 | $shadowColor, $font, $code 509 | ); 510 | 511 | return $imageCanvas; 512 | } 513 | 514 | /** 515 | * The draw process of the text content base on the code provided. 516 | * This method is like the print process that will provide the content in the created 517 | * image canvas. 518 | * 519 | * @param mixed $imageCanvas 520 | * @param int $textAngle 521 | * @param string $font 522 | * @param int $fontSize 523 | * @param array $textPosition 524 | * @param mixed $fontColor 525 | * @param string $code 526 | * 527 | * @return $imageCanvas 528 | */ 529 | protected function drawText($imageCanvas, $textAngle, $font, $fontSize, $textPosition, $fontColor, $code) 530 | { 531 | \imagettftext( 532 | $imageCanvas, $fontSize, $textAngle, 533 | $textPosition['text_position_x'], 534 | $textPosition['text_position_y'], 535 | $fontColor, $font, $code 536 | ); 537 | 538 | return $imageCanvas; 539 | } 540 | 541 | /** 542 | * The draw process for the text cross line. This process will add more complexity 543 | * for the reading automation of the generated image captcha. 544 | * 545 | * The process of adding more challenge to any automation attempt in the captcha image. 546 | * 547 | * @param mixed $imageCanvas 548 | * @param array $backgroundSize 549 | * @param array $textPosition 550 | * 551 | * @return $imageCanvas 552 | */ 553 | protected function drawTextCrossLine($imageCanvas, $backgroundSize, $textAngle, $textPosition) 554 | { 555 | $text_position_y = $textPosition['text_position_y']; 556 | 557 | $lineAngle = $textAngle > 0 ? (($text_position_y) - $textAngle * 5) : (($text_position_y)); 558 | 559 | $black = \imagecolorallocate($imageCanvas, 20, 20, 20); 560 | \imagesetthickness($imageCanvas, 4); 561 | \imageline($imageCanvas, 10, $text_position_y - 14, $backgroundSize['bg_width'] - 10, $lineAngle, $black); 562 | 563 | return $imageCanvas; 564 | } 565 | 566 | /** 567 | * The background resources base directory path. 568 | * 569 | * @return string 570 | */ 571 | protected function backgroundsDirectoryPath() 572 | { 573 | return \dirname(__FILE__) . '/../resources/backgrounds/'; 574 | } 575 | 576 | /** 577 | * The font resources base directory path. 578 | * 579 | * @return string 580 | */ 581 | protected function fontsDirectoryPath() 582 | { 583 | return \dirname(__FILE__) . '/../resources/fonts/'; 584 | } 585 | 586 | /** 587 | * The wrapper for the hex to rgb class convert method. 588 | * This essential to wrapped in a method that add more 589 | * flexibility to change later on. 590 | * 591 | * @param string $hexString 592 | * 593 | * @return array 594 | */ 595 | protected function convertHexToRGB($hexString) 596 | { 597 | return HexToRGB::convert($hexString); 598 | } 599 | 600 | /** 601 | * The export functions for the image depending on the selected 602 | * image type. 603 | * 604 | * @param mixed $image The generated image content. 605 | * 606 | * @return string 607 | */ 608 | protected function imageExportContents($image) 609 | { 610 | \ob_start(); 611 | 612 | \imagepng($image); 613 | 614 | return \ob_get_clean(); 615 | } 616 | 617 | /** 618 | * The store session method that add the ability to transfer the generated 619 | * code in the other places, for example pages etc. 620 | * This later on will be the basis of the validation of user organic inputed 621 | * code base on the image perspective. 622 | * 623 | * @return void 624 | */ 625 | public function storeSession() 626 | { 627 | $this->startSession(); 628 | 629 | $_SESSION[$this->config['session_index_name']] = array( 630 | 'code' => $this->getCode() 631 | ); 632 | } 633 | 634 | /** 635 | * The get session method way to collect the stored session data. 636 | * This can be use for validation of organic code provided by the user. 637 | * 638 | * @return array 639 | */ 640 | public function getSession() 641 | { 642 | if (! isset($_COOKIE[$this->config['session_name']])) { 643 | return false; 644 | } 645 | 646 | $this->startSession(); 647 | 648 | $data = $this->collectSessionData(); 649 | 650 | \session_unset(); 651 | \session_destroy(); 652 | 653 | unset($_COOKIE[$this->config['session_index_name']]); 654 | 655 | return $data; 656 | } 657 | 658 | /** 659 | * The start session method, initialize the session for captcha instance. 660 | * The max session time is set to 15mins and the garbage collector can now truncate this 661 | * unused session. Some of the security setup are provided in the config property like 662 | * https and http only, the other depends on the PHP ini setup. 663 | * 664 | * @return void 665 | */ 666 | protected function startSession() 667 | { 668 | $cookie = \session_get_cookie_params(); 669 | 670 | \session_set_cookie_params( $cookie['lifetime'], $cookie['path'], $cookie['domain'], 671 | $this->config['session_https'], $this->config['session_http_only'] 672 | ); 673 | 674 | \session_name($this->config['session_name']); 675 | \session_start(array('gc_maxlifetime' => 860)); 676 | } 677 | 678 | /** 679 | * The collector for the session data. This check first if the session is the index of 680 | * captcha in the session available if not then return a null value. 681 | * 682 | * @return mixed 683 | */ 684 | protected function collectSessionData() 685 | { 686 | if (! isset($_SESSION[$this->config['session_index_name']])) { 687 | return null; 688 | } 689 | 690 | return $_SESSION[$this->config['session_index_name']]; 691 | } 692 | } 693 | -------------------------------------------------------------------------------- /src/Exception/CaptchaException.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace LordDashMe\SimpleCaptcha\Exception; 13 | 14 | use Exception; 15 | 16 | /** 17 | * Captcha Exception Class. 18 | * 19 | * @author Joshua Clifford Reyes 20 | */ 21 | class CaptchaException extends Exception {} 22 | -------------------------------------------------------------------------------- /src/Exception/Utility/HexToRGB.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace LordDashMe\SimpleCaptcha\Exception\Utility; 13 | 14 | use LordDashMe\SimpleCaptcha\Exception\CaptchaException; 15 | 16 | /** 17 | * Hex To RGB Exception Class. 18 | * 19 | * @author Joshua Clifford Reyes 20 | */ 21 | class HexToRGB extends CaptchaException 22 | { 23 | const IS_INVALID_STRING_TYPE = 1; 24 | const IS_INVALID_STRING_LENGTH = 2; 25 | 26 | public static function isInvalidStringType( 27 | $message = 'The string type is invalid.', 28 | $code = self::IS_INVALID_STRING_TYPE, 29 | $previous = null 30 | ) { 31 | return new static($message, $code, $previous); 32 | } 33 | 34 | public static function isInvalidStringLength( 35 | $message = 'The string length is invalid.', 36 | $code = self::IS_INVALID_STRING_LENGTH, 37 | $previous = null 38 | ) { 39 | return new static($message, $code, $previous); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Facade/Captcha.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace LordDashMe\SimpleCaptcha\Facade; 13 | 14 | use LordDashMe\StaticClassInterface\Facade; 15 | 16 | /** 17 | * Captcha Facade Class. 18 | * 19 | * @author Joshua Clifford Reyes 20 | */ 21 | class Captcha extends Facade 22 | { 23 | /** 24 | * {@inheritdoc} 25 | */ 26 | public static function getStaticClassAccessor() 27 | { 28 | return 'LordDashMe\SimpleCaptcha\Captcha'; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/Utility/HexToRGB.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace LordDashMe\SimpleCaptcha\Utility; 13 | 14 | use LordDashMe\SimpleCaptcha\Exception\Utility\HexToRGB as HexToRGBException; 15 | 16 | /** 17 | * HexToRGB Utility Class. 18 | * 19 | * @author Joshua Clifford Reyes 20 | */ 21 | class HexToRGB 22 | { 23 | /** 24 | * The convert process of hex to rgb type. 25 | * This only accept hex string data type. 26 | * 27 | * @param string $hexString The hex string that will be converted. 28 | * @param bool $returnAsString (Optional) The return type if string. 29 | * @param string $separator (Optional) The separator if the return type is string. 30 | * 31 | * @throws LordDashMe\SimpleCaptcha\Exception\Utility\HexToRGB::isInvalidStringType 32 | * @throws LordDashMe\SimpleCaptcha\Exception\Utility\HexToRGB::isInvalidStringLength 33 | * 34 | * @return array|string 35 | */ 36 | public static function convert($hexString, $returnAsString = false, $separator = ',') 37 | { 38 | if (! \is_string($hexString)) { 39 | throw HexToRGBException::isInvalidStringType(); 40 | } 41 | 42 | $hexString = \preg_replace("/[^0-9A-Fa-f]/", '', $hexString); 43 | 44 | $rgb = array(); 45 | 46 | if (\strlen($hexString) === 6) { 47 | $color = \hexdec($hexString); 48 | $rgb['r'] = 0xFF & ($color >> 0x10); 49 | $rgb['g'] = 0xFF & ($color >> 0x8); 50 | $rgb['b'] = 0xFF & $color; 51 | } else if (\strlen($hexString) === 3) { 52 | $rgb['r'] = \hexdec(\str_repeat(\substr($hexString, 0, 1), 2)); 53 | $rgb['g'] = \hexdec(\str_repeat(\substr($hexString, 1, 1), 2)); 54 | $rgb['b'] = \hexdec(\str_repeat(\substr($hexString, 2, 1), 2)); 55 | } else { 56 | throw HexToRGBException::isInvalidStringLength(); 57 | } 58 | 59 | return ($returnAsString) ? \implode($separator, $rgb) : $rgb; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /tests/Unit/CaptchaTest.php: -------------------------------------------------------------------------------- 1 | assertInstanceOf(Captcha::class, new Captcha()); 17 | } 18 | 19 | /** 20 | * @test 21 | */ 22 | public function it_should_generate_captcha_code_base_on_the_given_length() 23 | { 24 | $captcha = new Captcha(); 25 | $captcha->code(5); 26 | 27 | $this->assertEquals(5, strlen($captcha->getCode())); 28 | } 29 | 30 | /** 31 | * @test 32 | */ 33 | public function it_should_generate_captcha_image_base_on_the_generated_code() 34 | { 35 | $captcha = new Captcha(); 36 | $captcha->code(5); 37 | $captcha->image(); 38 | 39 | $this->assertNotEmpty($captcha->getImage()); 40 | } 41 | 42 | /** 43 | * @test 44 | */ 45 | public function it_should_generate_captcha_image_without_shadow_base_on_the_generated_code() 46 | { 47 | $captcha = new Captcha(array('shadow' => false)); 48 | $captcha->code(5); 49 | $captcha->image(); 50 | 51 | $this->assertNotEmpty($captcha->getImage()); 52 | } 53 | 54 | /** 55 | * @test 56 | */ 57 | public function it_should_generate_captcha_image_base_on_the_generated_code_with_config_restriction() 58 | { 59 | $captcha = new Captcha(array( 60 | 'angle_min' => -1, 61 | 'angle_max' => 11, 62 | 'font_size_min' => 9 63 | )); 64 | $captcha->code(4); 65 | $captcha->image(); 66 | 67 | $this->assertNotEmpty($captcha->getImage()); 68 | 69 | $captcha->init(array( 70 | 'angle_min' => 11, 71 | 'angle_max' => -1, 72 | )); 73 | $captcha->code(5); 74 | $captcha->image(); 75 | 76 | $this->assertNotEmpty($captcha->getImage()); 77 | 78 | $captcha->init(array( 79 | 'font_size_min' => 11, 80 | 'font_size_max' => -1, 81 | )); 82 | $captcha->code(5); 83 | $captcha->image(); 84 | 85 | $this->assertNotEmpty($captcha->getImage()); 86 | } 87 | 88 | /** 89 | * @test 90 | */ 91 | public function it_should_generate_captcha_image_and_with_mocked_textbox_size_when_text_position_xmin_greater_than_xmax() 92 | { 93 | $captcha = Mockery::mock('LordDashMe\SimpleCaptcha\Captcha[textBoxSize]') 94 | ->shouldAllowMockingProtectedMethods(); 95 | $captcha->shouldReceive('textBoxSize') 96 | ->andReturn(array( 97 | 0 => -5, 98 | 1 => 13, 99 | 2 => 228, 100 | 3 => 13, 101 | 4 => 228, 102 | 5 => -34, 103 | 6 => -5, 104 | 7 => -34 105 | )); 106 | $captcha->code(5); 107 | $captcha->image(); 108 | 109 | $this->assertNotEmpty($captcha->getImage()); 110 | } 111 | 112 | /** 113 | * @test 114 | */ 115 | public function it_should_generate_captcha_image_and_with_mocked_textbox_size_when_text_position_ymin_greater_than_ymax() 116 | { 117 | $captcha = Mockery::mock('LordDashMe\SimpleCaptcha\Captcha[textBoxSize]') 118 | ->shouldAllowMockingProtectedMethods(); 119 | $captcha->shouldReceive('textBoxSize') 120 | ->andReturn(array( 121 | 0 => -6, 122 | 1 => 13, 123 | 2 => 110, 124 | 3 => -7, 125 | 4 => 103, 126 | 5 => -47, 127 | 6 => -13, 128 | 7 => -26 129 | )); 130 | $captcha->code(5); 131 | $captcha->image(); 132 | 133 | $this->assertNotEmpty($captcha->getImage()); 134 | } 135 | 136 | /** 137 | * @test 138 | */ 139 | public function it_should_generate_captcha_image_and_with_mocked_textbox_size_when_text_position_x_and_y_are_minimum_value() 140 | { 141 | $captcha = Mockery::mock('LordDashMe\SimpleCaptcha\Captcha[textBoxSize]') 142 | ->shouldAllowMockingProtectedMethods(); 143 | $captcha->shouldReceive('textBoxSize') 144 | ->andReturn(array( 145 | 0 => -1, 146 | 1 => 1, 147 | 2 => 120, 148 | 3 => 1, 149 | 4 => 120, 150 | 5 => -27, 151 | 6 => -1, 152 | 7 => -27 153 | )); 154 | $captcha->code(5); 155 | $captcha->image(); 156 | 157 | $this->assertNotEmpty($captcha->getImage()); 158 | } 159 | 160 | /** 161 | * @test 162 | */ 163 | public function it_should_generate_captcha_image_and_with_mocked_textbox_size_when_text_position_x_and_y_are_not_minimum_value() 164 | { 165 | $captcha = Mockery::mock('LordDashMe\SimpleCaptcha\Captcha[textBoxSize]') 166 | ->shouldAllowMockingProtectedMethods(); 167 | $captcha->shouldReceive('textBoxSize') 168 | ->andReturn(array( 169 | 0 => -1, 170 | 1 => 9, 171 | 2 => 100, 172 | 3 => 5, 173 | 4 => 99, 174 | 5 => -30, 175 | 6 => -2, 176 | 7 => -27 177 | )); 178 | $captcha->code(5); 179 | $captcha->image(); 180 | 181 | $this->assertNotEmpty($captcha->getImage()); 182 | } 183 | 184 | /** 185 | * @test 186 | */ 187 | public function it_should_generate_captcha_image_and_with_mocked_text_angle_when_text_angle_is_negative_value() 188 | { 189 | $captcha = Mockery::mock('LordDashMe\SimpleCaptcha\Captcha[textAngle]') 190 | ->shouldAllowMockingProtectedMethods(); 191 | $captcha->shouldReceive('textAngle') 192 | ->andReturn(-5); 193 | $captcha->code(5); 194 | $captcha->image(); 195 | 196 | $this->assertNotEmpty($captcha->getImage()); 197 | } 198 | 199 | /** 200 | * @test 201 | */ 202 | public function it_should_generate_captcha_image_and_with_mocked_text_angle_when_text_angle_is_positive_value() 203 | { 204 | $captcha = Mockery::mock('LordDashMe\SimpleCaptcha\Captcha[textAngle]') 205 | ->shouldAllowMockingProtectedMethods(); 206 | $captcha->shouldReceive('textAngle') 207 | ->andReturn(5); 208 | $captcha->code(5); 209 | $captcha->image(); 210 | 211 | $this->assertNotEmpty($captcha->getImage()); 212 | } 213 | 214 | /** 215 | * @test 216 | */ 217 | public function it_should_store_the_code_in_flash_session() 218 | { 219 | $captcha = new Captcha(); 220 | $captcha->code(5); 221 | $captcha->image(); 222 | $captcha->storeSession(); 223 | 224 | $this->assertTrue(isset($_SESSION['LDM_SIMPLE_CAPTCHA'])); 225 | 226 | session_write_close(); 227 | } 228 | 229 | /** 230 | * @test 231 | * @depends it_should_store_the_code_in_flash_session 232 | */ 233 | public function it_should_return_false_in_get_session_when_session_cookie_is_not_set() 234 | { 235 | $captcha = new Captcha(); 236 | 237 | $captchaStoredData = $captcha->getSession(); 238 | 239 | $this->assertTrue(! $captchaStoredData); 240 | } 241 | 242 | /** 243 | * @test 244 | * @depends it_should_store_the_code_in_flash_session 245 | */ 246 | public function it_should_get_the_code_in_flash_session() 247 | { 248 | $_COOKIE['ldm-simple-captcha'] = 'mocked session cookie.'; 249 | 250 | $captcha = new Captcha(); 251 | 252 | $captchaStoredData = $captcha->getSession(); 253 | 254 | $this->assertTrue(isset($captchaStoredData['code'])); 255 | } 256 | 257 | /** 258 | * @test 259 | * @depends it_should_get_the_code_in_flash_session 260 | */ 261 | public function it_should_get_the_null_value_in_flash_session() 262 | { 263 | $captcha = new Captcha(); 264 | 265 | $captchaStoredData = $captcha->getSession(); 266 | 267 | $this->assertTrue(! isset($captchaStoredData['code'])); 268 | } 269 | } 270 | -------------------------------------------------------------------------------- /tests/Unit/Facade/CaptchaTest.php: -------------------------------------------------------------------------------- 1 | assertInstanceOf(HexToRGB::class, new HexToRGB()); 16 | } 17 | 18 | /** 19 | * @test 20 | */ 21 | public function it_should_throw_invalid_string_type_when_given_hex_is_not_string() 22 | { 23 | $this->expectException(\LordDashMe\SimpleCaptcha\Exception\Utility\HexToRGB::class); 24 | $this->expectExceptionCode(1); 25 | $this->expectExceptionMessage('The string type is invalid.'); 26 | 27 | HexToRGB::convert(null); 28 | } 29 | 30 | /** 31 | * @test 32 | */ 33 | public function it_should_throw_invalid_string_length_when_given_hex_is_not_valid_length() 34 | { 35 | $this->expectException(\LordDashMe\SimpleCaptcha\Exception\Utility\HexToRGB::class); 36 | $this->expectExceptionCode(2); 37 | $this->expectExceptionMessage('The string length is invalid.'); 38 | 39 | HexToRGB::convert('null'); 40 | } 41 | 42 | /** 43 | * @test 44 | */ 45 | public function it_should_convert_given_hex_string_to_rgb_in_array_return_type() 46 | { 47 | $rgb = HexToRGB::convert('#555'); 48 | 49 | $this->assertInternalType('array', $rgb); 50 | } 51 | 52 | /** 53 | * @test 54 | */ 55 | public function it_should_convert_given_hex_string_to_rgb_in_string_return_type() 56 | { 57 | $rgb = HexToRGB::convert('#555', true); 58 | 59 | $this->assertInternalType('string', $rgb); 60 | } 61 | 62 | /** 63 | * @test 64 | */ 65 | public function it_should_convert_given_hex_string_with_6_length_to_rgb_in_array_return_type() 66 | { 67 | $rgb = HexToRGB::convert('#555555'); 68 | 69 | $this->assertInternalType('array', $rgb); 70 | } 71 | } -------------------------------------------------------------------------------- /tests/bootstrap.php: -------------------------------------------------------------------------------- 1 |