开发者

Local variable overwrite session variable in PHP

Hi I'm having some problem with a PHP page: I'm writing a little CMS using this tutorial. I manage to write a class I use to interact with menus and all is working well: I can insert, delete and get all items of the menu in a page where I can reorder them. When I started to write the same page for users, I encountered an issue: I'm using a Sentry class to validate users in each page:

require_once('../includes/Sentry.php');  
$theSentry = new Sentry();  
if (!$theSentry->checkLogin(1) ){ header("Location: index.php"); die(); }

Now: if I use this validation alone, the page is working well, but I need to query the database and extract all the user in the user_admin.php page:

require_once('../includes/DbUser.php');
$user_connector = new DbUser();
$all_users = array();
$all_users = $user_connector->getUserArray();
foreach($all_users as $id => $user){ echo " ... " };

If I comment one of the two section, all is working well, but if I leave this code running together, the page is correctly created, but next time I run a page using the Sentry class, I'm redirected to login page with an error. The Sentry class use a Validator class to check credentials, and a method in this class is reporting an array input instead of a single value input.

My question is: how can be possible that two different objects created from two different classes, can interact generating such a problem? I think you need the code of the two method:

class Sentry {

...

function checkLogin($group=9,$user='',$pass='',$goodRedirect='',$badRedirect='') {
        // Include database and validation classes, and create objects
        require_once('DbConnector.php');
        require_once('Validator.php');
        $validate = new Validator();
        $loginConnector = new DbConnector();

        // If user is already logged in then check credentials
        if ($_SESSION['user'] && $_SESSION['pass']){

            // Validate session data
            if (!$validate->validateTextOnly($_SESSION['user'])){return false;}
            if (!$validate->validateTextOnly($_SESSION['pass'])){return false;}

            if ($_SESSION['gruppo'] <= $group){
                // Existing user ok, continue
                if ($goodRedirect != '') { 
                    header("Location: ".$goodRedirect) ;
                }           
                return true;
            }else{
                // Existing user not ok, logout
                //$this->logout();
                header("Location: low_perm.php");
                die;
                //return false;
            }

        // User isn't logged in, check credentials
        }else{  
            // Validate input
            if (!$validate->validateTextOnly($user)){return false;}
            if (!$validate->validateTextOnly($pass)){return false;}

            // Look up user in DB
            $getUser = $loginConnector->query("SELECT * FROM `utenti` WHERE `usr` = '".$user."' AND `psw` = PASSWORD('".$pass."') AND `gruppo` <= ".$group." AND `attivo` = 1");
            $this->userdata = $loginConnector->fetchArray($getUser);

            if ($loginConnector->getNumRows($getUser) > 0){
                // Login OK, store session details
                // Log in
                $_SESSION["user"] = $user;
                $_SESSION["pass"] = $this->userdata['pass'];
                $_SESSION["gruppo"] = $this->userdata['gruppo'];

                if ($goodRedirect) { 
                    header("Location: ".$goodRedirect);
                }
                return true;

            }else{
                // Login BAD
                unset($this->userdata);
                if ($badRedirect) { 
                    header("Location: ".$badRedirect) ;
                }       
                return false;
            }
        }           
    }
}

And this is the function to get the users:

class DbUser extends DbConnector{

...

    function getUserArray() {
        while ($row = mysql_fetch_object($this->user_result)) {
            $this->users[$row->id] = $row;
        }
        return $this->users;    
    }
}

I know it's a difficult-to-explain question, so let me know if I need to specify something else... Thanks

EDIT: The error is in Validator class and in this function (the line with preg_match() ):

function validateTextOnly($theinput,$description = ''){
    $result = preg_match ("/^[A-Za-z0-9\ ]+$/", $theinput );
    if ($result AND $theinput!=''){
        return true;
    }else{
        $this->errors[] = $description;
        return false; 
    }
}

GREAT NEWS: I found where the error was, but I'm not able to understand why this code doesn't work:

$user_connector = new DbUser();
$all_users = array();
$all_users = $user_connector->getUsers();
foreach($all_users as $id => $user){ ... }

The foreach statement is the point: when I'm using $all_user as $id=>$user, it actually overwrite the content of $_SESSION['user'] with the last object used in the cycle (an "user" object). Anyone can explain me how a l开发者_如何学运维ocal variable can overwrite a session one? I would like to make it clear: I solve the problem (changing $id => $user with $id => $userObj), but I'm looking for an explanation. Thanks!


I had the exact same problem as you, and in my case it was because PHP's register globals was turned on.

Register globals is a php configuration setting that creates a local variable for each variable that is set in $_SESSION. This means that when you set $_SESSION['user'], a local variable $user will also be created for you. If you overwrite this variable in you code, as you reported, the new value will also be set in $_SESSION. For more info on register globals, look here.

To turn this setting off, you must edit the php.ini file which is loaded for the web-server you are using, and set the register_globals setting to Off, and then restart your web-server. Remember that if you plan to run this code on any other web-server, this setting will also have to be turned off for your code to function properly.


If you are creating a framework, I recomend you to use an Autoload. On index controller, you can specify a function to call when a class is not found. Example.

You use: require_once('../includes/DbUser.php'); $user_connector = new DbUser();

If you write that, first of all you must always controll if file is included once. This spends some time in php process. The way is NEVER write "require" or "include" and let php to "not find" the class he is looking for. Then you must controll that class Dbuser is inside Dbuser.php file, with same name. Finally insert an autoload where only can be fired once ( like index.php on root ). You must do it like that:

function classAutoload($className){
    if (!class_exists($className, false)){
        @include_once(dirname(__FILE__).'/includes/'.$className.'.php');
}
spl_autoload_register('classAutoload');

PHP will manage if class is included, and if not, it will load before get an instance. No more includes and requires, just get classes. You can add as many autoloads as you need, always being sure you only instance this piece of code once.

You also should use "&&" instead of "AND" of php. AND is just an alias and, as double quote, php must find internaly what is exactly this character. Efficiency is important on a framework, remember you will use it on every web call...

I hope you to help with your framework.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