4

我正在为 Joomla 开发!2.5.6 并且此代码用于与 Joomla 1.5 一起正常工作

第 1 页

JFactory::getSession()->clear('domain_name', 'dominiForm');

第2页

$session = JFactory::getSession();
$session->set('domain_name', $domain_name, 'dominiForm');

第 3 页

$session = JFactory::getSession();
$domain_name = $session->get('domain_name', null, 'dominiForm');

问题是第 3 页有时会返回 null,有时会返回保存的值。它在我的开发机器上工作正常,但在生产服务器上不行,我不知道该怎么做。

这是服务器上的一些 phpinfo()

PHP Version 5.3.3-7+squeeze14
session
Session Support     enabled
Registered save handlers    files user sqlite
Registered serializer handlers  php php_binary wddx

Directive   Local Value Master Value
session.auto_start  Off Off
session.bug_compat_42   Off Off
session.bug_compat_warn Off Off
session.cache_expire    180 180
session.cache_limiter   none    nocache
session.cookie_domain   no value    no value
session.cookie_httponly Off Off
session.cookie_lifetime 0   0
session.cookie_path /   /
session.cookie_secure   Off Off
session.entropy_file    no value    no value
session.entropy_length  0   0
session.gc_divisor  1000    1000
session.gc_maxlifetime  2700    1440
session.gc_probability  0   0
session.hash_bits_per_character 5   5
session.hash_function   0   0
session.name    a6252c638b628a21b4b4b1cf3338a103    PHPSESSID
session.referer_check   no value    no value
session.save_handler    user    files
session.save_path   /var/lib/php5   /var/lib/php5
session.serialize_handler   php php
session.use_cookies On  On
session.use_only_cookies    On  On
session.use_trans_sid   0   0
4

3 回答 3

4

您正在生产服务器上使用自定义 session.save_handler。可能你不在你的开发机器上。

请注意,Joomla 确实获得了错误的会话锁定 - 没有。从本质上讲,这意味着您是竞争条件的受害者。

如果您查看session_set_save_handler() 的文档,您会看到有打开、关闭、读取、写入、销毁和 gc(垃圾收集)的回调。

open应该“初始化”东西,但最重要的是应该为用于存储的资源获取写锁。

read平时读书,write写字。

close应该释放写锁。

如果会话保存处理程序未获取锁,则具有相同会话 id 的多个并行请求可以相互覆盖!

你应该在你的服务器上执行一个简单的测试,看看你是否有这个问题:

<?php

// initialize alternate session save handler here.
//include_once "session-handler.php";

if (isset($_GET['subrequest'])) {
    $starttime = time();
    $subrequest = intval($_GET['subrequest']);

    session_start(); // should wait until lock is released

    echo "<html><pre>";
    echo "Request started on ". date("Y-m-d H:i:s", $starttime)."\n";
    echo "Session locked for this request on ". date("Y-m-d H:i:s"). "\n";
    echo "Executing subrequest ". $subrequest."\n";
    $_SESSION["subrequest"][] = 'collected subrequest #'.$subrequest;
    echo "All subrequests collected:\n";
    var_dump($_SESSION["subrequest"]);
    echo "\nWaiting 1 second\n";

    sleep(1);
    echo "Releasing session lock on ". date("Y-m-d H:i:s"). "\n";
    echo "</pre></html>";
    exit();
}

session_start();

$_SESSION['subrequest'] = array('master request');

?>
<html>
<iframe src="?subrequest=1" width="90%" height="100"></iframe>
<hr>
<iframe src="?subrequest=2" width="90%" height="100"></iframe>
<hr>
<iframe src="?subrequest=3" width="90%" height="100"></iframe>
</html>

这个 PHP 文件将初始化会话并在屏幕上发出三个 iframe,几乎立即再次向服务器发出三个请求。

如果会话被探测锁定,则每个 iframe 将在接下来的几秒钟内一个接一个地连续填充。此外,按照出现的顺序,控制输出$_SESSION['subrequest']应包括最后返回的子请求的所有子请求。

如果会话未正确锁定,则所有三个 iframe 将在加载主页一秒后几乎立即填满,并且都将仅在调试输出中报告它们自己的子请求以及主请求。

如果我将此实现用于从 php.net 文档(示例 #2)页面获得的文件系统存储,正确保存到会话将失败!

<?php
class FileSessionHandler
{
    private $savePath;

    function open($savePath, $sessionName)
    {
        $this->savePath = $savePath;
        if (!is_dir($this->savePath)) {
            mkdir($this->savePath, 0777);
        }

        return true;
    }

    function close()
    {
        return true;
    }

    function read($id)
    {
        return (string)@file_get_contents("$this->savePath/sess_$id");
    }

    function write($id, $data)
    {
        return file_put_contents("$this->savePath/sess_$id", $data) === false ? false : true;
    }

    function destroy($id)
    {
        $file = "$this->savePath/sess_$id";
        if (file_exists($file)) {
            unlink($file);
        }

        return true;
    }

    function gc($maxlifetime)
    {
        foreach (glob("$this->savePath/sess_*") as $file) {
            if (filemtime($file) + $maxlifetime < time() && file_exists($file)) {
                unlink($file);
            }
        }

        return true;
    }
}

$handler = new FileSessionHandler();
session_set_save_handler(
    array($handler, 'open'),
    array($handler, 'close'),
    array($handler, 'read'),
    array($handler, 'write'),
    array($handler, 'destroy'),
    array($handler, 'gc')
);

// the following prevents unexpected effects when using objects as save handlers
register_shutdown_function('session_write_close');

如果我看一下一些 Joomla 会话类,我会预测存储到 APC、数据库和 XCache 将无法通过此测试,因为它们使用自定义函数而没有实现openclose正确。

我不熟悉 Joomla,因此您必须自己实现 Joomla 将会话使用到此测试脚本中的方式。

最后一点:如果无法对数据库中的单个数据集进行锁定(例如,您正在使用 MyISAM 表),那么实际上您不能使用该表来存储会话数据。获取表上的锁将停止所有其他用户会话。

于 2012-10-14T19:18:35.697 回答
0

您是否在生产机器上使用缓存机制,例如清漆?因为在处理会话和 joomla 时缓存总是一团糟,所以当我使用缓存时遇到了很多与缓存自己相关的问题(这就是为什么我目前不使用缓存,只是没有用户缓存的 APC)。

于 2012-10-02T08:46:56.877 回答
0

我认为您可以使用此脚本在第一页或第二页中使用以下脚本

 $session =& JFactory::getSession();
    $session->set('name', "value");

* name是你的 session 变量, value 是你的值

然后在第三页使用这个

$session =& JFactory::getSession();

echo $session->get('name');* name是你的会话变量

于 2012-10-17T12:02:35.993 回答