jQuery AJAX PHP OOP 登录后 SESSION 丢失

3

我有一个面向对象的PHP登录系统,使用jQuery AJAX成功登录用户,但在重定向到新的网页(或返回URL)时,$SESSION信息丢失。代码有什么问题?

编辑/更新:我发现当我分配、查看/回显$_SESSION变量时,这个问题会在任何页面上发生。有些地方不对。这是我的php.ini文件中关于SESSIONS的副本。

[Session]
; Handler used to store/retrieve data.
; http://php.net/session.save-handler
session.save_handler = files

; Argument passed to save_handler.  In the case of files, this is the path
; where data files are stored. Note: Windows users have to change this
; variable in order to use PHP's session functions.
;
; The path can be defined as:
;
;     session.save_path = "N;/path"
;
; where N is an integer.  Instead of storing all the session files in
; /path, what this will do is use subdirectories N-levels deep, and
; store the session data in those directories.  This is useful if you
; or your OS have problems with lots of files in one directory, and is
; a more efficient layout for servers that handle lots of sessions.
;
; NOTE 1: PHP will not create this directory structure automatically.
;         You can use the script in the ext/session dir for that purpose.
; NOTE 2: See the section on garbage collection below if you choose to
;         use subdirectories for session storage
;
; The file storage module creates files using mode 600 by default.
; You can change that by using
;
;     session.save_path = "N;MODE;/path"
;
; where MODE is the octal representation of the mode. Note that this
; does not overwrite the process's umask.
; http://php.net/session.save-path
session.save_path = "/var/php_sessions"

; Whether to use cookies.
; http://php.net/session.use-cookies
session.use_cookies = 1

; http://php.net/session.cookie-secure
;session.cookie_secure =

; This option forces PHP to fetch and use a cookie for storing and maintaining
; the session id. We encourage this operation as it's very helpful in combating
; session hijacking when not specifying and managing your own session id. It is
; not the end all be all of session hijacking defense, but it's a good start.
; http://php.net/session.use-only-cookies
session.use_only_cookies = 1

; Name of the session (used as cookie name).
; http://php.net/session.name
session.name = PHPSESSID

; Initialize session on request startup.
; http://php.net/session.auto-start
session.auto_start = 1

; Lifetime in seconds of cookie or, if 0, until browser is restarted.
; http://php.net/session.cookie-lifetime
session.cookie_lifetime = 0

; The path for which the cookie is valid.
; http://php.net/session.cookie-path
session.cookie_path = /

; The domain for which the cookie is valid.
; http://php.net/session.cookie-domain
session.cookie_domain =

; Whether or not to add the httpOnly flag to the cookie, which makes it inaccessible to browser scripting languages such as JavaScript.
; http://php.net/session.cookie-httponly
session.cookie_httponly =

; Handler used to serialize data.  php is the standard serializer of PHP.
; http://php.net/session.serialize-handler
session.serialize_handler = php

; Defines the probability that the 'garbage collection' process is started
; on every session initialization. The probability is calculated by using
; gc_probability/gc_divisor. Where session.gc_probability is the numerator
; and gc_divisor is the denominator in the equation. Setting this value to 1
; when the session.gc_divisor value is 100 will give you approximately a 1% chance
; the gc will run on any give request.
; Default Value: 1
; Development Value: 1
; Production Value: 1
; http://php.net/session.gc-probability
session.gc_probability = 1

; Defines the probability that the 'garbage collection' process is started on every
; session initialization. The probability is calculated by using the following equation:
; gc_probability/gc_divisor. Where session.gc_probability is the numerator and
; session.gc_divisor is the denominator in the equation. Setting this value to 1
; when the session.gc_divisor value is 100 will give you approximately a 1% chance
; the gc will run on any give request. Increasing this value to 1000 will give you
; a 0.1% chance the gc will run on any give request. For high volume production servers,
; this is a more efficient approach.
; Default Value: 100
; Development Value: 1000
; Production Value: 1000
; http://php.net/session.gc-divisor
session.gc_divisor = 1000

; After this number of seconds, stored data will be seen as 'garbage' and
; cleaned up by the garbage collection process.
; http://php.net/session.gc-maxlifetime
session.gc_maxlifetime = 1440

