php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #79076 Unexpected Result when
Submitted: 2020-01-08 02:22 UTC Modified: 2020-01-19 05:54 UTC
From: ptmp727 at gmail dot com Assigned:
Status: Not a bug Package: Session related
PHP Version: 7.3.13 OS: macOS
Private report: No CVE-ID: None
 [2020-01-08 02:22 UTC] ptmp727 at gmail dot com
Description:
------------
This is the first time I am doing this. I am completing a project for University so I am not very experienced so please accept my apologies if I do not follow the proper protocol. Happy to provide any other information.

Basically I am creating a module based MVC style framework with will also work as a single page app and I have finally managed to get everything to work.

I am using DOMDocument for templating and it is RUNNING UNEXPECTED CODE and causing the script to produce bizarre results by deleting session variables at runtime.

The app logic is very symmetric and follows the basic structure and pseudocode:

app init,
validate request,
auth form function: All request methods except for 'GET' must have a token and a form id field set in the session and must match.

If the request is get and if the session tokens are set, delete the tokens (Ensures tokens are refreshed on every request), *** This is the point of the bug ***

If Valid,
Request object uses the router to dispatch the request to a module class and a method responses.

Now In this example we are using the /login route which has a form component login, 

Here is what is happening:

1) Initial request comes in for /login,
2) Request URL Is sanitized and Validated,
3) Auth::form() function is called:
Check if Request method is NOT 'GET',
If true validate the form,
ElseIf Session Tokens are set, delete them (Ensuring that tokens can be regenerated on a new request)

works normally as the method is get and no tokens are set yet, the function does not throw any errors (as expected)
4) Request is routed to the AuthModule and the login method

5) Login method uses a function to generate random token and save it in the session and returns the login component,

6) Token is added to hidden form field

7) I use DOMDocument object to get the main template and append the login component to the root element by cloning the node.

8) Whole response sent to browser.

//So far works as expected,

Now!

9) On Form submission,

An exception is thrown stating that the form token has not been set in the session,

Even though I have verified that the session variable is valid and set before the app terminates.
The request lifecycle of sending the form component works perfectly and all session variables are set (checked by testing the session super global in the app destructor method), but somehow on the next request when the form is submitted, the form tokens are disappearing from the session.

Some How point 3 else if condition even though evaluates to false, the unset($_SESSION['tokens']) line of code SOMEHOW RUNS, I CANT UNDERSTAND FOR THE LIFE OF ME.

If I uncomment the line of code which unsets the session, EVERYTHING WORKS FINE

Also If I do not use the Dom document for templating and simply send the component back there is no error.

Code samples:

//Checking the session variables at the start of the script
//Undefined variable notice
var_dump($_SESSION['tokens']);

//Foundation function calls the Auth::form function which checks the tokens:
$app->foundation(function ($request, $response){
    $response->capture(
	$request->route()
    );
});

//Auth class has a form function
public static function form(){
    if($_SERVER['REQUEST_METHOD'] != 'GET'){
        //Code to validate and check tokens here!
    }elseif(asset($_SESSION['tokens'])){
        //This line of code somehow runs even though the else if condition fails,
        //This problem only happens when I am using DOM Document for templating
        unset($_SESSION['tokens']);
    }
}

//AuthModule class:
class AuthModule extends Module{
     public function login(){
        $token = Form::token('login'); //Creates session tokens
        return $this->component('login.php', ['token' => $token]);
     }
}

//Testing code in index.php at the end of the main app object destructor method which shows session:

class App{
   function __destruct(){
      var_dump($_SESSION['tokens']);//Shows session variables perfectly!
   }
}

//At the start of the script:
//Checking the session variables at the start of the script
//Undefined variable notice
var_dump($_SESSION['tokens']);

Just to reiterate this problem only happens when using DOMDocument templating, where I have to use:
libxml_use_internal_errors(true); and libxml_use_internal_errors(false); to suppress errors.

I am sorry I do have a GitHub account but I did not want to upload the project before it is ready, but for the purpose of testing I can upload to GitHub,
I am working on my localhost so Im not sure how I can share my app and project,
I do not have a URL yet,

If I uncomment the line of code in the Auth::form function which unsets the session, some how the session tokens are not deleted.
I cannot understand why this is happening, especially as the unset line of code has not even ran yet and the condition never evaluates to true as the tokens are somehow never set in the session at run-time for the next request after being set properly


PHP Version: 7.3.8,
ENV: Mac MAMP PRO


If anyone can provide an email, I am happy


Test script:
---------------

public function set_response()
{
    $html = new HTMLDom($this->response);
    $domelem = $html->body->firstChild;
    $cloned = $this->importNode($domelem, true);
    $this->app_root->appendChild($cloned);
    $this->save_html();
}

public function capture($response)
{
    if ($response === false) {
	$this->not_found();
    }elseif (is_string($response)) {
      $dom = new MapDom($response);
      $dom->set_response();
      $this->response = $dom->get_response();
      //When not using domdocument, it works perfectly:
      //$this->response = $response; 
    }
}

Expected result:
----------------
The Session variables set in the previous request should be set at the top of the script before the Auth::form deletes them (If they are set and if the request method is get)

Actual result:
--------------
Session tokens are not defined at the top of the script.


Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2020-01-08 02:39 UTC] requinix@php.net
-Status: Open +Status: Feedback
 [2020-01-08 02:39 UTC] requinix@php.net
It's going to be rather difficult for us to give you more information here, let alone determine whether there is a bug with PHP, so I can give you a few comments to try one by one to see if any of them make a difference:

1. Make sure you have your error reporting settings appropriate for development and have checked for *any* kind of error or notice
2. I see an "asset" function you typed here. I assume that's actually "isset"? Or is it "assert"?
3. When you var_dumped the tokens, did you get an undefined *variable* or undefined *offset* warning? Former means the session wasn't started yet, latter means the tokens was not set.
4. Make sure that during your browsing you are not going between different domains (eg, example.com <-> www.example.com) which could cause you to lose session data.
5. Check your session cookie settings that they have the right domain name and path
6. Try disabling Xdebug, if enabled
7a. Try disabling opcache, if enabled
7b. If disabling opcache fixes the problem, enable and try with opcache.optimization_level=0

If all else fails, you should indeed upload the code somewhere like GitHub and reach out to a PHP support forum or the general mailing list to get more eyes on it. https://www.php.net/mailing-lists.php Since this is just a bug tracker, we're not usually able to spend a lot of time going through code looking for issues.
 [2020-01-19 04:22 UTC] php-bugs at lists dot php dot net
No feedback was provided. The bug is being suspended because
we assume that you are no longer experiencing the problem.
If this is not the case and you are able to provide the
information that was requested earlier, please do so and
change the status of the bug back to "Re-Opened". Thank you.
 [2020-01-19 04:28 UTC] ptmp727 at gmail dot com
-Status: No Feedback +Status: Closed
 [2020-01-19 04:28 UTC] ptmp727 at gmail dot com
Hi, I am extremely sorry, It was my error.
I spent three days over this.
It was actually the HTML file.

I have apache reset to redirect everything to index.html, unless a valid file is found.
The Browsers were making a request for the favicon.ico file and that was redirecting to index.php, thus making an extra request,

Please accept my apologies, No error with PHP :)
 [2020-01-19 05:54 UTC] requinix@php.net
-Status: Closed +Status: Not a bug
 
PHP Copyright © 2001-2021 The PHP Group
All rights reserved.
Last updated: Sun Apr 18 05:01:24 2021 UTC