vendor and env first commit

This commit is contained in:
2025-03-28 08:52:46 +01:00
parent f8388bc81b
commit 8f26283832
10976 changed files with 1349952 additions and 2 deletions
+4
View File
@@ -0,0 +1,4 @@
/vendor
composer.phar
composer.lock
.DS_Store
+18
View File
@@ -0,0 +1,18 @@
language: php
dist: trusty
php:
- 5.5
- 5.6
- 7.0
- 7.1
- 7.2
before_script:
- travis_retry composer self-update
- travis_retry composer install --prefer-source --no-interaction --dev
script:
- composer install
- vendor/bin/phpunit
+22
View File
@@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2014 Nguyễn Văn Ánh
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+197
View File
@@ -0,0 +1,197 @@
No CAPTCHA reCAPTCHA
==========
[![Build Status](https://travis-ci.org/anhskohbo/no-captcha.svg?branch=master&style=flat-square)](https://travis-ci.org/anhskohbo/no-captcha)
[![Latest Stable Version](https://poser.pugx.org/anhskohbo/no-captcha/v/stable)](https://packagist.org/packages/anhskohbo/no-captcha)
[![Total Downloads](https://poser.pugx.org/anhskohbo/no-captcha/downloads)](https://packagist.org/packages/anhskohbo/no-captcha)
[![Latest Unstable Version](https://poser.pugx.org/anhskohbo/no-captcha/v/unstable)](https://packagist.org/packages/anhskohbo/no-captcha)
[![License](https://poser.pugx.org/anhskohbo/no-captcha/license)](https://packagist.org/packages/anhskohbo/no-captcha)
![recaptcha_anchor 2x](https://cloud.githubusercontent.com/assets/1529454/5291635/1c426412-7b88-11e4-8d16-46161a081ece.gif)
> For Laravel 4 use [v1](https://github.com/anhskohbo/no-captcha/tree/v1) branch.
## Installation
```
composer require anhskohbo/no-captcha
```
## Laravel 5 and above
### Setup
**_NOTE_** This package supports the auto-discovery feature of Laravel 5.5 and above, So skip these `Setup` instructions if you're using Laravel 5.5 and above.
In `app/config/app.php` add the following :
1- The ServiceProvider to the providers array :
```php
Anhskohbo\NoCaptcha\NoCaptchaServiceProvider::class,
```
2- The class alias to the aliases array :
```php
'NoCaptcha' => Anhskohbo\NoCaptcha\Facades\NoCaptcha::class,
```
3- Publish the config file
```ssh
php artisan vendor:publish --provider="Anhskohbo\NoCaptcha\NoCaptchaServiceProvider"
```
### Configuration
Add `NOCAPTCHA_SECRET` and `NOCAPTCHA_SITEKEY` in **.env** file :
```
NOCAPTCHA_SECRET=secret-key
NOCAPTCHA_SITEKEY=site-key
```
(You can obtain them from [here](https://www.google.com/recaptcha/admin))
### Usage
#### Init js source
With default options :
```php
{!! NoCaptcha::renderJs() !!}
```
With [language support](https://developers.google.com/recaptcha/docs/language) or [onloadCallback](https://developers.google.com/recaptcha/docs/display#explicit_render) option :
```php
{!! NoCaptcha::renderJs('fr', true, 'recaptchaCallback') !!}
```
#### Display reCAPTCHA
Default widget :
```php
{!! NoCaptcha::display() !!}
```
With [custom attributes](https://developers.google.com/recaptcha/docs/display#render_param) (theme, size, callback ...) :
```php
{!! NoCaptcha::display(['data-theme' => 'dark']) !!}
```
Invisible reCAPTCHA using a [submit button](https://developers.google.com/recaptcha/docs/invisible):
```php
{!! NoCaptcha::displaySubmit('my-form-id', 'submit now!', ['data-theme' => 'dark']) !!}
```
Notice that the id of the form is required in this method to let the autogenerated
callback submit the form on a successful captcha verification.
#### Validation
Add `'g-recaptcha-response' => 'required|captcha'` to rules array :
```php
$validate = Validator::make(Input::all(), [
'g-recaptcha-response' => 'required|captcha'
]);
```
##### Custom Validation Message
Add the following values to the `custom` array in the `validation` language file :
```php
'custom' => [
'g-recaptcha-response' => [
'required' => 'Please verify that you are not a robot.',
'captcha' => 'Captcha error! try again later or contact site admin.',
],
],
```
Then check for captcha errors in the `Form` :
```php
@if ($errors->has('g-recaptcha-response'))
<span class="help-block">
<strong>{{ $errors->first('g-recaptcha-response') }}</strong>
</span>
@endif
```
### Testing
When using the [Laravel Testing functionality](http://laravel.com/docs/5.5/testing), you will need to mock out the response for the captcha form element.
So for any form tests involving the captcha, you can do this by mocking the facade behavior:
```php
// prevent validation error on captcha
NoCaptcha::shouldReceive('verifyResponse')
->once()
->andReturn(true);
// provide hidden input for your 'required' validation
NoCaptcha::shouldReceive('display')
->zeroOrMoreTimes()
->andReturn('<input type="hidden" name="g-recaptcha-response" value="1" />');
```
You can then test the remainder of your form as normal.
When using HTTP tests you can add the `g-recaptcha-response` to the request body for the 'required' validation:
```php
// prevent validation error on captcha
NoCaptcha::shouldReceive('verifyResponse')
->once()
->andReturn(true);
// POST request, with request body including g-recaptcha-response
$response = $this->json('POST', '/register', [
'g-recaptcha-response' => '1',
'name' => 'John',
'email' => 'john@example.com',
'password' => '123456',
'password_confirmation' => '123456',
]);
```
## Without Laravel
Checkout example below:
```php
<?php
require_once "vendor/autoload.php";
$secret = 'CAPTCHA-SECRET';
$sitekey = 'CAPTCHA-SITEKEY';
$captcha = new \Anhskohbo\NoCaptcha\NoCaptcha($secret, $sitekey);
if (! empty($_POST)) {
var_dump($captcha->verifyResponse($_POST['g-recaptcha-response']));
exit();
}
?>
<form action="?" method="POST">
<?php echo $captcha->display(); ?>
<button type="submit">Submit</button>
</form>
<?php echo $captcha->renderJs(); ?>
```
## Contribute
https://github.com/anhskohbo/no-captcha/pulls
+43
View File
@@ -0,0 +1,43 @@
{
"name": "anhskohbo/no-captcha",
"description": "No CAPTCHA reCAPTCHA For Laravel.",
"keywords": [
"recaptcha",
"no-captcha",
"captcha",
"laravel",
"laravel4",
"laravel5",
"laravel6"
],
"license": "MIT",
"authors": [
{
"name": "anhskohbo",
"email": "anhskohbo@gmail.com"
}
],
"require": {
"php": ">=5.5.5",
"illuminate/support": "^5.0|^6.0|^7.0|^8.0|^9.0|^10.0|^11.0",
"guzzlehttp/guzzle": "^6.2|^7.0"
},
"require-dev": {
"phpunit/phpunit": "~4.8|^9.5.10|^10.5"
},
"autoload": {
"psr-4": {
"Anhskohbo\\NoCaptcha\\": "src/"
}
},
"extra": {
"laravel": {
"providers": [
"Anhskohbo\\NoCaptcha\\NoCaptchaServiceProvider"
],
"aliases": {
"NoCaptcha": "Anhskohbo\\NoCaptcha\\Facades\\NoCaptcha"
}
}
}
}
+18
View File
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false"
backupStaticAttributes="false"
bootstrap="vendor/autoload.php"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false"
syntaxCheck="false"
>
<testsuites>
<testsuite name="Package Test Suite">
<directory suffix=".php">./tests/</directory>
</testsuite>
</testsuites>
</phpunit>
+18
View File
@@ -0,0 +1,18 @@
<?php
namespace Anhskohbo\NoCaptcha\Facades;
use Illuminate\Support\Facades\Facade;
class NoCaptcha extends Facade
{
/**
* Get the registered name of the component.
*
* @return string
*/
protected static function getFacadeAccessor()
{
return 'captcha';
}
}
+246
View File
@@ -0,0 +1,246 @@
<?php
namespace Anhskohbo\NoCaptcha;
use Symfony\Component\HttpFoundation\Request;
use GuzzleHttp\Client;
class NoCaptcha
{
const CLIENT_API = 'https://www.google.com/recaptcha/api.js';
const VERIFY_URL = 'https://www.google.com/recaptcha/api/siteverify';
/**
* The recaptcha secret key.
*
* @var string
*/
protected $secret;
/**
* The recaptcha sitekey key.
*
* @var string
*/
protected $sitekey;
/**
* @var \GuzzleHttp\Client
*/
protected $http;
/**
* The cached verified responses.
*
* @var array
*/
protected $verifiedResponses = [];
/**
* NoCaptcha.
*
* @param string $secret
* @param string $sitekey
* @param array $options
*/
public function __construct($secret, $sitekey, $options = [])
{
$this->secret = $secret;
$this->sitekey = $sitekey;
$this->http = new Client($options);
}
/**
* Render HTML captcha.
*
* @param array $attributes
*
* @return string
*/
public function display($attributes = [])
{
$attributes = $this->prepareAttributes($attributes);
return '<div' . $this->buildAttributes($attributes) . '></div>';
}
/**
* @see display()
*/
public function displayWidget($attributes = [])
{
return $this->display($attributes);
}
/**
* Display a Invisible reCAPTCHA by embedding a callback into a form submit button.
*
* @param string $formIdentifier the html ID of the form that should be submitted.
* @param string $text the text inside the form button
* @param array $attributes array of additional html elements
*
* @return string
*/
public function displaySubmit($formIdentifier, $text = 'submit', $attributes = [])
{
$javascript = '';
if (!isset($attributes['data-callback'])) {
$functionName = 'onSubmit' . str_replace(['-', '=', '\'', '"', '<', '>', '`'], '', $formIdentifier);
$attributes['data-callback'] = $functionName;
$javascript = sprintf(
'<script>function %s(){document.getElementById("%s").submit();}</script>',
$functionName,
$formIdentifier
);
}
$attributes = $this->prepareAttributes($attributes);
$button = sprintf('<button%s><span>%s</span></button>', $this->buildAttributes($attributes), $text);
return $button . $javascript;
}
/**
* Render js source
*
* @param null $lang
* @param bool $callback
* @param string $onLoadClass
* @return string
*/
public function renderJs($lang = null, $callback = false, $onLoadClass = 'onloadCallBack')
{
return '<script src="'.$this->getJsLink($lang, $callback, $onLoadClass).'" async defer></script>'."\n";
}
/**
* Verify no-captcha response.
*
* @param string $response
* @param string $clientIp
*
* @return bool
*/
public function verifyResponse($response, $clientIp = null)
{
if (empty($response)) {
return false;
}
// Return true if response already verfied before.
if (in_array($response, $this->verifiedResponses)) {
return true;
}
$verifyResponse = $this->sendRequestVerify([
'secret' => $this->secret,
'response' => $response,
'remoteip' => $clientIp,
]);
if (isset($verifyResponse['success']) && $verifyResponse['success'] === true) {
// A response can only be verified once from google, so we need to
// cache it to make it work in case we want to verify it multiple times.
$this->verifiedResponses[] = $response;
return true;
} else {
return false;
}
}
/**
* Verify no-captcha response by Symfony Request.
*
* @param Request $request
*
* @return bool
*/
public function verifyRequest(Request $request)
{
return $this->verifyResponse(
$request->get('g-recaptcha-response'),
$request->getClientIp()
);
}
/**
* Get recaptcha js link.
*
* @param string $lang
* @param boolean $callback
* @param string $onLoadClass
* @return string
*/
public function getJsLink($lang = null, $callback = false, $onLoadClass = 'onloadCallBack')
{
$client_api = static::CLIENT_API;
$params = [];
$callback ? $this->setCallBackParams($params, $onLoadClass) : false;
$lang ? $params['hl'] = $lang : null;
return $client_api . '?'. http_build_query($params);
}
/**
* @param $params
* @param $onLoadClass
*/
protected function setCallBackParams(&$params, $onLoadClass)
{
$params['render'] = 'explicit';
$params['onload'] = $onLoadClass;
}
/**
* Send verify request.
*
* @param array $query
*
* @return array
*/
protected function sendRequestVerify(array $query = [])
{
$response = $this->http->request('POST', static::VERIFY_URL, [
'form_params' => $query,
]);
return json_decode($response->getBody(), true);
}
/**
* Prepare HTML attributes and assure that the correct classes and attributes for captcha are inserted.
*
* @param array $attributes
*
* @return array
*/
protected function prepareAttributes(array $attributes)
{
$attributes['data-sitekey'] = $this->sitekey;
if (!isset($attributes['class'])) {
$attributes['class'] = '';
}
$attributes['class'] = trim('g-recaptcha ' . $attributes['class']);
return $attributes;
}
/**
* Build HTML attributes.
*
* @param array $attributes
*
* @return string
*/
protected function buildAttributes(array $attributes)
{
$html = [];
foreach ($attributes as $key => $value) {
$html[] = $key.'="'.$value.'"';
}
return count($html) ? ' '.implode(' ', $html) : '';
}
}
@@ -0,0 +1,73 @@
<?php
namespace Anhskohbo\NoCaptcha;
use Illuminate\Support\ServiceProvider;
class NoCaptchaServiceProvider extends ServiceProvider
{
/**
* Indicates if loading of the provider is deferred.
*
* @var bool
*/
protected $defer = false;
/**
* Bootstrap the application events.
*/
public function boot()
{
$app = $this->app;
$this->bootConfig();
$app['validator']->extend('captcha', function ($attribute, $value) use ($app) {
return $app['captcha']->verifyResponse($value, $app['request']->getClientIp());
});
if ($app->bound('form')) {
$app['form']->macro('captcha', function ($attributes = []) use ($app) {
return $app['captcha']->display($attributes, $app->getLocale());
});
}
}
/**
* Booting configure.
*/
protected function bootConfig()
{
$path = __DIR__.'/config/captcha.php';
$this->mergeConfigFrom($path, 'captcha');
if (function_exists('config_path')) {
$this->publishes([$path => config_path('captcha.php')]);
}
}
/**
* Register the service provider.
*/
public function register()
{
$this->app->singleton('captcha', function ($app) {
return new NoCaptcha(
$app['config']['captcha.secret'],
$app['config']['captcha.sitekey'],
$app['config']['captcha.options']
);
});
}
/**
* Get the services provided by the provider.
*
* @return array
*/
public function provides()
{
return ['captcha'];
}
}
View File
+9
View File
@@ -0,0 +1,9 @@
<?php
return [
'secret' => env('NOCAPTCHA_SECRET'),
'sitekey' => env('NOCAPTCHA_SITEKEY'),
'options' => [
'timeout' => 30,
],
];
View File
+69
View File
@@ -0,0 +1,69 @@
<?php
use Anhskohbo\NoCaptcha\NoCaptcha;
class NoCaptchaTest extends PHPUnit_Framework_TestCase
{
/**
* @var NoCaptcha
*/
private $captcha;
public function setUp()
{
parent::setUp();
$this->captcha = new NoCaptcha('{secret-key}', '{site-key}');
}
public function testRequestShouldWorks()
{
$response = $this->captcha->verifyResponse('should_false');
}
public function testJsLink()
{
$this->assertTrue($this->captcha instanceof NoCaptcha);
$simple = '<script src="https://www.google.com/recaptcha/api.js?" async defer></script>'."\n";
$withLang = '<script src="https://www.google.com/recaptcha/api.js?hl=vi" async defer></script>'."\n";
$withCallback = '<script src="https://www.google.com/recaptcha/api.js?render=explicit&onload=myOnloadCallback" async defer></script>'."\n";
$this->assertEquals($simple, $this->captcha->renderJs());
$this->assertEquals($withLang, $this->captcha->renderJs('vi'));
$this->assertEquals($withCallback, $this->captcha->renderJs(null, true, 'myOnloadCallback'));
}
public function testDisplay()
{
$this->assertTrue($this->captcha instanceof NoCaptcha);
$simple = '<div data-sitekey="{site-key}" class="g-recaptcha"></div>';
$withAttrs = '<div data-theme="light" data-sitekey="{site-key}" class="g-recaptcha"></div>';
$this->assertEquals($simple, $this->captcha->display());
$this->assertEquals($withAttrs, $this->captcha->display(['data-theme' => 'light']));
}
public function testdisplaySubmit()
{
$this->assertTrue($this->captcha instanceof NoCaptcha);
$javascript = '<script>function onSubmittest(){document.getElementById("test").submit();}</script>';
$simple = '<button data-callback="onSubmittest" data-sitekey="{site-key}" class="g-recaptcha"><span>submit</span></button>';
$withAttrs = '<button data-theme="light" class="g-recaptcha 123" data-callback="onSubmittest" data-sitekey="{site-key}"><span>submit123</span></button>';
$this->assertEquals($simple . $javascript, $this->captcha->displaySubmit('test'));
$withAttrsResult = $this->captcha->displaySubmit('test','submit123',['data-theme' => 'light', 'class' => '123']);
$this->assertEquals($withAttrs . $javascript, $withAttrsResult);
}
public function testdisplaySubmitWithCustomCallback()
{
$this->assertTrue($this->captcha instanceof NoCaptcha);
$withAttrs = '<button data-theme="light" class="g-recaptcha 123" data-callback="onSubmitCustomCallback" data-sitekey="{site-key}"><span>submit123</span></button>';
$withAttrsResult = $this->captcha->displaySubmit('test-custom','submit123',['data-theme' => 'light', 'class' => '123', 'data-callback' => 'onSubmitCustomCallback']);
$this->assertEquals($withAttrs, $withAttrsResult);
}
}