Session Management (Zend Framework specific) - zend-framework

I'm trying to get the rememberMe() function to remember users and retain sessions for months at a time.
I've read that if you pass a value through rememberMe() it will not work if the session has already been started. From the session_set_cookie_params() documentation in the PHP manual, "you need to call session_set_cookie_params() for every request and before session_start() is called."
By I am calling Zend_session::start() in my bootstrap as i thought I was supposed to. My problem is that rememberMe() doesn't seem to be working.
When I call session_get_cookie_params(); I get:
Array([lifetime] => 0 [path] => / [domain] => [secure] => httponly] =>)
Any thoughts?

I've solved the problem. sessions were being erased by another website on the same server which expires sessions every 24 minutes. To fix this I set the session.save_path to a new folder. I also set session.gc_maxlifetime and session.cookie_lifetime to be very large numbers.
problem solved!

Don't use the start() method. It should work fine if you are using MVC. The session_start must be called before any output is send and that's right before sending response (because of outputbuffering). The session is started automatically upon first Zend_Session_namespace usage.

Related

Play ws scala server hangs up on request after 120seconds - which options to use?

I am pretty sure that this is a config problem, so I'll post my code and the relevant application.conf options of my play app.
I have a play server that needs to interact with another server "B" (basically multi-file upload to B). The interaction happens inside an async -Action which should result in an OK with B's response on the upload. This is the reduced code:
def authenticateAndUpload( url: String) = Action.async( parse.multipartFormData) { implicit request =>
val form = authForm.bindFromRequest.get
val (user, pass) = (form.user, form.pass)
//the whole following interaction with the other server happens in a future, i.e. login returns a Future[Option[WSCookie]] which is then used
login(user, pass, url).flatMap {
case Some(cookie) => //use the cookie to upload the files and collect the result, i.e. server responses
//this may take a few minutes and happens in yet another future, which eventually produces the result
result.map(cc => Ok(s"The server under url $url responded with $cc"))
case None =>
Future.successful(Forbidden(s"Unable to log into $url, please go back and try again with other credentials."))
}
}
I am pretty sure that the code itself works since I can see my server log which nicely prints B's responses every few seconds and proceeds until everything is correctly uploaded. The only problem is that the browser hangs up with a server overloaded message after 120s which should be a play default value - but for which config parameter?
I tried to get rid of it by setting every play.server.http. timeout option I could get my hands on and even decided to use play.ws, specific akka, and other options of which I am quite sure that they are not necessary... however the problem remains, here is my current application.config part:
ws.timeout.idle="3600s"
ws.timeout.request ="3600s"
ws.timeout.response="3600s"
play.ws.timeout.idle="3600s"
play.ws.timeout.request="3600s"
play.ws.timeout.response="3600s"
play.server.http.connectionTimeout="3600s"
play.server.http.idleTimeout="3600s"
play.server.http.requestTimeout="3600s"
play.server.http.responseTimeout="3600s"
play.server.http.keepAlive="true"
akka.http.host-connection-pool.idle-timeout="3600s"
akka.http.host-connection-pool.client.idle-timeout= "3600s"
The browser hang up happened both on Safari and Chrome, where Chrome additionally started a second communication with B after about 120 seconds - also both of these communications succeeded and produced the expected logs, only the browsers had both hang up.
I am using Scala 2.12.2 with play 2.6.2 in an SBT environment, the server is under development, pre-compiled but then started via run - I read that it may not pick up the application.conf options - but it did on some file size customizing. Can someone tell me the correct config options or my mistake on the run process?

PHPUnit and Zend Framework assertRedirectTo() issue

