Zend_Test - Setting redirect in Controller Plugin for PHPUnit - zend-framework

I have been trying to use PHPUnit to test an application. I have it all working, but cannot test redirects.
My redirects are occurring inside an Acl Controller Plugin, not inside an Action in a Controller.
I have changed them to use the suggested format of
$r = Zend_Controller_Action_HelperBroker::getStaticHelper('redirector');
$r->gotoSimple("index", "index", "default");
But this fails in the tests, the response body is empty and I get errors like
Zend_Dom_Exception: Cannot query; no document registered
If I then change the test so that the dispatch method does not result in gotoSimple() being called then the test runs correctly.
How am I supposed to do a redirect in my application so that it runs correctly with Zend_Test's response object?
The Zend docs cover this in about two lines, which I have tried and it fails.
Thanks.

To test that redirect has occurred, you need to add
$this->assertRedirectTo( 'index' );
after running $this->dispatch();
You cannot query the response body, since it's empty in case of redirect (that's where your exception comes from).
You can always check what the response actually looks like with
print_r( $this->getResponse() );

Make sure, your actions return anything after redirections, because Zend_Test_PHPUnit disables redirects, so the code after redirect is executed as well.
$r = Zend_Controller_Action_HelperBroker::getStaticHelper('redirector');
$r->gotoSimple("index", "index", "default");
return;
or
$r = Zend_Controller_Action_HelperBroker::getStaticHelper('redirector');
return $r->gotoSimple("index", "index", "default");
To test the redirect itself, you may use assertRedirect* assertions.
Read the above manual, because there are important notes about action hooks.

Related

Expecting arguments in Mojolicious routes

I have two routes in Mojolicious app as follows:
my $route = $r->any('/api')->to('API#');
$route->get('/get_data')->to('#process_forms');
$route->get('/get_data/?file=:file&name=:name')->to('#submit_forms');
if I go to /api/get_data I get redirected to process_forms function. I want the app to take me to submit_forms function if I pass additional arguments to that same route. for example, url /api/get_data/?file=myfile&name=myname should call submit_forms function, but that's not the case here.
In both scenarios, process_forms is called.
What option Mojolicious routing provides to help me with this?
Mojo's router connects URL and HTTP request methods to controllers. The GET and POST parameters are not used in routing. This makes sense, because a URL is typically supposed to target a resource by itself.
You have a path /get_data you need to send that to one controller. From there you want it sounds like you want to do is to go to another controller if you have GET parameters (passed in the URL). You can do this, but it's not normally what you want.
Just putting a conditional in a controller,
What you normally want when handling get parameters is simply to put them inside a block in the controller, IE,
my $query = $c->req->query_params
my $file = $query->param('foo');
my $name = $query->param('name');
if ( defined $file && defined $name) {
# we have file and name
}
else {
# or we do not
}
Redispatch
But you can always redispatch to a different controller (manually)
MyApp::Controller::submit_forms($self);
Or, through Mojo,
$self->routes->continue("#submit_forms")
As a last idea, you can also make it that the route doesn't match if the post variables aren't there. But, I've never needed to do this.

The "state" param from the URL and session do not match