; NOTE: If you are using the subdirectory option for storing session files
;       (see session.save_path above), then garbage collection does *not*
;       happen automatically.  You will need to do your own garbage
;       collection through a shell script, cron entry, or some other method.
;       For example, the following script would is the equivalent of
;       setting session.gc_maxlifetime to 1440 (1440 seconds = 24 minutes):
;          find /path/to/sessions -cmin +24 | xargs rm

; PHP 4.2 and less have an undocumented feature/bug that allows you to
; to initialize a session variable in the global scope, even when register_globals
; is disabled.  PHP 4.3 and later will warn you, if this feature is used.
; You can disable the feature and the warning separately. At this time,
; the warning is only displayed, if bug_compat_42 is enabled. This feature
; introduces some serious security problems if not handled correctly. It's
; recommended that you do not use this feature on production servers. But you
; should enable this on development servers and enable the warning as well. If you
; do not enable the feature on development servers, you won't be warned when it's
; used and debugging errors caused by this can be difficult to track down.
; Default Value: On
; Development Value: On
; Production Value: Off
; http://php.net/session.bug-compat-42
session.bug_compat_42 = Off

; This setting controls whether or not you are warned by PHP when initializing a
; session value into the global space. session.bug_compat_42 must be enabled before
; these warnings can be issued by PHP. See the directive above for more information.
; Default Value: On
; Development Value: On
; Production Value: Off
; http://php.net/session.bug-compat-warn
session.bug_compat_warn = Off

; Check HTTP Referer to invalidate externally stored URLs containing ids.
; HTTP_REFERER has to contain this substring for the session to be
; considered as valid.
; http://php.net/session.referer-check
session.referer_check =

; How many bytes to read from the file.
; http://php.net/session.entropy-length
session.entropy_length = 0

; Specified here to create the session id.
; http://php.net/session.entropy-file
; On systems that don't have /dev/urandom /dev/arandom can be used
; On windows, setting the entropy_length setting will activate the 
; Windows random source (using the CryptoAPI)
session.entropy_file = /dev/urandom

; Set to {nocache,private,public,} to determine HTTP caching aspects
; or leave this empty to avoid sending anti-caching headers.
; http://php.net/session.cache-limiter
session.cache_limiter = nocache

; Document expires after n minutes.
; http://php.net/session.cache-expire
session.cache_expire = 180

; trans sid support is disabled by default.
; Use of trans sid may risk your users security.
; Use this option with caution.
; - User may send URL contains active session ID
;   to other person via. email/irc/etc.
; - URL that contains active session ID may be stored
;   in publicly accessible computer.
; - User may access your site with the same session ID
;   always using URL stored in browser's history or bookmarks.
; http://php.net/session.use-trans-sid
session.use_trans_sid = 1

; Select a hash function for use in generating session ids.
; Possible Values
;   0  (MD5 128 bits)
;   1  (SHA-1 160 bits)
; This option may also be set to the name of any hash function supported by
; the hash extension. A list of available hashes is returned by the hash_algos()
; function.
; http://php.net/session.hash-function
session.hash_function = 0

; Define how many bits are stored in each character when converting
; the binary hash data to something readable.
; Possible values:
;   4  (4 bits: 0-9, a-f)
;   5  (5 bits: 0-9, a-v)
;   6  (6 bits: 0-9, a-z, A-Z, "-", ",")
; Default Value: 4
; Development Value: 5
; Production Value: 5
; http://php.net/session.hash-bits-per-character
session.hash_bits_per_character = 4

; The URL rewriter will look for URLs in a defined set of HTML tags.
; form/fieldset are special; if you include them here, the rewriter will
; add a hidden <input> field with the info which is otherwise appended
; to URLs.  If you want XHTML conformity, remove the form entry.
; Note that all valid entries require a "=", even if no value follows.
; Default Value: "a=href,area=href,frame=src,form=,fieldset="
; Development Value: "a=href,area=href,frame=src,input=src,form=fakeentry"
; Production Value: "a=href,area=href,frame=src,input=src,form=fakeentry"
; http://php.net/url-rewriter.tags
url_rewriter.tags = "a=href,area=href,frame=src,input=src,form=,fieldset="

我有最初的登录页面login.php(其中包含jQuery AJAX)。

<?php

    session_start();