I'm having an issue with assertRedirectTo() in a test I have created, below is the code I have used:
public function testLoggedInIndexAction() {
$this->dispatch('/');
$this->assertController('index');
$this->resetResponse();
$this->request->setPost(array(
'type' => 'login',
'username' => 'root',
'password' => 'asdasd',
));
$this->request->setMethod('POST');
$this->dispatch('/');
$this->assertRedirectTo('/feed/');
}
You log in through / (index.php/) and submit post details there and the it redirects you to /feed/ (index.php/feed/). The details I have supplied are correct and should work however I am having issues whereby PHPUnit is saying they are incorrect:
There was 1 failure:
1) IndexControllerTest::testLoggedInIndexAction
Failed asserting response redirects to "/feed/"
/home/public_html/mashhr/library/Zend/Test/PHPUnit/Constraint/Redirect.php:190
/home/public_html/mashhr/library/Zend/Test/PHPUnit/ControllerTestCase.php:701
/home/public_html/mashhr/tests/application/controllers/UserControllerTest.php:36
#poelinca: No, it is simply a case of Zend_Test being unreliable in registering a redirect (even if it has been called correctly!)
In his case, the real app is no doubt redirecting the user properly, but the Zend_Test environment is having trouble registering properly called redirects. The best response I can think of is to omit any failing assertRedirect which actually works in the application.
This is not an optimal situation, but unless you're prepared to dig into the Zend code to see where the problem is, this may be your best bet for efficiency. This is an example of what causes unit testing to get a bad name: Having to alter code to pass tests which actually work already.
See http://framework.zend.com/issues/browse/ZF-7496 Which is misleadingly specific in its title: the problem relates to all redirects, especially those which must set headers and exit instead of dispatching the original controller.
For whatever reason, this behavior causes Redirects not to always fail, but to be highly unreliable instead! If anyone knows a better workaround to this problem (which is general, and probably unrelated to the OP's code) please let us know.
stumbled on this question while having the same problem. I ended up doing the following:
$this->assertRedirect();
$responseHeaders = $this->response->getHeaders();
$this->assertTrue(count($responseHeaders) != 0);
$this->assertArrayHasKey('value', $responseHeaders[0]);
// in my case I'm redirecting to another module
$this->assertEquals('/module/controller/action', $responseHeaders[0]['value']);
I've responded this answer in http://zend-framework-community.634137.n4.nabble.com/Zend-Test-failing-on-AssertRedirectTo-td3325845.html#a4451217
I'm having this same issue... A possible way to assert it could be in
PHPUnit and Zend Framework assertRedirectTo() issue
But the problem is there.. My example is (wich actually works if done manually):
// controller modules/picking/orders/product
$orderId = $this->_getParam('oId');
if (empty($orderId)) {
return $this->_redirect('picking/orders/browse/invalid/empty');
}
// test
$this->dispatch('picking/orders/product');
$this->assertRedirect(); // ok
$this->assertRedirectTo('picking/orders/browse'); // error
$this->assertRedirectTo('picking/orders/browse/invalid/empty'); // error
After I've found the error!
Actually, following the example above i've found that the string comparizon in my example has an error:
'.../public//picking/orders/browse/invalid/empty'
'.../public/picking/orders/browse/invalid/empty'
... fixing the preprended slash solve the problem! ;)
So if i understand right , you wrote a test that fails ( id say this is perfect ) .
In order to make the test pass you need to debug you're app and see where the problem is , in this case you need to have a look at the actual redirection ( or eaven the post fields sent by the form ) , maybe check the routing too . I gues nobody here will be able to answer you're question unless you post the code in you're index controller/form/view and feed controller .
For future reference, I had this issue today and it was caused by the Url class failing to build a valid url (I was passing the wrong parameters) but not reporting an error to PHPUnit (probably because PHPUnit masks the error).
Correcting the url parameters fixes the url and with it the assertion.

How to use Zend_Form_Element_Hash?

