How to test Zend framework2 form which implements CSRF element? - zend-framework

I have created the login form using Zend/Form and it contains input elements as well as CSRF element.
<!-- sample login.phtml code snippet -->
<form method="post" action="/xyz">
<?php
echo $this->formelement($form->get('email'));
echo $this->formelement($form->get('password'));
echo $this->formelement($form->get('csrf'));
echo $this->formelement($form->get('submit'));
?>
</form>
The following testcase fails because of the validation against CSRF element.
public function testLogin()
{
//code goes here
$params = array('email' => 'example#test.com', 'password' => 'example#test.com');
$this->dispatch($url, $method, $params);
//if the given username and password is correct the login page redirected to default home page
$this->assertResponseStatusCode(302);
}
In the above testcase i set the email and password values but i don't know how to set CSRF element. How could i test the form which implements CSRF element?

This can easily be achieved with the following:
$form = new LoginForm();
$csrf = $form->get('csrf')->getValue();
$params = array('email' => 'example#test.com',
'password' => 'example#test.com',
'csrf' => $csrf
);
Unless your form needs the form manager when you are going to have to use that rather than just instantiating the class but that's pretty easy to do in a unit test as well.
UPDATE:
Another method that works:
$form = new LoginForm();
$form->prepare();
$params = new \Zend\Stdlib\Parameters(
array(
'csrf' => $_SESSION['Zend_Validator_Csrf_salt_csrf']['hash'],
'yourotherparams' => 'thingsandstuff'
);
$this->dispatch($url, $method, $params);

Related

can't pass parameter from view to controller

Hi all I am currently working with zend 2.3. and while listing students I am trying to make link that allows to show detales about selected person. My problem is that I can't pass selected id to the action in module's controller. Here is my view's code that coresponds to link:
<a href="<?php echo $this->url('admin' ,
array( 'controller'=>'Admin', 'action'=>'viewstudent', 'ID' => $student->ID))."/admin/viewstudent";?>">detales</a>
and the action in controller
public function viewstudentAction ()
{
$id = (int) $this->params()->fromRoute('ID', 0);
echo $id;
//echo var_dump($id);
return new ViewModel(array(
'students' => $this->getStudentTable()->viewstudent($id),
));
}
Then I var_dump $id variable it shows 0 So what is the correct way to do this?
I have edited the a href's code like this
<a href="<?php echo $this->url('admin/default' ,
array( 'controller'=>'Admin', 'action'=>'viewstudent', 'id' => $student->ID));?>">Просмотр</a>
and it resolves to this:
Просмотр
url is
http://localhost:8080/disability/public/admin/Admin/viewstudent
The url is
http://localhost:8080/disability/public/admin/Admin/viewstudent
Problem is the same id didn't pass
I have found the solution to the problem. I passed the parameter using query here is how it looks in view file
<a href="<?php echo $this->url('admin/default',
array('controller' => 'Admin',
'action'=>'viewstudent'
),
array('query' =>
array('id' => $student->ID)
)
);
?>">view</a>
And then using $this->params retrieve it in my controller file
$id = $this->params()->fromQuery('id');

Show 404 error in fuelphp pagination

I want to use pagination in FuelPHP, I'm using this code:
$config = array(
'pagination_url' => 'http://localhost/live/public/index.php/admin/accounts/index/',
'total_items' => Model_Account::count(),
'per_page' => 10,
'uri_segment' => 3,
// or if you prefer pagination by query string
//'uri_segment' => 'page',
);
$pagination = Pagination::forge('mypagination', $config);
$data['example_data'] = Model_Account::query()
->rows_offset($pagination->per_page)
->rows_limit($pagination->offset)
->get();
// we pass the object, it will be rendered when echo'd in the view
$data['pagination'] = $pagination;
and here's the view:
<?php echo Pagination::instance('mypagination')->previous(); ?>
<?php echo Pagination::instance('mypagination')->render(); ?>
<?php echo Pagination::instance('mypagination')->next(); ?>
<?php echo Pagination::instance('mypagination')->last(); ?>
But when I try to click on any pagination in frontend then it sends error: 404 page not found
You will need to have a route set up so fuel knows how to map the URI admin/accounts/index/:page to the correct controller.
Something like the below should work in your routes.php config file. (Might need tweaking depending on your app)
'admin/accounts/index/:page' => 'admin/accounts/index'

