Disable symfony 2 csrf token protection on ajax submit - ajax

i'm building a mobile app talking to my symfony2 app via webservices
I can't find a way to disable csrf protection on a specific controller/action
i want to post registration data to this action and use sf2 form validation. I do not call the form in my mobile app
Can't change container parameters in action, throw an exception because it is a frozen parameter...
I do not want to disable form protection for whole my application
any clue ?
thanks !
update: with symfony 2.1.x
/**
* {#inheritdoc}
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'csrf_protection' => false,
));
}

If you're looking for a bit easier and faster solution than suggested in answer above, here's how:
<?php
// ...
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilder;
use Symfony\Component\OptionsResolver\OptionsResolver;
class MyType extends AbstractType
{
// ...
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'csrf_protection' => false,
));
}
}
.. or if you're using older versions (Symfony 2.0.*):
<?php
// ...
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilder;
class MyType extends AbstractType
{
// ....
public function getDefaultOptions(array $options)
{
$options = parent::getDefaultOptions($options);
$options['csrf_protection'] = false;
return $options;
}
}
Consult the Symfony documentation for additional information.
Edit: updated answer to latest Symfony version, thanks
naitsirch

Using the form factory
For those who want to create a simple form in a controller:
$form = $this->container->get('form.factory')
->createNamedBuilder(null, 'form', null, array('csrf_protection' => false))
->add('yourField','text', array(
'label' => false,
'mapped' => false
))
->getForm();

public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'csrf_protection' => false,
]);
}

Using the form factory in Symfony 3
use Symfony\Component\Form\Extension\Core\Type\FormType;
$form = $this->container->get('form.factory')
->createNamedBuilder(null, FormType::class, null, array('csrf_protection' => false))
->add('yourField','text', array(
'label' => false,
'mapped' => false
))
->getForm();
Adapted from Mick's answer

I can't be 100% sure but I think I read somewhere that you can pass csrf_provider option while creating form.
All providers are subtypes of interface Symfony\Component\Form\Extension\Csrf\CsrfProvider and you should be able to create your own:
class MyNonCsrfProvider extends DefaultCsrfProvider{
public function isCsrfTokenValid($intention, $token)
{
return true;
}
}
and in controller:
$this->createForm(new CustomFormType(), array(
'csrf_provider' => new MyNonCsrfProvider()
));
I haven't tried this myself but this sounds like a possible solution...

Related

Merge FormRequest rules

This question is based on this thread: Merge 2 rules FormFequest for validate an update and store action in laravel5.5
Context: Let's suppose I have these 2 requests and I want to merge the SocialMediaFormRequest rules in ReadersFormRequest rules.
ReadersFormRequest
class ReadersFormRequest extends FormRequest
{
public function rules(SocialMediaFormRequest $social)
{
$mediaRules = $social->rules();
$rules = [
'first_name'=>'required',
'last_name'=>'required',
'birthday'=>'required',
'region'=>'required',
'photo_url'=>'required',
'support'=>'required',
'riwayas_id'=>'required',
'description'=>'required',
];
return array_merge($rules,$mediaRules);
}
}
SocialMediaFormRequest
class SocialMediaFormRequest extends FormRequest
{
public function rules()
{
return [
'url'=>'required|url',
'title'=>'required'
];
}
}
Form that I received
first_name: "example"
last_name: "example"
birthday: 2022-06-13
region: somewhere
photo_url: "https:XXX"
support: false
riwayas_id: 1
description: ""
media.url: "https:YYY"
media.title: "stackoverflow"
Question: How can I only pass the argument media.XXX in my form SocialMediaFormRequest?
You can use prepareForValidation() method in the form request to sanitize the inputs : https://laravel.com/docs/9.x/validation#preparing-input-for-validation
So, if in SocialMediaFormRequest you receive the full request you can only get the required fields like that:
public function prepareForValidation()
{
$this->replace([
'url' => $this->url ?? ($this->media['url'] ?? null),
'title' => $this->title ?? ($this->media['title'] ?? null),
]);
}
Also, in ReadersFormRequest when you inject the other request or resolve it from the container it doesn't work correctly, so it is better to get the rules like that:
public function rules()
{
$mediaRules = (new SocialMediaFormRequest())->rules();
and in order to access the media.* attributes in ReadersFormRequest you can again use prepareForValidation:
public function prepareForValidation()
{
$this->merge([
'url' => $this->media['url'] ?? null,
'title' => $this->media['title'] ?? null,
]);
}

yii2 custom validation not working

I need to compare 2 attribute value in the model and only if first value is lower than second value form can validate.I try with below code but it not worked.
controller
public function actionOpanningBalance(){
$model = new Bill();
if ($model->load(Yii::$app->request->post())) {
$model->created_at = \Yii::$app->user->identity->id;
$model->save();
}else{
return $this->render('OpanningBalance', [
'model' => $model,
]);
}
}
Model
public function rules()
{
return [
[['outlet_id', 'sr_id', 'bill_number', 'bill_date', 'created_at', 'created_date','bill_amount','credit_amount'], 'required'],
[['outlet_id', 'sr_id', 'created_at', 'updated_at'], 'integer'],
[['bill_date', 'd_slip_date', 'cheque_date', 'created_date', 'updated_date','status'], 'safe'],
[['bill_amount', 'cash_amount', 'cheque_amount', 'credit_amount'], 'number'],
[['comment'], 'string'],
['credit_amount',function compareValue($attribute,$param){
if($this->$attribute > $this->bill_amount){
$this->addError($attribute, 'Credit amount should less than Bill amount');
}],
[['bill_number', 'd_slip_no', 'bank', 'branch'], 'string', 'max' => 225],
[['cheque_number'], 'string', 'max' => 100],
[['bill_number'], 'unique']
];
}
}
It's going in to the validator function but not add the error like i wanted
$this->addError($attribute, 'Credit amount should less than Bill amount');
anyone can help me with this?
If the validation is not adding any error, it's most likely being skipped. The issue is most likely becasue of default rules behaviour whereby it skips empty or already error given values as per here: https://www.yiiframework.com/doc/guide/2.0/en/input-validation#inline-validators
Specifically:
By default, inline validators will not be applied if their associated attributes receive empty inputs or if they have already failed some validation rules. If you want to make sure a rule is always applied, you may configure the skipOnEmpty and/or skipOnError properties to be false in the rule declarations.
So you would need to set up the skipOnEmpty or skipOnError values depending on what works for you:
[
['country', 'validateCountry', 'skipOnEmpty' => false, 'skipOnError' => false],
]
Try this:
public function actionOpanningBalance(){
$model = new Bill();
if ($model->load(Yii::$app->request->post()) && $model->validate()) {
$model->created_at = \Yii::$app->user->identity->id;
$model->save();
}else{
return $this->render('OpanningBalance', [
'model' => $model,
]);
}
}
For Validation
You can use anonymous function :
['credit_amount',function ($attribute, $params) {
if ($this->$attribute > $this->bill_amount)) {
$this->addError($attribute, 'Credit amount should less than Bill amount.');
return false;
}
}],
you can use like this below answer is also write
public function rules(){
return [
['credit_amount','custom_function_validation', 'on' =>'scenario'];
}
public function custom_function_validation($attribute){
// add custom validation
if ($this->$attribute < $this->cash_amount)
$this->addError($attribute,'Credit amount should less than Bill amount.');
}
I've made custom_function_validation working using 3rd params like this:
public function is18yo($attribute, $params, $validator)
{
$dobDate = new DateTime($this->$attribute);
$now = new DateTime();
if ($now->diff($dobDate)->y < 18) {
$validator->addError($this, $attribute, 'At least 18 years old');
return false;
}
}
This is a back end validation and it will trigger on submit only. So you can try something like this inside your validation function.
if (!$this->hasErrors()) {
// Your validation code goes here.
}
If you check the basic Yii2 app generated you can see that example in file models/LoginForm.php, there is a function named validatePassword.
Validation will trigger only after submitting the form.

Phalcon validation scenario

I used to use Yii framework. I would like to make project using Phalcon. I could not find validation scenario on Phalcon. What is the best way to correctly implement it on Phalcon?
Thanks in advance.
Any data validation:
<?php
use Phalcon\Validation\Validator\PresenceOf,
Phalcon\Validation\Validator\Email;
$validation = new Phalcon\Validation();
$validation->add('name', new PresenceOf(array(
'message' => 'The name is required'
)));
$validation->add('email', new PresenceOf(array(
'message' => 'The e-mail is required'
)));
$validation->add('email', new Email(array(
'message' => 'The e-mail is not valid'
)));
$messages = $validation->validate($_POST);
if (count($messages)) {
foreach ($messages as $message) {
echo $message, '<br>';
}
}
http://docs.phalconphp.com/en/1.2.6/reference/validation.html
If you are working with models:
<?php
use Phalcon\Mvc\Model\Validator\InclusionIn,
Phalcon\Mvc\Model\Validator\Uniqueness;
class Robots extends \Phalcon\Mvc\Model
{
public function validation()
{
$this->validate(new InclusionIn(
array(
"field" => "type",
"domain" => array("Mechanical", "Virtual")
)
));
$this->validate(new Uniqueness(
array(
"field" => "name",
"message" => "The robot name must be unique"
)
));
return $this->validationHasFailed() != true;
}
}
http://docs.phalconphp.com/en/1.2.6/reference/models.html#validating-data-integrity
models also have events, so you can add any logic you need in these functions:
http://docs.phalconphp.com/en/1.2.6/reference/models.html#events-and-events-manager
I would like to use forms for CRUD as they are very dynamic and reusable.
You can achieve that in forms using options.
You can pass additional options to form and act like a scenario.
You can check Form constructor here
https://docs.phalconphp.com/en/latest/api/Phalcon_Forms_Form.html
In your controller you can pass $options
<?php
use Phalcon\Mvc\Controller;
class PostsController extends Controller
{
public function insertAction()
{
$options = array();
$options['scenario'] = 'insert';
$myForm = new MyForm(null, $options);
if($this->request->hasPost('insert')) {
// this will be our model
$profile = new Profile();
// we will bind model to form to copy all valid data and check validations of forms
if($myForm->isValid($_POST, $profile)) {
$profile->save();
}
else {
echo "<pre/>";print_r($myForm->getMessages());exit();
}
}
}
public function updateAction()
{
$options = array();
$options['scenario'] = 'update';
$myForm = new MyForm(null, $options);
}
}
And your form should look like something this
<?php
// elements
use Phalcon\Forms\Form;
use Phalcon\Forms\Element\Text;
// validators
use Phalcon\Validation\Validator\PresenceOf;
class MyForm extends Form {
public function initialize($entity = null, $options = null) {
$name = new Text('first_name');
$this->add($name);
if($options['scenario'] == 'insert') {
// at the insertion time name is required
$name->addValidator(new PresenceOf(array('message' => 'Name is required.')));
}
else {
// at the update time name is not required
// as well you can add more additional validations
}
}
}
now you can add multiple scenarios and act based on scenarios.

Zend Framework 2: get matched route in view

I'm currently learning ZF2 by developing a small MVC application roughly based on the skeleton app. Right now I'm trying to hide some fixed HTML elements based on the route matched: just as an example, I don't want the main menu to show during the login phase.
I can do that easily by passing toggle parameters as return values from the controller actions, but it doesn't feel right, so I'd like to just check the matched route from the layout and compose the layout accordingly.
Problem is, I don't know how to get the matched route in the template. Is this possible? Are there other solutions to avoid adding layout logic into controllers?
Edit after some good Frankenstein work, I was able to find a solution for this. I like the idea of using a helper, so I just tried to pass it the Application object, from the boostrap function in the main module:
$app = $e->getApplication();
$serviceManager = $app->getServiceManager();
....
$serviceManager->get('viewhelpermanager')->setFactory('getRoute', function($sm) use ($app) {
return new Helper\GetRoute($app);
});
and the helper function:
use Zend\View\Helper\AbstractHelper;
class GetRoute extends AbstractHelper {
private $sm;
public function __construct($app) {
$this->sm = $app->getServiceManager();
}
public function echoRoute() {
$router = $this->sm->get('router');
$request = $this->sm->get('request');
$routeMatch = $router->match($request);
if (!is_null($routeMatch))
echo $routeMatch->getMatchedRouteName();
}
}
perhaps there's a cleaner, more ZF2ish way to do this...
Another solution without a new match
$routeMatch = $serviceLocator->get('Application')->getMvcEvent()->getRouteMatch();
echo $routeMatch->getMatchedRouteName();
There is a way to get service manager in layout:
$sm = $this->getHelperPluginManager()->getServiceLocator();
and then you can access $sm->get('router') etc.
You could create a View helper that implements ServiceManagerAwareInterface. Then inside the View helper using the ServiceManager instance to retrieve both the router and request objects then reconstruct the route match.
$services = $this->getServiceManager();
$router = $services->get('router');
$request = $services->get('request');
$routeMatch = $router->match($request);
echo $routeMatch->getMatchedRouteName();
I'd also recommend writing the View helper so that code only triggers once per request.
When moving to ZF3, you should consider use this method... since getLocator isn't available anymore (and it's not correct inject it).
Create the Helper
namespace Application\View\Helper;
use Zend\Http\Request;
use Zend\Router\RouteStackInterface;
use Zend\View\Helper\AbstractHelper;
/**
* Helper to get the RouteMatch
*/
class RouteMatch extends AbstractHelper
{
/**
* RouteStackInterface instance.
*
* #var RouteStackInterface
*/
protected $router;
/**
* #var Request
*/
protected $request;
/**
* RouteMatch constructor.
* #param RouteStackInterface $router
* #param Request $request
*/
public function __construct(RouteStackInterface $router, Request $request)
{
$this->router = $router;
$this->request = $request;
}
/**
* #return \Zend\Router\RouteMatch
*/
public function __invoke()
{
return $this->router->match($this->request);
}
}
Create a Factory for this helper
namespace Application\View\Helper;
use Interop\Container\ContainerInterface;
use Zend\ServiceManager\Factory\FactoryInterface;
class RouteMatchFactory implements FactoryInterface
{
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
$router = $container->get('router');
$request = $container->get('request');
return new RouteMatch($router, $request);
}
}
Call your Factory on your Module.php and create an Alias for it.
public function getViewHelperConfig()
{
return array(
'factories' => array(
RouteMatch::class => RouteMatchFactory::class,
),
'aliases' => array(
'routeMatch' => RouteMatch::class,
)
);
}
That's it... you have a RouteMatch Helper using the new ZF3 standards.
Bye!
In view you can use:
$this->getHelperPluginManager()->getServiceLocator()->get('request')->getUri()->getPath();
or
$this->getHelperPluginManager()->getServiceLocator()->get('request')->getUri()->toString();
I believe you can solve it by finding the action/controller names:
$controller = $this->getRequest()->getControllerName();
$action = $this->getRequest()->getActionName();
Once you know the action, you can have specific conditions to enable sections of the layout.
I view you can use
$this->getHelperPluginManager()->getServiceLocator()->get('Application')->getMvcEvent()->getRouteMatch()->getMatchedRouteName();
Additional information about "Rodrigo Boratto" post for integrating getRouteMatch in ZF3 (I can't comment because I have under 50 repo...)
In view helper file these line:
use Zend\Mvc\Router\RouteMatch as MvcRouteMatch;
use Zend\Mvc\Router\RouteStackInterface;
should be:
use Zend\Router\RouteMatch as MvcRouteMatch;
use Zend\Router\RouteStackInterface;
I don't know when they made that change but the files are in Zend\Router namespace.
P.S. I use composer if that matters.
My controller:
<?PHP
namespace SomeName\Controller;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
class SomeController extends AbstractActionController
{
public function getIdAction()
{
$id = $this->params()->fromRoute('id', 0);
return new ViewModel(array(
'id' => $id,
));
}
}
My Router:
<?php
return array(
'controllers' => array(
'invokables' => array(
'SomeName\Controller\Some' => 'SomeName\Controller\SomeController',
),
),
'router' => array(
'routes' => array(
'testId' => array(
'type' => 'segment',
'options' => array(
'route' => '/[:id]',
'constraints' => array(
'id' => '\d*',
),
'defaults' => array(
'controller' => 'SomeName\Controller\Some',
'action' => 'getId',
),
),
),
),
),
'view_manager' => array(
'template_path_stack' => array(
'album' => __DIR__ . '/../view',
),
),
);
At any view or layout, you are able to test route with this function:
<?php function itsRoute($routeName){
$flag = false;
if($this->serverUrl(true) == $this->url($route,[],['force_canonical'=>true]))){
$flag = true;
}
return $flag;
}

Using Validation Callback in Kohana 3.2 ORM model

I'm trying to create a custom function to validate multiple fields in kohana 3.2 orm model.
I know that there's a lot of examples showing how to do this from the controller but I want to set it up in the orm model.
I'm trying to do something like this:
public function rules()
{
return array(
'my_field' => array(
array(array($this, 'my_function')),
),
);
}
public function my_function(Validation $validation, $my_field)
{
//Some calculation and then return error..
$validation->add_error($my_field, 'my_field_not_valid');
}
Dont forget to define params for your custom callback:
public function rules()
{
return array(
'my_field' => array(
array(array($this, 'my_function'), array(':validation', ':field')),
),
);
}
http://kohanaframework.org/3.2/guide/kohana/security/validation#binding-variables
PS. Please paste your error/exception text. Usually it already contains correct answer.

Resources