?>
<html>
    <head>
                <script type="text/javascript" src="http://static.fluxexchange.com/fluxexchange/js/jquery-1.8.3.min.js"></script>

    </head>
    <body>
        <form action="" id="login" class="network_login" onSubmit="return false;">
                                <h3>Sign in to share your cultures and interests with friends.</h3>
                                <div>
                                <label>Handle, Email, or Phone</label><input name="handle" id="login-handle" class="login_input">
                                </div>
                                <div>
                                <label>Passcode</label><input name="password" id="login-password" class="login_input" type="password">
                                </div>
                                <div>
                                <input class="auto-authenticate" type="checkbox" style="border:0px;"><label style="width:auto;">Keep me authenticated</label>
                                </div>
                                <?php
                                    $iredirect_url=$_GET['return_url'];
                                ?>
                                <input type="hidden" name="return_url" value="<?php echo $iredirect_url; ?>">

                                <label id="login_submit_button" class="login_button">
                                    <input class="login-button-blue" value="Authenticate" type="submit">
                                </label>
                                <div id="login-loader" class="loader"></div>
                                <span class="login-option" id="more-login-options">I'm looking for more login options.</span>
                            </form>
              $(function(){
    $("#login-loader").hide();
    $("#login-success-notification").hide();
    $("#login_submit_button").click(function(){
        $("#login-loader").fadeIn(1000);
        authenticateUser();
    });
});
function authenticateUser(){

    $.ajax({
        type:"POST",
        url:"engine/authenticate_user.php",
        cache:false,
        data: $("#login").serialize(),
        dataType:"json",
        async:false,
        success: function(resp){

            console.log(resp);

            $('.reg-error-notification').empty();
            $('.reg-error-notification').hide();


            if(resp.logged_in=="true"){
                $("#login-success-notification").append('<p>'+resp.session_test+'</p>').fadeIn(1000, function(){
                    window.location.href=resp.return_url;
                });

            } else {
                $("#login-loader").fadeOut(1000);
                $('#login-error-notification').append('<p>The handle you entered is incorrect. Please try again.</p>').fadeIn(1000);
            }
        },
    });
}
    </body>
</html>

还有index.php(当问题发生时重定向到登录页面)。

<?
    session_start();
        print_r($_SESSION['network_id']);   

?>

以及 authenticate_user.php

<?php
    session_start();
    require("login-classes.php");

    $Authenticate= new Authenticate($_POST['handle'], $_POST['password'], $_POST['network'], $_POST['fenetwork']);
    $Authenticate->authenticateUser();

    $result=array();
    if($Authenticate->isLoggedIn()){

        $result['logged_in']="true";
        $result['return_url']=($_POST['return_url']);
        $result['session_test']=$_SESSION['network_id'];
    } else {

        $result['logged_in']="false";
    }

    echo json_encode($result);
?>