calling echo $this->action('panLogin','user') and $this->action('panRegister','user') on same script

I have a problem, i'm trying to render 2 forms (login and register) on one layout scrpt (header.phtml), every time i submit on one of the forms both actions for the controller are getting fired and i'm unsure how to fix it.
The forms are getting rendered fine within the layout, however when you click 'Login' or 'Register' on the forms the code fires in both the 'login' and 'register actions.
the header layout script snippet:-
<div class="left">
<h1>Already a member? <br>Then Login!</h1>
<?php
echo $this->action('panlogin', 'user');
?>
</div>
<div class="left right">
<h1>Not a member yet? <br>Get Registered!</h1>
<?php
echo $this->action('panregister', 'user');
?>
</div>
the action scripts (phtmls)
panregister.phtml
<div id="pan-register">
<?php
$this->registerForm->setAction($this->url);
echo $this->registerForm;
?>
</div>
panlogin.phtml
<div id="pan-login">
<?php
$this->loginForm->setAction($this->url);
?>
</div>
the user controller actions:-
class Ajfit_UserController extends Zend_Controller_Action
{
protected $_loginForm;
protected $_registerForm;
public function init()
{
$this->_loginForm = new Ajfit_Form_User_Login(array(
'action' => '/user/login',
'method' => 'post',
));
$this->_registerForm = new \Ajfit\Form\User\Registration(array(
'action' => '/user/register',
'method' => 'post'
));
}
//REGISTER ACTIONS
public function panregisterAction(){
$this->registerAction();
}
public function registerAction(){
$request = $this->_request;
if ($this->_request->isPost()){
$formData = $this->_request->getPost();
}
$this->view->registerForm = $this->_registerForm;
}
//LOGIN ACTIONS
public function panloginAction(){
$this->loginAction();
}
public function loginAction(){
$request = $this->_request;
if(!$auth->hasIdentity()){
if ($this->_request->isPost()){
$formData = $this->_request->getPost();
}
}
$this->view->loginForm = $this->_loginForm;
}
}
Please can someone with a little more knowlegde with the action('act','cont'); ?> code with in a layout script help me out with this problem.
Thanks
Andrew
While David is correct where best practices are concerned, I have on occasion just added another if() statement. Kinda like this:
if ($this->getRequest()->isPost()) {
if ($this->getRequest()->getPost('submit') == 'OK') {
just make sure your submit label is unique.
Eventually I'll get around to refactoring all those actions I built early in the learning process, for now though, they work.
Now to be nosy :)
I noticed: $formData = $this->_request->getPost(); while this works, if you put any filters on your forms retrieving the data in this manner bypasses your filters. To retrieve filtered values use $formData = $this->getValues();
from the ZF manual
The Request Object
GET and POST Data
Be cautious when accessing data from the request object as it is not filtered in any way. The router and
dispatcher validate and filter data for use with their tasks, but
leave the data untouched in the request object.
From Zend_Form Quickstart
Assuming your validations have passed, you can now fetch the filtered
values:
$values = $form->getValues();
Don't render the actions in your layout. Just render the forms:
<div class="left">
<h1>Already a member? <br>Then Login!</h1>
<?php
echo new \Ajfit\Form\User\Login(array(
'action' => '/user/login',
'method' => 'post'
));
?>
</div>
<div class="left right">
<h1>Not a member yet? <br>Get Registered!</h1>
<?php
echo new \Ajfit\Form\User\Registration(array(
'action' => '/user/register',
'method' => 'post'
));
?>
</div>
Then, whichever form gets used will post to its own action.

Create a form for uploading images

I want to let users upload images from their drives. Searching around the net, here's what I've found :
The form :
class ImageForm extends BaseForm
{
public function configure()
{
parent::setUp();
$this->setWidget('file', new sfWidgetFormInputFileEditable(
array(
'edit_mode'=>false,
'with_delete' => false,
'file_src' => '',
)
));
$this->setValidator('file', new sfValidatorFile(
array(
'max_size' => 500000,
'mime_types' => 'web_images',
'path' => '/web/uploads/assets',
'required' => true
//'validated_file_class' => 'sfValidatedFileCustom'
)
));
}
}
the action :
public function executeAdd(sfWebRequest $request)
{
$this->form = new ImageForm();
if ($request->isMethod('post'))
if ($this->form->isValid())
{
//...what goes here ?
}
}
the template :
<form action="<?php echo url_for('#images_add') ?>" method="POST" enctype="multipart/data">
<?php echo $form['file']->renderError() ?>
<?php echo $form->render(array('file' => array('class' => 'file'))) ?>
<input type="submit" value="envoyer" />
</form>
Symfony doesn't throw any errors, but nothing is transfered. What am I missing ?
Youre missing an impotant part which is binding the the values to the form:
public function executeAdd(sfWebRequest $request)
{
$this->form = new ImageForm();
if ($request->isMethod('post'))
{
// you need to bind the values and files to the submitted form
$this->form->bind(
$request->getParameter($this->form->getName())
$request->getFiles($this->form->getName())
);
// then check if its valid - if it is valid the validator
// should save the file for you
if ($this->form->isValid())
{
// redirect, render a different view, or set a flash message
}
}
}
However, you want to make sure you set the name format for your form so you can grab a the values and files in the fashion... In your configure method you need to call setNameFormat:
public function configure()
{
// other config code
$this->widgetSchema->setNameFormat('image[%s]');
}
Also in configure you dont need to call parent::setUp()... That is called automatically and is actually what invokes the configure method.
LAstly, you ned to have to correct markup - your emissing the form name from your tag:
<form action="<?php echo url_for('#images_add') ?>" name="<?php echo $form->getName() ?>" method="POST" enctype="multipart/data">
Personally I like to use the form object to generate this as well as it looks cleaner to my eyes:
<?php echo $form->renderFormTag(
url_for('#images_add'),
array('method' => 'post') // any other html attriubutes
) ?>
It will work out the encoding and name attributes based on how youve configured the form.

Problem passing URL variables in post form submission with CakePHP FormHelper

I'm writing my first CakePHP application and am just writing the second part of a password reset form where a user has received an email containing a link to the site and when they click it they're asked to enter and confirm a new password.
The url of the page is like this:
/users/reset_password_confirm/23f9a5d7d1a2c952c01afacbefaba41a26062b17
The view is like:
<?php echo $form->create('User', array('action' => 'reset_password_confirm')); ?>
<?php
echo $form->input('password', array('label' => 'Password'));
echo $form->input('confirm_password', array('type' => 'password', 'label' => 'Confirm password'));
echo $form->hidden('static_hash');
?>
<?php echo $form->end('Reset password'); ?>
However this produces a form like:
<form id="UserResetPasswordConfirmForm" method="post" action="/users/reset_password_confirm/8">
The problem is the user id (8 in this case) is being added to the form action. It's not really a problem here, but when I want to pass through the hash to my controller:
function reset_password_confirm($static_hash=null) {
// function body
}
$static_hash is now populated with 8 rather than the hash from the URL.
I know I could sort this out by creating the form tag myself rather than using $form->create but is there a more cakey way of doing this?
$form->create('User', array('action' => '…', 'id' => false));
Just explicitly set params you don't want passed to null or false. This is unfortunately a case where Cake tries to be a little too intelligent for its own good. ;o)
You could probably also do something like this to POST to the same URL again:
$form->create('User', $this->here);
How about passing it as a parameter instead of form data :
<?php
echo $form->create('User', array('action' => 'reset_password_confirm', $static_hash));
echo $form->input('password', array('label' => 'Password'));
echo $form->input('confirm_password', array('type' => 'password', 'label' => 'Confirm password'));
echo $form->end('Reset password');
?>
and in the controller :
function reset_password_confirm($static_hash = null) {
// Check if form is submitted
if (!empty($this->data)) {
// if it submitted then do your logic
} else {
$this->set('static_hash', $static_hash); // Else, pass the hash to the view, so it can be passed again when form is submitted
}
}
Hope this help :)