In facebook documantion
require('include/facebook/autoload.php'); //SDK directory
$fb = new Facebook\Facebook([
'app_id' => '***********',
'app_secret' => '***********************'
]);
$helper = $fb->getRedirectLoginHelper();
$permissions = ['email', 'public_profile']; // optional
$loginUrl = $helper->getLoginUrl('http://www.meusite.com.br/login-callback.php', $permissions);
When direct it to the url $loginUrl, the return is:
Facebook SDK returned an error: Cross-site request forgery validation failed. The "state" param from the URL and session do not match
I had the same error.
The problem occurred because I did getLoginUrl(...) before getAccessToken()
So rid of getLoginUrl(...) in redirected URL and code should works.
I had the same issue and for me that error was occurring because I did not put session_start(); in my login.php page code before calling getLoginUrl(..) and also at the top of login-callback.php page.
Just put session_start(); in your "login" page and "login-callback" page and it will work surely just like it is working for me now.
There could be 2 reason for this error:
you didn't call session_start(); before getLoginUrl call
You executed getLoginUrl again in login-callback.php, so state value regenerated and mismatched with the redirected value
Possible Fixes : I used the following configuration settings .
Enable WebAuthLogin under the advanced tab . Provide the url in the WebAuthLogin settins as same as that you provide in $loginUrl ;
For example if you use $loginUrl as https://example.com/ use that same in the WebAuthlogin Url
$loginUrl = $helper->getLoginUrl('https://example.com/', $permissions);
This problem occures also in case that you generate 2 or more login links on the same page (e.g. one for login and other for registration - even both point to the same url, they have just different labels).
Facebook SDK creates/updates $_SESSION[FBRLH_state] for each new generated loginURL. So if there are 2 generated URLs (using $helper->getLoginUrl()) then the $_SESSION[FBRLH_state] is 2-times rewritten and valid only for the last generated URL. Previous login URL becomes invalid. It means that it is not possible to generate 2 valid loginURLs. In case that 2 same URLs are generated then return the first one and avoid call of Facebook SDK for generation of second one.
I had the same problem.
The reason for this error is because --->
When "$helper->getLoginUrl" calls, it create a session variable "FB_State", and this is something to FB uses to match the token. Every-time getLoginUrl calls, it create new state. Then after user authorized and redirect back, if you codes cannot detect this event and re-run "$helper->getLoginUrl", then this error will occur.
The solution ->
refine your coding, stop run "$helper->getLoginUrl" again if authorized.
if you already rerun, then set the session variable for the token to NULL if you have, then User can re-authorize again.
when user tries re-authorize, they can remove the authorized APP once or you need to generate new link with "$helper->getReRequestUrl"
Yet, token has be called by "getAccessToken()" before the "$helper->getLoginUrl" or "$helper->getReRequestUrl" runs.
Good Luck!!!!!
Finally, looking into FB code, I discovered that the problem "Cross-site request forgery validation failed. Required param “state” missing" and similars are caused by PHP variable $_SESSION['FBRLH_state'] that for some "strange" reason when FB call the login-callback file.
To solve it I store this variable "FBRLH_state" AFTER the call of function $helper->getLoginUrl(...). Is very important to do only after the call of this function due to is inside this function when the variable $_SESSION['FBRLH_state'] is populated.
Below an example of my code in the login.php:
$uri=$helper->getLoginUrl($uri, $permissions);
foreach ($_SESSION as $k=>$v) {
if(strpos($k, "FBRLH_")!==FALSE) {
if(!setcookie($k, $v)) {
//what??
} else {
$_COOKIE[$k]=$v;
}
}
}
var_dump($_COOKIE);
And in the login-callback.php before calling all FB code:
foreach ($_COOKIE as $k=>$v) {
if(strpos($k, "FBRLH_")!==FALSE) {
$_SESSION[$k]=$v;
}
}
Last, but not least, remember also to include code for PHP session so..
if(!session_id()) {
session_start();
}
...
...
...
...
<?php session_write_close() ?>
I hope this response can help you to save 8-10 hours of work :)
Bye, Alex.
This issue was a bit confusing for me, because I had to change a line at the facebook src file:
src/Facebook/Helpers/FacebookRedirectLoginHelper.php
at the function: "validateCsrf" like this:
if ($result !== 0) {
throw new FacebookSDKException('Cross-site request forgery validation failed. The "state" param from the URL and session do not match.');
}
And change it into:
if ($result === 0) {
throw new FacebookSDKException('Cross-site request forgery validation failed. The "state" param from the URL and session do not match.');
}
I don't know if this makes a violation to the facebook SDK security, so I truly opened to any exlanation or recommendation for this answer.
You may also make the following changes at the facebook app manager:
add your site and callback-url into your facebook app account at:
setting->advanced:Valid OAuth redirect URIs
Don't forget to add another url with slash (/) at the end of each url and check all 4 checkboxes at Client OAuth Settings.
I had the same error. Are you using 1 file or 2? I was trying to get by using 1 file but my error was resolved when I split into login.php & fb-callback.php as the documentation recommended. My sessions were being re-written so the state was never saved properly.
Good luck!
Happens when the session in missing a needed variable.
might be caused by several things.
In my case I left the "www" out of the callback URL
You could actually be parsing the data from another domain... for example:
website.com is different from www .website.com
If you're parsing data from http ://website.com/login.php to http://www.website.com/fb-callback.php this would be a cross-domain problem and the error you are receiving would be because of that....
http ://website.com and http ://www.website.com are the same but the script identifies them as different..... hope that gives insight to the problem.

Joomla JError doesn't show but then appears

