├── .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 | [](https://packagist.org/packages/lorddashme/php-simple-captcha) [](https://php.net/) [](https://coveralls.io/github/LordDashMe/php-simple-captcha?branch=master)
6 |
7 | ## Sample
8 |
9 |    
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 |
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 |
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 |