Session error when using nette/forms in other app

Notice: This thread is very old.
mikeb
Member | 33
+
0
-

Hello
I'm brand new to nette and at this stage just using the nette/forms (instaled via composer) in a legacy app which does a session start before the page with the nette form is called. i get the following error:

Deprecated: Missing annotation @property for Nette\Http\Session::$started used in *****\vendor\nette\http\src\Http\Session.php:410 in ****\vendor\nette\utils\src\Utils\SmartObject.php on line 116

Fatal error: Exception in Nette\Forms\Form::__toString(): Unable to set 'session.use_only_cookies' to value '1' when session has been started by session.auto_start or session_start(). in *****\vendor\nette\http\src\Http\Session.php:410 in ****\vendor\nette\forms\src\Forms\Form.php on line 655

i had to silence tracy to see the error as tracy just said server error and it wasn't an error in my php logs. my guess is there's a clash in how sessions are handled. If i eliminate all traces of the other app my nette/forms code runs fine, which at this stage is just the bootstrap3-rendering.php examples recycled from here.

its on an xampp server with php 5.6.8. can anyone suggest a solution? is it around session management? is it a matter of starting nette http before anything else? if so, how?

thanks
Mike

Last edited by mikeb (2016-09-21 12:46)

CZechBoY
Member | 3608
+
0
-

Can you remove your manual session_start()? Nette automatically starts the session.

mikeb
Member | 33
+
0
-

I can't really remove the other apps session start tho i could start nette first and then the other app would use the current session.
i did try adding use nette/forms before the other app's startup but no luck. can you suggest how i can start nette without using it?

thanks

mikeb
Member | 33
+
0
-

further… it appears the sessions exceptions are not encountered until the form is echoed via the Forms\Form.php __toString() magic method which manages the rendering.
So even when i start Nette before the other legacy app, I can't work around Nette's requirement for starting a session…
maybe override the __toString() method? tho that sounds very hacky.
or is it that Nette forms just won't play well with other frameworks or apps that also require session?

all comments appreciated
Mike

mikeb
Member | 33
+
0
-

OK one more comment. the form I am playing with adds CSRF protection:

//$form->addProtection('Security token has expired, please submit the form again');

if I comment out this line then the session error no longer appears. I assume this feature changes the rendering process and bumps into the session clash.
I don't understand Nette well enough to know if this is intentional (i guess session holds the CSRF token?) but it does look like a show stopper.

???

CZechBoY
Member | 3608
+
0
-

Yep, csrf token isstored in session. Try setup nette session with autoStart: True.

tpr
Member | 55
+
0
-

FYI I also have this session issue when using the standalone Forms and addProtection(). Haven't found a way to get rid of it.

Last edited by tpr (2016-09-22 09:21)

mikeb
Member | 33
+
0
-

ok thanks. i don't see a config.neon in standalone forms module. can you guide me on where i'd set autoStart: True

cheers

mikeb
Member | 33
+
0
-

in \vendor\nette\http\src\Bridges\HttpDI\SessionExtension.php
i changed

$defaults = ['autoStart' => 'true',...

and even when I

use Nette\Forms\Form;
$form = new Form;

as the first functions of the legacy app it still throws the exception when the form is echoed (rendered).

??? all ideas welcome!

Last edited by mikeb (2016-09-22 10:14)

mikeb
Member | 33
+
0
-

ok i think I have a work-around/result using the forms module alone with a legacy app that also sets session. that is, generate and add a token as a hidden required element and add a custom validator to that:

1. make a token (I'm happy with one token per sesssion as session is destroyed with login/logout)

if(!isset($_SESSION['mb_token'])){
	if(!isset($_SESSION)){
		session_start();
	}
	$_SESSION['mb_token'] = md5(uniqid(rand(), TRUE)); // MB: add a token for the posts, ajax
}

2. then make a custom validator:

class MyValidators
{
	static function checkToken($item){

		if(!isset($_SESSION['mb_token'])){
			return FALSE;
		}
        if($item->value==$_SESSION['mb_token']) return true;
		return false;

    }
}

3. then add a hidden input to the form:

$form->addHidden('mb_token', $_SESSION['mb_token'])
    ->setRequired(true)
	->addRule('MyValidators::checkToken', 'Your page has timed-out - please reload the page and try again');

I'm sure there is a more elegant and nette-friendly solution but this appears to work. and I can now use nette forms with my project and have some CSRF protection!
(it would be nice it future versions of nette didn't have such insistent requirements for session so they could play nicely with other apps, assuming security isn't compromized)

HTH

Mike

Last edited by mikeb (2016-09-23 02:30)

CZechBoY
Member | 3608
+
0
-

Now I tested it myself. So when I faked Session::$started to TRUE, then no error is thrown and it works.
Problem is that you need to fork whole library and change 1 varaible.

Last edited by CZechBoY (2016-09-23 08:21)

mikeb
Member | 33
+
0
-

CzechBoy – where did you change Session::$started to TRUE?
as above, SessionExtension defaults didn't work for me

CZechBoY
Member | 3608
+
+1
-

in Nette\Http\Session class… there is

private static $started = FALSE;
mikeb
Member | 33
+
0
-

that works! with private static $started = true; i can use $form->addProtection(... even with my other app!.
Now, yes forking the whole project is a problem, pity i can't see any other way to change this… ??

CZechBoY
Member | 3608
+
0
-

Fork only the Nette/Http library and then change only that one line.