Then I'm trying to use Zend_Form_Element_Hash it regenerates a hash every request.
In my code:
// form
$this->addElement('hash', 'hihacker', array('salt' => 'thesal'));
Then I dumping $_SESSION I see a new value each page reload.
Then I send a form it reports an error "The token '28a5e0e2a50a3d4afaa654468fd29420' does not match the given token 'a64407cc11376dac1916d2101de90d29'", each time - new pair of tokens
$form = new Form();
$form->addElement('hash', 'hihacker',
array('salt' => 'YOUR TOO MUCH SALTY TEXT !!##'));
if ($this->_request->isPost() && $form->isValid($this->_request->getPost())) {
// Valid ! you are safe do what ever you want .
} else if (count($form->getErrors('request_token')) > 0) {
///get him to the error controller
$this->_forward('csrf-forbidden', 'error');
return;
}
its working very well for me but double check your session setting
"
Internally, the element stores a unique identifier using Zend_Session_Namespace, and checks for it at submission (checking that the TTL has not expired). The 'Identical' validator is then used to ensure the submitted hash matches the stored hash.
The 'formHidden' view helper is used to render the element in the form.
"
form ZF docs
Zend_Form_Element_Hash is supposed to regenerate every request. What you're describing is your tokens going out of synch. This generally happens with multiple forms or with redirects/forwards.
If you're using ajax somewhere on the page you can put this in the controller action (near the end)
$form->hash->initCsrfToken();
$this->view->hash = $form->hash->getValue();
Then when you do the ajax call, just pull the token and replace the token on the form using a selector and .replaceWith(). This is how you deal with multiple forms as well
Otherwise you're probably either redirecting something or loading something twice and you should change the hop in the Zend library. The hop is how many times a token can be requested before it expires
Check that there is not a hidden redirect or forward somewhere in your script... the hash has a hop count of 1 so any redirect will make it expire.
FWIW i think there was a subtle bug in the hash a few versions of ZF ago. I got stuck on exactly the same problem, and hacked the code to make the hop count = 2. When I upgraded ZF this problem went away.

facebook connect api "Cannot use string offset as an array in" error

Please help! I have been grappling with this error for days and I cannot for the life of me figure it out. I am using facebook connect and fetching a "contact_email" attribute using their api method users_getInfo.
The issue is that when I execute this PHP file, i get this error: "Cannot use string offset as an array in...". This error specifically refers to this line of code: $firstName=$user_details[0]['contact_email'];
I'm thinking this is because the user_getInfo method is not returning any results... However, the most ridiculous part about all this is that, I can execute the code below several dozens of times in a row SUCCESSFULLY without the above error, BUT THEN randomly without changing ANY code at all, I will suddenly encounter this error, in which case it will begin to give me an error several dozens of times, and then AGAIN without any code change, start executing successfully again.
This odd behavior occurs regardless of the attribute i am fetching.. (contact_email, first_name, last_name, etc.). I am running php 5.2.11. Is there something I'm missing??
Please Help!
include_once 'site/fbconnect/config.php'; //has $api_key and $secret defined.
include_once 'site/facebook-platform/client/facebook.php';
global $api_key,$secret;
$fb=new Facebook($api_key,$secret);
$fb->require_login();
$fb_user=$fb->get_loggedin_user();
$user_details=$fb->api_client->users_getInfo($fb_user,array('last_name','first_name','contact_email'));
$email=$user_details[0]['contact_email'];
$firstName=$user_details[0]['first_name'];
$lastName=$user_details[0]['last_name'];
Using the facebook php client API I was also receiving that error but my error was related to checking if the users are friends using the friends_areFriends php method.
//$results_array = $facebook->api_client->friends_areFriends($fb_user, $selected_friend_uid);
//$answer = $results_array[0]['are_friends'];
I would get this error when I assigned the $result, "Cannot use string offset as an array" and aparently the friends_areFriends method above was failing alot. My solution was to create a for loop that ran that code and then check $answer to see if it was an array using php method is_array() and executing the method call again if it wasn't. My loop was for 10 tries before just letting it fail. In the end, this check was severely degrating the performance of my facebook application. Instead, I removed the friends_areFriends api call alltogather and my facebook app performance was nice and fast again.
You could probably implement a similar feature allowing the method to retry itself if the result is not an array. The problem I think is on facebook's side, sometimes they are flooded and the requests do not complete successfully. I caution you not to retry more than 5 tries though because if you do a forever loop, rest assured they will ban you from the using the Facebook API for flooding it, so be careful.

How do I use and debug WWW::Mechanize?

