Although there are quite a lot of questions concerning Yii2 captchas as well as problems with saving, I couldn't find and answer that solved my problem. Hope someone can help:
In my website I included a contact form along with a captcha. Therefor I added code to the model, to the IndexController and the form as described here: https://yii2-cookbook-test.readthedocs.io/forms-captcha/#how-add-captcha-to-a-form
The captcha is displayed and prevents from submitting the form if the code wasn't entered correctly. However, if I include the captcha validation rules, the message is not saved to the database. So there seems to be something wrong with the validation rule.
['verifyCode', 'captcha', 'captchaAction' => '/contact/index/captcha']
I just don't see what is wrong here. When I comment it out, it the model is saved but the captcha isn't validated. Leaving the part with "captchaAction" out leads to an Invalid Captcha ID error, the solution is to include the captchaAction as described here: Yii2 Invalid CAPTCHA action ID in module
Does anyone have an idea of what might be wrong here? Running in circles...
Form:
...
<div class="form-group">
<div><?= Yii::t('ContactModule.form', 'Please enter the letters from the image.'); ?></div>
<?= $form->field($model, 'verifyCode')->widget(Captcha::class, [
'captchaAction' => '/contact/index/captcha',
])->label(false); ?>
</div>
...
Model:
class Contact extends ActiveRecord{
public $verifyCode;
/**
* #inheritdoc
*/
public static function tableName()
{
return 'contact';
}
/**
* #inheritdoc
*/
public function rules()
{
return [
[['name','email','message'], 'required'], //Checking that all the fields are required
['email', 'email'], // Validating that email is a valid email
[['name'],'string', 'max' => 50], //Verifying that name is not greater than its max length
[['email'], 'string', 'max' => 50], //Verifying that email is not greater than its max length
[['message'], 'string', 'max' => 255],//Verifying that message is not greater than its max length
['state', 'boolean'],
[['date'], 'date', 'format' => 'php:Y-m-d'],
['verifyCode', 'captcha', 'captchaAction' => '/contact/index/captcha'],
];
}
...
Controller
class IndexController extends Controller
{
public $subLayout = "#contact/views/layouts/default";
/**
* #inheritdoc
*/
public function actions()
{
return [
'captcha' => [
'class' => 'yii\captcha\CaptchaAction',
]
];
}
/**
* Renders the index view for the module
*
* #return string
*/
public function actionIndex()
{
$model = new Contact();
if ($model->load(Yii::$app->request->post()) && $model->validate()) {
$model->save();
...
Related
Trying to validate if there are only spaces in input box.
This is my validations:
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Contracts\Validation\Validator;
use App\Rules\allAreSpaces;
class StoreUser extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'email' => 'required|email|max:64',
'phone' => 'bail|required|numeric|phone_min|phone_max|unique:users|not_in:0',
'password' => [new allAreSpaces, 'required', 'min:8', 'max:16', 'confirmed'],
'password_confirmation' => 'required',
];
}
public function messages()
{
return [
'email.required' => 'Email address cannot be empty',
'email.email' => 'Enter a valid Email address',
'email.max' => 'Email address cannot exceed 64 characters',
'email.unique' => 'Email already exists',
'phone.required' => 'Mobile number cannot be empty',
'phone.numeric' => 'Mobile number has to be numeric',
'phone.phone_min' => 'Mobile number should contain a minimum 5 characters',
'phone.phone_max' => 'Mobile number cannot exceed 11 characters',
'phone.unique' => 'Mobile number already exists',
'phone.not_in' => 'Enter a valid mobile number ',
'password.required' => 'Password cannot be empty',
'password.min' => 'Password should contain minimum 8 characters',
'password.max' => 'Password cannot exceed 16 characters',
'password.confirmed' => 'Password mismatch.Retry',
'password_confirmation.required' => 'Confirm Password cannot be empty',
];
}
public function withValidator(Validator $validator)
{
$email = $this->request->get( 'email' ); // Start with
$user = \App\User::Where('email', $email)->first();
if($user && $user->activated == 0){
$row = \App\User::find($user->id);
$row->delete();
}else{
$validator->sometimes('email', 'unique:users', function ($input) {
return true;
});
}
}
}
The following is the custom rule object that i was created:
<?php
namespace App\Rules;
use Illuminate\Contracts\Validation\Rule;
class allAreSpaces implements Rule
{
/**
* Create a new rule instance.
*
* #return void
*/
public function __construct()
{
//
}
/**
* Determine if the validation rule passes.
*
* #param string $attribute
* #param mixed $value
* #return bool
*/
public function passes($attribute, $value)
{
if(strlen($value) > 0){
if (strlen(trim($value)) == 0){
return false;
}
}
return true;
}
/**
* Get the validation error message.
*
* #return string
*/
public function message()
{
return 'Password cannot contain space character alone';
}
}
Initially its returning, 'Password cannot contain space character alone'. but after i type some spaces then submit it shows 'Password cannot be empty'. But i want 'Password cannot contain space character alone' if the typed characters are only spaces.
Eventhough i did use the following code, its not showing if the input has some spaces, instead it shows, 'Password cannot be empty'.
public function passes($attribute, $value)
{
return false;
}
i was wondering why is that?
Have you checked the global middleware, that is ran for all routes in your application which is set in your HTTP Kernel? These might come into play:
"By default, Laravel includes the TrimStrings and ConvertEmptyStringsToNull middleware in your application's global middleware stack. These middleware are listed in the stack by the App\Http\Kernel class. These middleware will automatically trim all incoming string fields on the request, as well as convert any empty string fields to null. This allows you to not have to worry about these normalization concerns in your routes and controllers.
If you would like to disable this behavior, you may remove the two middleware from your application's middleware stack by removing them from the $middleware property of your App\Http\Kernel class."
Laravel 5.5 Docs - Requests - Input trimming and normalization
This might be relevant as well, goes into some complications that can happen because of these middleware:
"By default, Laravel includes the TrimStrings and ConvertEmptyStringsToNull middleware in your application's global middleware stack. These middleware are listed in the stack by the App\Http\Kernel class. Because of this, you will often need to mark your "optional" request fields as nullable if you do not want the validator to consider null values as invalid. "
Laravel 5.5 Docs - Validation - A note on optional fields
so this is my register controller
protected function validator(array $data)
{
return Validator;
}
/**
* Create a new user instance after a valid registration.
*
* #param array $data
* #return User
*/
protected function create(array $data)
{
register here
}
I want to add a referral system to this process basically when registering user might send a refer_id (id of a user who has referred this user to website), I'll check that refer id and if it was valid I'll do some my thing
I want to change my validation function to something like
protected function validator(array $data)
{
$validation = Validator::make($data, [
'email' => ['required' ,'email' , 'max:255', Rule::unique('users')->where('rep_id' , $this->rep->id) ] ,
'password' => 'required|string|min:6|confirmed',
'name' => 'required|max:255',
'last_name' => 'required|max:255',
'refer_id' => 'present|numeric',
]);
if(isset($data['refer_id']))
{
$refer = User::find($data['refer_id']) ;
if($refer)
{
// return error : refer id is wrong !
}
}
return $validation ;
}
my problem is this part
// return error: refer id is wrong!
how can I return registering the user with this error back to view or add this error to validation errors?
Laravel has a clean approach to do this
try this
'refer_id' => 'nullable|exists:users,id'
or may be
'refer_id' => 'present|numeric|exists:users,id'
I have a user registration form, where i am using file input box to upload image.
Now the problem is , if i will select video file to upload it will pass ValidateRequest .
In ValidateRequest, i already define the rule for image, below is the code:
class UserValidateRequest extends Request {
public function __construct() {
}
protected $messages = [
'required.password' => 'We need to know your e-mail address!',
];
protected $rules = [
'first_name' => 'required|regex:"[a-zA-Z 0-9]"',
'last_name' => 'regex:"[a-zA-Z 0-9]"',
'image' => ' mimes:jpeg,jpg,png,gif |max:2048',
];
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize() {
return true;
}
public function messages() {
return [
'password.regex' => 'Password shall be 8-20 characters, must have a number and an alphabet', ,
'image.mimes' => 'Upload Gif || JPG || JPEG || PNG Images Only'
];
}
public function attributes() {
return[];
}
}
Instead of using mime type validation, try to add image validation rule to image field:
'image' => 'image|max:2048'
Trying my hand on learning laravel.
I have a user form which post to this route
Route::post('users/add','usersController#store')->middleware('admin');
The store function in the usersController calls another function called validateForm which basically validates the input from the form ,like so
class usersController extends Controller
{
/*
*Store a user in database
*/
function store(){
$input=Request::all();
// create the validation rules ------------------------
$rules = array(
'name' => 'required', // just a normal required validation
'lastname' => 'required', // just a normal required validation
'email' => 'required|email|unique:users', // required and must be unique in the users table
'password' => 'required',
);
$validationResponse=$this->validateForm($input,$rules);
if($validationResponse=="passed"){
$user=new \App\User;
$user->name=$input['name'];
$user->email=$input['email'];
$user->lastname=$input['lastname'];
$user->password=\Hash::make($input['password']);
$user->userlevel=isset($input['isAdmin'])?1:0;
$user->save();
return redirect('users');
}
else{
return Redirect::to('users/create')
->withErrors($validationResponse)->withInput();
}
}
/*
*validate user form input
*/
function validateForm($input,$rules){
// do the validation ----------------------------------
// validate against the inputs from our form
$validator = Validator::make($input, $rules);
// check if the validator failed -----------------------
if ($validator->fails()) {
// get the error messages from the validator
$messages = $validator->messages();
return $messages;
}
else{
return 'passed';
}
}
}
Now this is fine for accesing from the userController, but what if I have another controller say projectsController and I want to access the same funtion i.e. validateForm
Where I should put this common function and how can I access it from any controller?
Laravel built in answer to this is Form Request
Just create a form request using php artisan make:request UserCheck, and put in your validation rules in the method rules
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules() {
return [
'name' => 'required', // just a normal required validation
'lastname' => 'required', // just a normal required validation
'email' => 'required|email|unique:users', // required and must be unique in the users table
'password' => 'required',
]; }
And call it
/*
* Store a user in database
*/
public function store(UserCheck $request)
{
// The incoming request is valid...
}
I'm trying to make yii2 to validate my ActiveForm field that should be numeric and of 8 characters long.
Following is what I tried in the default LoginForm model of yii2/advanced/backend, but unfortunately the isNumeric validator simply doesn't kick in:
public function rules()
{
return [
// username and password are both required
[['username', 'password'], 'required'],
// username should be numeric
['username', 'isNumeric'],
// username should be numeric
['username', 'string', 'length'=>8],
// password is validated by validatePassword()
['password', 'validatePassword'],
];
}
/**
* Validates if the username is numeric.
* This method serves as the inline validation for username.
*
* #param string $attribute the attribute currently being validated
* #param array $params the additional name-value pairs given in the rule
*/
public function isNumeric($attribute, $params)
{
if (!is_numeric($this->username))
$this->addError($attribute, Yii::t('app', '{attribute} must be numeric', ['{attribute}'=>$attribute]));
}
/**
* Validates the password.
* This method serves as the inline validation for password.
*
* #param string $attribute the attribute currently being validated
* #param array $params the additional name-value pairs given in the rule
*/
public function validatePassword($attribute, $params)
{
if (!$this->hasErrors()) {
$user = $this->getUser();
if (!$user || !$user->validatePassword($this->password)) {
$this->addError($attribute, 'Incorrect username or password.');
}
}
}
I also tried adding a scenario as suggested in a related post (https://stackoverflow.com/a/27817221/2037924) but that only worked (as in displayed the error) if I did not include the password field in the scenario.
Is this a good way to achieve this at all, or can you think of a better way of doing it?
Note: the reason I define username as string is because the numbers may contain leading 0's.
Try with integer data type:
[['username'], 'integer'],
[['username'], 'string', 'min' => 8],
It will validate both numeric and length. This will do the trick.
Read more about the validations here: http://www.yiiframework.com/doc-2.0/guide-tutorial-core-validators.html#number
This works fine for me using the contact form from yii2-basic
/**
* #return array the validation rules.
*/
public function rules()
{
return [
// name, email, subject and body are required
[['name', 'email', 'subject', 'body'], 'required'],
// email has to be a valid email address
['email', 'email'],
['subject', 'is8NumbersOnly'],
// verifyCode needs to be entered correctly
['verifyCode', 'captcha'],
];
}
public function is8NumbersOnly($attribute)
{
if (!preg_match('/^[0-9]{8}$/', $this->$attribute)) {
$this->addError($attribute, 'must contain exactly 8 digits.');
}
}
public function rules()
{
return [
// username should be numeric
['username', 'match', 'pattern' => '/^\d{8}$/', 'message' => 'Field must contain exactly 8 digits.],
// ...
];
}
try this:
public function rules()
{
return [
// name, email, subject and body are required
[['name', 'email', 'subject', 'body'], 'required'],
// email has to be a valid email address
['email', 'email'],
[['subject'], 'number'],
[['subject'], 'string', 'max' => 8, 'min' => 8],
// verifyCode needs to be entered correctly
['verifyCode', 'captcha'],
];
}