Google recaptcha validation in yii2 always fails - yii2

I use himiklab/yii2-recaptcha-widget. I always get a validation error when I submit the form.
{"captcha":["The verification code is incorrect."]}.
Form:
$form->field($model, 'captcha',['template' => "{input}\n{hint}\n{error}"])->widget(
\himiklab\yii2\recaptcha\ReCaptcha::className(),
[
'siteKey' => <mysitekey>,
'widgetOptions' => ['id'=>'recaptcha1']
])
Controller:
if(isset($_POST['Contact'])){
if ($model->load(Yii::$app->request->post()) && $model->save()) {
What am I doing wrong?

The problem is that Yii always run validation twice, on validation() method and during the save executes again the validation, this cause that the first validation is successful however the second returns an error.
So, for the second case you will need to save without running the validations, which save(false).
The second chance might be to unhook the validation of the captcha just before the safe() method.

Related

CakePHP 3.8. Security Component - FormHelper end() method

Exact Problem and the Solution
Upon activating the CakePHP (3) Security Component, when loading a form, you generate three hidden fields in the form. These are '_Token[fields]', '_Token[unlocked]' and '_Token[debug]'. What exactly happens is the Form->end() method calls the secure() method (see FormHelper) when the request data contains a ['Token'] parameter.
The forms that were not working for me were all forms rendered as an Element. For these forms, the '$this->request->params' did not contain the parameter normally generated by the Security Component.
Solution was in manually adding the parameter to the request data..
$this->request->params['_Token'] = ['unlockedFields' => []];
This than runs through the secure() method of FormHelper, as it should, and token parameters are correctly added.
Original Question
I have an issue using the SecurityComponent of CakePHP 3.8.
Everything was working fine, until I loaded Component in my AppController.
If (!$this->request->is('ajax')) {
$this->loadComponent('Security');
}
My forms were working fine, but upon activating the component I get an error message. Apparently using the Security Component checks for an additional token apart from the csrf-token.
'_Token' was not found in request data.
I found a solution in customizing the Form->end() method.
"The end() method closes and completes a form. Often, end() will only
output a closing form tag, but using end() is a good practice as it
enables FormHelper to insert the hidden form elements that
Cake\Controller\Component\SecurityComponent requires."
I customized my end method as suggested in documentation:
echo $this->Form->end(['data-type' => 'hidden']);
But my output in HTML differs from the output in the documentation..
Documentation Output:
<div style="display:none;">
<input type="hidden" name="_Token[fields]" data-type="hidden"
value="2981c38990f3f6ba935e6561dc77277966fabd6d%3AAddresses.id">
<input type="hidden" name="_Token[unlocked]" data-type="hidden"
value="address%7Cfirst_name">
</div>
Example of a non-working form..
echo $this->Form->create($athlete, ['url' => ['controller' => 'Athletesux', 'action' => $action]]);
echo $this->Form->control('user_id', ['type' => 'hidden', 'value' => $userid]);
echo $this->Form->control('first_name');
echo $this->Form->control('last_name');
echo $this->Form->control('threek_time', ['value' => $athlete['3K_time']]);
echo $this->Form->control('fivek_time', ['value' => $athlete['5K_time']]);
echo $this->Form->control('tenk_time', ['value' => $athlete['10K_time']]);
echo $this->Form->select('country', $countryoptions);
echo $this->Form->select('gender', $gender);
echo $this->Form->button('Add Athlete');
echo $this->Form->end();
My output contains only one hidden field, for '_csrfToken'...
Can anyone explain what I can do about this? I don't find much information on this..
Thanks!

putting if statement in api with laravel

I'm currently learning on how API works and my mentor gave me a task to create submit the form using API and store the data on database with laravel and the task also require mandatory if logic on some field.
I have succeeded with the first task (storing data to the database ) and I'm having difficulties writing the mandatory if.
I'm confused, on my task paper I'm told to create one controller, one model and two endpoints (request-schedule and request-leaving) where each endpoint should have some parameters.
and for the request-leaving parameter, there are 10 parameters, 6 of them have this requirement like (mandatory if request type Request Day Off)
There are 3 requests typewritten on there
1. Request Day off
2. Request Schedule
3. Change Schedule
I'm a super newbie in programming, does anyone know how to solve this?
public function CreateReqSchedule(Request $request)
{
$reqschedule = new B777();
$reqschedule->reqtype = $request->input('reqtype');
$reqschedule->startdate = $request->input('startdate');
$reqschedule->enddate = $request->input('enddate');
$reqschedule->reason = $request->input('reason');
$reqschedule->route = $request->input('route');
$reqschedule->actualschedule = $request->input('actualschedule');
$reqschedule->changetoschedule = $request->input('changetoschedule');
$reqschedule->swapcrewid = $request->input('swapcrewid');
$reqschedule->swapcrewschedule = $request->input('swapcrewschedule');
$reqschedule->note = $request->input('note');
$reqschedule->save();
return response()->json($reqschedule);
}
code above is my only work, I'm feeling anxious, because I've googled it myself but I'm still stuck.
So you are talking about validations. you can put laravel validation into it like below
Use required validation for mandotory data and return response in json
// Making validation for fields
$validator = \Validator::make($request->all(), [
'fields1' => 'required',
'fields2' => 'required',
'fields3' => 'required',
]);
if ($validator->fails())
{
// return response on validaton fails
return response()->json(['status'=>400,'errors'=>$validator->errors()->all()]);
}
// If validation passes store your data in database

Laravel: Store error messages in database

Any one know how to send error messages to database in laravel which generate from app/exceptions/handler.php ?
I need to send what error massages generated in report() method to database.
If you are interested doing this manually, you can do something as following.
Step 1 -
Create a model to store errors that has a DB structure as following.
class Error extends Model
{
protected $fillable = ['user_id' , 'code' , 'file' , 'line' , 'message' , 'trace' ];
}
Step 2
Locate the App/Exceptions/Handler.php file, include Auth, and the Error model you created. and replace the report function with the following code.
public function report(Exception $exception) {
// Checks if a user has logged in to the system, so the error will be recorded with the user id
$userId = 0;
if (Auth::user()) {
$userId = Auth::user()->id;
}
$data = array(
'user_id' => $userId,
'code' => $exception->getCode(),
'file' => $exception->getFile(),
'line' => $exception->getLine(),
'message' => $exception->getMessage(),
'trace' => $exception->getTraceAsString(),
);
Error::create($data);
parent::report($exception);
}
(I am demonstrating this using laravel 5.6)
Because Laravel uses Monolog for handling logging it seems that writing Monolog Handler would be the cleanest way.
I was able to find something that exists already, please have a look at monolog-mysql package. I did not use it, so I don't know whether it works and if it works well, but it's definitely good starting point.

How to use Url::remember in yii2

I want to create a link on my error page to take user back to the previous link.
Suppose the current URL is http://example.com/site/product, and a user try to view
http://example.com/site/product?id=100 and a product with id =100 does not exit, the system should throw 404 error to the error page, now if i want to create a link to take the user back to http://example.com/site/product the previous URl how do I make this work. i can make this work by hardcoding this in my error views file, but i want it dynamically as i have many controller an action using the same view file.
I try this in my site conteoller
controller/site
public function actions()
{
$url = Url::remember();
return [
'error' => [
'class' => 'yii\web\ErrorAction',
],
$this->render('error',['url'=>$url]),
];
}
and try to get the value the in error view file like this
/views/site/error.php
<p>
<?= Html::a('go back', [$url)?>
</p>
but it has no vaule..
please any good idea on how to make this work, am also open to new solution
this is form Yii2 Guide http://www.yiiframework.com/doc-2.0/guide-helper-url.html#remember-urls
There are cases when you need to remember URL and afterwards use it
during processing of the one of sequential requests. It can be
achieved in the following way:
// Remember current URL Url::remember();
// Remember URL specified. See Url::to() for argument format.
Url::remember(['product/view', 'id' => 42]);
// Remember URL specified with a name given
Url::remember(['product/view', 'id' => 42], 'product');
In the next
request we can get URL remembered in the following way:
$url = Url::previous();
// or
$productUrl = Url::previous('product');

Is it possible to get the Model error code inside the controller in CakePHP?

I have a simple unsubscribe function in my Unsubscribed controller.
if ($this->Unsubscribe->save($this->data['Unsubscribes'])) {
// success
$this->Session->setFlash('Your email has been unsubscribed!');
$this->redirect('/unsubscribes/unsubscribe');
} else {
// error
$this->Session->setFlash('There was an error!');
$this->redirect('/unsubscribes/unsubscribe');
}
Here is the problem. I want to set the email address in the database as unique. So if someone enters the email address multiple times (or we already have it in our unsubscribe list), we are not populating the database with duplicate records. However, I want the visitor to know they have been added to the database (so they know they are unsubscribed).
Is there a way to detect the Duplicate entry error from the controller so I can equate that to a success? The caveat, I don't want to create a extended app_model. Any ideas? Can it be done? How is the best way to do this?
SOLUTION: Here is the final solution I implemented. I added the validation (as suggested by the chosen answer below) and I updated my controller as follows:
// error
if(isset($this->Unsubscribe->validationErrors['email'])){
$error = 'Your email has been unsubscribed!';
} else {
$error = 'Something went wrong. Please try again.';
}
$this->Session->setFlash($error);
$this->redirect('/unsubscribes/unsubscribe');
What about using the isUnique validation rule? Then just use the validation error to inform the user.
var $validate = array(
'login' => array(
'rule' => 'isUnique',
'message' => 'This username has already been taken.'
)
);
Stole this directly from the cookbook. Section 4.1.4.14 isUnique to be precise.
I think you can do it like this:
if ($this->Unsubscribe->find('count',array('conditions'=>array('email'=>$this->data['Unsubscribes']['email']))) > 0 )
{
$this->Session->setFlash('duplicate email!');
$this->redirect('/unsubscribes/unsubscribe');
}
//then do your stuff
It depends. Is there any other error that might occur that you want to display? Or is this the only error that may occur? In case of the latter, just don't check:
$this->Unsubscribe->save($this->data['Unsubscribes']);
// I don't care if that actually saved or not,
// unless something horrible happened the email is in the database
$this->Session->setFlash('Your email has been unsubscribed!');
$this->redirect('/unsubscribes/unsubscribe');
Otherwise, you can use the invalidFields() method to find out what went wrong.