I am very new to Perl and i am learning on the fly while i try to automate some projects for work. So far its has been a lot of fun.
I am working on generating a report for a customer. I can get this report from a web page i can access.
First i will need to fill a form with my user name, password and choose a server from a drop down list, and log in.
Second i need to click a link for the report section.
Third a need to fill a form to create the report.
Here is what i wrote so far:
my $mech = WWW::Mechanize->new();
my $url = 'http://X.X.X.X/Console/login/login.aspx';
$mech->get( $url );
$mech->submit_form(
form_number => 1,
fields =>{
'ctl00$ctl00$cphVeriCentre$cphLogin$txtUser' => 'someone',
'ctl00$ctl00$cphVeriCentre$cphLogin$txtPW' => '12345',
'ctl00$ctl00$cphVeriCentre$cphLogin$ddlServers' => 'Live',
button => 'Sign-In'
},
);
die unless ($mech->success);
$mech->dump_forms();
I dont understand why, but, after this i look at the what dump outputs and i see the code for the first login page, while i belive i should have reached the next page after my successful login.
Could there be something with a cookie that can effect me and the login attempt?
Anythings else i am doing wrong?
Appreciate you help,
Yaniv
This is several months after the fact, but I resolved the same issue based on a similar questions I asked. See Is it possible to automate postback from the client side? for more info.
I used Python's Mechanize instead or Perl, but the same principle applies.
Summarizing my earlier response:
ASP.NET pages need a hidden parameter called __EVENTTARGET in the form, which won't exist when you use mechanize normally.
When visited by a normal user, there is a __doPostBack('foo') function on these pages that gives the relevant value to __EVENTTARGET via a javascript onclick event on each of the links, but since mechanize doesn't use javascript you'll need to set these values yourself.
The python solution is below, but it shouldn't be too tough to adapt it to perl.
def add_event_target(form, target):
#Creates a new __EVENTTARGET control and adds the value specified
#.NET doesn't generate this in mechanize for some reason -- suspect maybe is
#normally generated by javascript or some useragent thing?
form.new_control('hidden','__EVENTTARGET',attrs = dict(name='__EVENTTARGET'))
form.set_all_readonly(False)
form["__EVENTTARGET"] = target
You can only mechanize stuff that you know. Before you write any more code, I suggest you use a tool like Firebug and inspect what is happening in your browser when you do this manually.
Of course there might be cookies that are used. Or maybe your forgot a hidden form parameter? Only you can tell.
EDIT:
WWW::Mechanize should take care of cookies without any further intervention.
You should always check whether the methods you called were successful. Does the first get() work?
It might be useful to take a look at the server logs to see what is actually requested and what HTTP status code is sent as a response.
If you are on Windows, use Fiddler to see what data is being sent when you perform this process manually, and then use Fiddler to compare it to the data captured when performed by your script.
In my experience, a web debugging proxy like Fiddler is more useful than Firebug when inspecting form posts.
I have found it very helpful to use Wireshark utility when writing web automation with WWW::Mechanize. It will help you in few ways:
Enable you realize whether your HTTP request was successful or not.
See the reason of failure on HTTP level.
Trace the exact data which you pass to the server and see what you receive back.
Just set an HTTP filter for the network traffic and start your Perl script.
The very short gist of aspx pages it that they hold all of the local session information within a couple of variables prefixed by "__" in the general aspxform. Usually this is a top level form and all form elements will be part of it, but I guess that can vary by implementation.
For the particular implementation I was dealing with I needed to worry about 2 of these state variables, specifically:
__VIEWSTATE
__EVENTVALIDATION.
Your goal is to make sure that these variables are submitted into the form you are submitting, since they might be part of that main form aspxform that I mentioned above, and you are probably submitting a different form than that.
When a browser loads up an aspx page a piece of javascript passes this session information along within the asp server/client interaction, but of course we don't have that luxury with perl mechanize, so you will need to manually post these yourself by adding the elements to the current form using mechanize.
In the case that I just solved I basically did this:
my $browser = WWW::Mechanize->new( );
# fetch the login page to get the initial session variables
my $login_page = 'http://www.example.com/login.aspx';
$response = $browser->get( $login_page);
# very short way to find the fields so you can add them to your post
$viewstate = ($browser->find_all_inputs( type => 'hidden', name => '__VIEWSTATE' ))[0]->value;
$validation = ($browser->find_all_inputs( type => 'hidden', name => '__EVENTVALIDATION' ))[0]->value;
# post back the formdata you need along with the session variables
$browser->post( $login_page, [ username => 'user', password => 'password, __VIEWSTATE => $viewstate, __EVENTVALIDATION => $validation ]);
# finally get back the content and make sure it looks right
print $response->content();