nsu-soft / yii-cap-captcha-widget
Widget for Yii views to check captcha by Cap Captcha service
Package info
github.com/nsu-soft/yii-cap-captcha-widget
pkg:composer/nsu-soft/yii-cap-captcha-widget
Requires
- php: >=8.3
- npm-asset/cap.js--widget: ^0.1.42
- yiisoft/yii2: ~2.0.50
Requires (Dev)
- codeception/codeception: ^5.3
- codeception/module-asserts: ^3.3
- codeception/module-yii2: ^2.0
- guzzlehttp/guzzle: ^7.10
- nsu-soft/yii-cap-captcha: ^3.0
Suggests
- nsu-soft/yii-cap-captcha: Allows you to validate token for client request via the Cap Captcha API
README
📑 Table of Contents
- Overview
- Features
- Requirements
- Installation
- Configuration
- Usage
- Quick Start with Docker
- Widget Properties Reference
- Testing
- Project Structure
- Integration with yii-cap-captcha
- Security
- Contributing
- License
📋 Overview
yii-cap-captcha-widget is a Yii2 view widget that provides seamless integration of the Cap Captcha client-side widget into your Yii2 application forms. It renders the CAPTCHA challenge interface and handles token generation using the official @cap.js/widget NPM package.
This widget works in conjunction with the yii-cap-captcha server-side component to provide complete bot protection: the widget handles client-side challenge display and token generation, while the companion package validates tokens on the server. Or you can use your own solution to validate tokens on the server. It's up to you.
✨ Features
- 🧩 Native Yii2 Widget: Drop-in component following Yii2 widget conventions (
CapWidget::widget()). - 🔐 Cap Captcha Integration: Renders the official Cap widget with full configuration support.
- ⚙️ Flexible Configuration: Customize endpoint, callback handlers, and widget options via PHP properties.
- 🎨 Asset Management: Automatic registration of required JS assets via Yii2 AssetBundle.
- 🔄 Event-Driven: Support for
onSolveJavaScript callback to handle token submission. - 🐳 Docker-Ready: Pre-configured environment for local development and testing.
- 🧪 Tested: Includes Codeception test suite for functional and unit testing.
🔧 Requirements
| Component | Version | Description |
|---|---|---|
| PHP | >= 8.3 |
Required PHP version |
| Yii Framework | ~2.0.50 |
Yii2 web application framework |
Optional (Recommended)
| Component | Version | Description |
|---|---|---|
| nsu-soft/yii-cap-captcha | ^3.0 |
Server-side component for token validation |
📦 Installation
If you don't have Composer, you may install it by following instruction.
Install the package via Composer:
composer require nsu-soft/yii-cap-captcha-widget
Install the server-side validation package, if you don't have your own solution. See the following instruction.
⚙️ Configuration
If you use nsu-soft/yii-cap-captcha package, configure it by following instruction
💻 Usage
Basic Widget Rendering
Render the widget directly in your Yii2 view file:
<?php $cap = Yii::$app->captcha; echo NsuSoft\Captcha\CapWidget::widget([ 'endpoint' => $cap->getEndpoint(), ]);
If you don't use nsu-soft/yii-cap-captcha package, you can specify properties manually:
<?php echo NsuSoft\Captcha\CapWidget::widget([ // Cap Captcha server URI. Replace {siteKey} with a real site key. 'endpoint' => 'http://localhost:3000/{siteKey}', ]);
With Custom Callback
<?php echo NsuSoft\Captcha\CapWidget::widget([ // Cap Captcha server URL. Replace {siteKey} with a real site key. 'endpoint' => 'http://localhost:3000/{siteKey}', // Optional: custom HTML id 'id' => 'my-captcha-widget', // Optional: use this event, if CapWidget is places out of the <form> tag. // If CapWidget placed inside the <form> tag, token will be added in request // in a field 'cap-token' automatically. 'onSolve' => 'function(e) { const token = e.detail.token; document.getElementById("captcha-token").value = token; document.getElementById("my-form").submit(); }', ]);
Full Example: Login Form with Captcha
<?php use NsuSoft\Captcha\CapWidget; use yii\helpers\Html; use yii\widgets\ActiveForm; $form = ActiveForm::begin([ 'id' => 'login-form', ]); ?> <?= $form->field($model, 'username')->textInput(['autofocus' => true]) ?> <?= $form->field($model, 'password')->passwordInput() ?> <!-- Render Cap Widget --> <?= CapWidget::widget([ 'endpoint' => Yii::$app->captcha->getEndpoint(), ]) ?> <div class="form-group"> <?= Html::submitButton('Login', ['class' => 'btn btn-primary', 'name' => 'login-button']) ?> </div> <?php ActiveForm::end(); ?>
🚀 Quick Start with Docker
The project includes docker-compose.yml for local development with a Cap Captcha server.
Start Services
docker-compose up -d
Access Points
| Service | URL | Description |
|---|---|---|
| 🌐 Cap Server | http://localhost:3000 |
Cap Captcha API endpoint |
| 📚 Swagger UI | http://localhost:3000/swagger |
Interactive API documentation |
| 🔑 Admin Key | o65imtWzvXDerEAt |
Default admin key (change in production) |
⚙️ Widget Properties Reference
| Property | Type | Default | Description |
|---|---|---|---|
endpoint |
string |
null |
Required. URI of the Cap Captcha server (e.g., http://localhost:3000/{siteKey}). |
cssVars |
array |
[] |
CSS variables you want to redeclare. See all available variables in CapWidget::DEFAULT_CSS_VARS |
disableHaptics |
bool|null |
null |
Disable haptics. |
hiddenFieldName |
string |
cap-token |
Cap Captcha hidden field name, where cap token was saved, when captcha was solved. |
id |
string|null |
auto-generated | HTML id attribute for the widget container. |
language |
string|null |
null |
The language in which to display the widget's messages. If not specified, the system language is used. Example: 'en-US' or 'ru-RU'. |
onSolve |
string|null |
null |
JavaScript function (as string) called when captcha is solved. Receives CustomEvent with detail.token. |
translationsCategory |
string |
widgets/cap |
Message category patterns for Application::$i18n->translations. |
troubleshootingUrl |
string |
https://capjs.js.org/guide/troubleshooting/instrumentation.html |
Troubleshooting URI. |
workerCount |
int|null |
null |
Workers count. Using all available cores to solving captcha, if it's not specified. |
onSolve Callback Example
The onSolve property accepts a JavaScript function as a string. The function receives a CustomEvent with a detail object containing the solved token:
function(e) { // e.detail.token contains the solved captcha token const token = e.detail.token; // Example: store in hidden field document.getElementById('captcha-token').value = token; // Example: submit form document.getElementById('my-form').submit(); }
🧪 Testing
The project uses Codeception for testing.
Run Tests Locally
# Install dependencies composer install --dev # Run all test suites vendor/bin/codecept run # Run with verbose output vendor/bin/codecept run --verbose # Run functional tests only vendor/bin/codecept run Functional
Run Tests in Docker
docker-compose run --rm php vendor/bin/codecept run
Configuration Files
| File | Purpose |
|---|---|
codeception.yml |
Main Codeception configuration |
config/test.php |
Test environment application config |
tests/Support/ |
Helper classes and fixtures |
🗂 Project Structure
yii-cap-captcha-widget/
├── src/
│ └── CapWidget.php # Main widget class
├── views/ # Directory fo test purpose
├── web/ # Directory fo test purpose
├── config/
│ └── test.php # Test configuration
├── controllers/ # Example controllers for testing
├── forms/ # Example form models
├── tests/
│ ├── Unit/ # Unit tests
│ ├── Functional/ # Integration tests
│ └── Support/ # Test helpers
├── bin/ # Docker helper scripts
├── composer.json # Dependencies and autoloading
├── docker-compose.yml # Docker orchestration
├── codeception.yml # Codeception configuration
├── LICENSE # BSD-3-Clause license
└── README.md # This file
🔗 Integration with yii-cap-captcha
For complete captcha protection, combine this widget with the yii-cap-captcha server-side component.
⚠️ Error Handling
Common Issues
| Issue | Solution |
|---|---|
| Cap Captcha API endpoint wasn't specified | Ensure endpoint property is set in widget config |
| Widget not rendering | Check that npm-asset/cap.js--widget is installed and assets are published |
| Token validation fails | Verify server-side secretKey matches the one registered with Cap server |
| CORS errors | Configure Cap server to allow requests from your domain |
Debugging Tips
-
Enable Yii2 debug mode to inspect asset loading:
'components' => [ 'assetManager' => [ 'appendTimestamp' => true, ], ],
-
Check browser console for Cap widget errors.
-
Log server-side validation requests:
Yii::info("Captcha token received: " . $model->captchaToken);
🔐 Security
⚠️ Critical Guidelines
-
Never expose
secretKeyin client-side code
The widget only handles client-side token generation. Server-side validation must use theyii-cap-captchacomponent with a securesecretKey. -
Validate tokens server-side
Always verify captcha tokens on the server usingCap::siteVerify()before processing sensitive actions. -
Use HTTPS in production
Configureendpointwithhttps://when deploying to production. -
Rotate keys regularly
Use the Cap server's key rotation features and update your configuration securely. -
Rate-limit validation endpoints
Protect your server-side validation route from abuse.
🤝 Contributing
We welcome contributions!
📋 Code Standards
- Follow PSR-12 coding style.
- Document public methods using PHPDoc.
- Add tests for new features or bug fixes.
- Use Conventional Commits for commit messages.
🔄 Pull Request Process
- Fork the repository.
- Create a feature branch:
git checkout -b feature/your-feature-name
- Make changes and add tests.
- Run tests:
vendor/bin/codecept run
- Update documentation if needed.
- Submit PR to
developbranch.
📄 License
This project is open-source software licensed under the BSD-3-Clause License.
See the LICENSE file for details.