I have 3d party component which set JError warning
JError::raiseWarning( 99, "Set your name please" );
$app = JFactory::getApplication();
$app->redirect($r);
Redirect goes to controller with code
function saveUserDetails(){
//some code here
//now I try to get that error which was set by raiseWarning
$other_errors = JError::getErrors();
print_r($other_errors);
die;
It returns just empty array. Why It doesn't contain that error?
Ok, I try to check session var with Joomla messages
$session =& JFactory::getSession();
$mes = $session->get('application.queue');
print_r($mes);
die;
Again empty. Where is that error, I can't understand.
If there is new request immediately after the redirect you might be loosing the session variable (JError content) inspect the fired requests with FireBug, Net tab, and see what happens there. Post any information you get there but if it's not in JErrors it shouldn't show on the site.
Can you give a link to the live site so I can test there and see the HTTP requests that could help.

redirect forms with url values in zend

I have a page of the format www.test.com/policy-info/
which has a form that takes you to another page www.test.com/payment-info.
Now I am redirecting the page from www.test.com/payment-info to www.test.com/policy-info based on the some values obtained from the form. How do I redirect with certain values in the url.
the filename is policy-info.phtml.
Is this the only way to redirect?
$this->redirect(www.test.com/policy-info/index.phhtml&count=2);
You can use this:
$this->_helper->redirector('action', 'controller', 'module', array('param1'=>'value1', 'param2'=>'value2'));
in your case:
$this->_helper->redirector('index', 'policy-info', 'default',array('param1'=>'value1', 'param2'=>'value2'));
I always use $this->_redirect(...) and that works fine:
$this->_redirect('/module/controller/action/param1/value1/param2/value2');
This may be a case where _forward() may be the best choice.
_forward($action, $controller = null, $module = null, array $params = null): perform another action. If called in preDispatch(), the
currently requested action will be skipped in favor of the new one.
Otherwise, after the current action is processed, the action requested
in _forward() will be executed.
also It looks like you may be using named/defined routes, if that is true gotoRoute maybe useful as well Redirector Helper:
$this->_helper->getHelper('Redirector')->gotoRoute(array('param'=>'value'), 'routeName');

zend framework urls and get method

I am developing a website using zend framework.
i have a search form with get method. when the user clicks submit button the query string appears in the url after ? mark. but i want it to be zend like url.
is it possible?
As well as the JS approach you can do a redirect back to the preferred URL you want. I.e. let the form submit via GET, then redirect to the ZF routing style.
This is, however, overkill unless you have a really good reason to want to create neat URLs for your search queries. Generally speaking a search form should send a GET query that can be bookmarked. And there's nothing wrong with ?param=val style parameters in a URL :-)
ZF URLs are a little odd in that they force URL parameters to be part of the main URL. I.e. domain.com/controller/action/param/val/param2/val rather than domain.com/controller/action?param=val&param2=val
This isn't always what you want, but seems to be the way frameworks are going with URL parameters
There is no obvious solution. The form generated by zf will be a standard html one. When submitted from the browser using GET it will result in a request like
/action/specified/in/form?var1=val1&var2=var2
Only solution to get a "zendlike url" (one with / instead of ? or &), would be to hack the form submission using javascript. For example you can listen for onSubmit, abort the submission and instead redirect browser to a translated url. I personally don't believe this solution is worth the added complexity, but it should perform what you're looking for.
After raging against this for a day-and-a-half, and doing my best to figure out the right way to do this fairly simple this, I gave up and did the following. I still can't believe there's not a better way.
The use case that necessitates this is a simple record listing, with a form up top for adding some filters (via GET), maybe some column sorting, and Zend_Paginate thrown in for good measure. I ran into issues using the Url view helper in my pagination partial, but I suspect with even just sorting and a filter-form, Zend_View_Helper_Url would still fall down.
But I digress. My solution was to add a method to my base controller class that merges any raw query-string parameters with the existing zend-style slashy-params, and redirects (but only if necessary). The method can be called in any action that doesn't have to handle POSTs.
Hopefully someone will find this useful. Or even better, find a better way:
/**
* Translate standard URL parameters (?foo=bar&baz=bork) to zend-style
* param (foo/bar/baz/bork). Query-string style
* values override existing route-params.
*/
public function mergeQueryString(){
if ($this->getRequest()->isPost()){
throw new Exception("mergeQueryString only works on GET requests.");
}
$q = $this->getRequest()->getQuery();
$p = $this->getRequest()->getParams();
if (empty($q)) {
//there's nothing to do.
return;
}
$action = $p['action'];
$controller = $p['controller'];
$module = $p['module'];
unset($p['action'],$p['controller'],$p['module']);
$params = array_merge($p,$q);
$this->_helper->getHelper('Redirector')
->setCode(301)
->gotoSimple(
$action,
$controller,
$module,
$params);
}