login-classes.php(包含在authenticate_user.php中)

 <?php
        //(C) Flux Exchange Network, Inc.
        require ("database-classes.php");

        class Authenticate {

            public function __construct($username, $password, $network_site, $parent_network) {

                $this->handle=$username;
                $this->password=crypt($password, $this->salt);
                $this->parent_network=$parent_network;
                $this->network_site=$network_site;          
            }

            public function authenticateUser(){
                $database=new Database();
                $database->getConnection();
                $database->startConnection();

                $authenticate_q=mysql_query("SELECT network_users.network_id
                FROM network_users
                WHERE network_users.handle = '$this->handle'
                AND network_users.password ='$this->password'
                LIMIT 1");

                if(mysql_num_rows($authenticate_q)==1){

                    $this->isLoggedIn=true;
                    $user=mysql_fetch_array($authenticate_q);
                    $this->network_id=$user['network_id'];
                    $this->setNetworkId();
                } else{
                    //header('HTTP/1.1 500 Internal Server Error');
                    //die("Something went wrong.");
                }
            }

            function isLoggedIn(){

                return $this->isLoggedIn;
            }

            function addError($error){

                $this->error_list[]=$error;
            }


            function setNetworkId(){

                $_SESSION['network_id']=$this->network_id;
            }

            private $network_id, $handle, $password, $network_site, $parent_network, $error_list, $isLoggedIn=false,
            $salt="PRIVATE INFO";
        }
    ?>

首先,使用浏览器工具查看网络流量并检查请求/响应头。检查cookie是否被正确传递。 - deceze
@Charles:我正在使用Google Chrome。我不确定如何查找请求/响应头。但是,我看到的是在“网络”下作为响应的200 OK。还有,在cookie下有一个名为PHPSESSID的值为一长串字符的内容。我让我的php脚本回显或json回传给ajax用户ID,它会显示出来,所以我确定SESSION已经初始化了。问题出现在重定向回index.php时。 - Kevin Karimu
你在使用SQL查询之前是否对输入进行了消毒处理? - Alex
点击您看到的请求文件名,然后查看标头。 - deceze
@deceze 我正在使用 Google Chrome,Cookie 上显示 PHPSESSID=51988711cfcca91750b2d5746a24cdf1。更有趣的是,在 Headers 部分下它说 Response Headers expires Nov 19 1981。这很奇怪,哈哈。 - Kevin Karimu
显示剩余3条评论
4个回答

2

所以这是您的PHP配置问题。

几天前,我在我的Linux测试机上遇到了这个问题 - 我通过清空存储会话数据的/tmp目录来解决它。

您正在运行哪个版本的PHP?

对于旧版本的PHP,必须启用扩展session.so(在php.ini中)才能使其工作,在较新的版本中,它应该默认工作。

您可以在php.ini文件中检查会话数据保存的路径,搜索以下行:

session.save_path = "/tmp"

在较新的安装版本中,此内容已被注释掉,默认情况下使用/tmp是可以的。
确保文件夹权限正确设置,以便PHP可以读写该文件夹。

当我查看我的php.ini文件时,它说:session.save_path = "N;/path",这是正确的吗?在我看来,这看起来不对。哈哈 - Kevin Karimu
我已经更新了这个问题/帖子,以展示我的php.ini文件的完整SESSION部分。 - Kevin Karimu
1
所以它被设置为/var/php_sessions - 检查该目录是否存在并将其chmod为777 EDIT - 还要删除该目录中的所有内容。 - jeremyj11
我刚刚发现问题出在我的托管服务上。他们已经在他们的端口修复了这个问题,现在它可以正常工作了。 - Kevin Karimu
我已经点赞并将您的答案作为解决方案,因为您对于PHP配置是正确的。 - Kevin Karimu
路径不存在,这就是问题所在。哈哈。 - Kevin Karimu

1

你测试过 PHP 会话是否正常工作吗?

我问这个的原因是最近我刚刚安装了 Linux / Apache / PHP,我的会话在删除 /tmp 的内容之前无法工作。

可以通过创建两个文件来测试,第一个文件:

session_start();
$_SESSION['test']='hi';

文件2:

session_start();
var_dump($_SESSION);

刚才我取得了一些成功。我在login-classes.php的setNetworkId()函数中,用setcookie('user_id', $userid)替换了$_SESSION['network_id']=$this->network_id;的代码。当我检查浏览器控制台时,它反映出已创建一个名为network_id的cookie,并且user_id的值是正确的。你认为可能发生了什么?哈哈。 - Kevin Karimu
听起来会话没起作用!使用setcookie并不好,因为对于禁用cookie的任何人都无法使用。你试过测试了吗? - jeremyj11
我在index.php上创建了一个测试会话,并且它成功地打印出来了。因此,在authenticate_user.php进行身份验证时(该身份验证是由login.php中的jQuery AJAX完成的),当SESSION设置为echo或display时,存在某些问题。但我不知道具体是什么问题。 - Kevin Karimu
它将始终在单个页面上工作,你测试过在一个页面上设置会话并在另一个页面上检索它吗? - jeremyj11
是的,我刚试了一下,它没有在页面之间传递。我在一个页面上创建了一个S_SESSION ['test'],在另一个页面上进行了回显,但它没有起作用。 - Kevin Karimu

1
可能是一个愚蠢的问题 - 但是你的登录文件是否在同一个域名下? PHP会话不会跨子域传输,因此如果您的login.php位于子域(例如login.example.com),而index.php位于www.example.com上,则无法正常工作。

它们在同一个域上。 - Kevin Karimu

0
问题现在缩小到了一个 $_SESSION 变量在页面之间传递。我已确保所有页面在顶部都有 session_start() 并设置了会话并在另一页上输出了会话。然而,它没有将数据传递到下一个页面。可能的原因是什么?

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接