【问题标题】:Trouble accessing Drupal $_SESSION variable from external page从外部页面访问 Drupal $_SESSION 变量时遇到问题
【发布时间】:2012-11-11 02:27:11
【问题描述】:

我在访问外部页面上的 $_SESSION 变量时遇到问题。

基本上,我在一个drupal节点上有一个表单,当提交时,它会发布到一个外部php文件,该文件将值保存到一个$_SESSION变量,如下所示:

//Bootstrap Drupal so we can use the SESSION variables, where we store the calling number for the
//duration of the logged in session
define('DRUPAL_ROOT', $_SERVER['DOCUMENT_ROOT']);
$base_url = 'http://'.$_SERVER['HTTP_HOST'];
require_once DRUPAL_ROOT . '/includes/bootstrap.inc';
drupal_bootstrap(DRUPAL_BOOTSTRAP_SESSION);

//Save number as the calling number for the session
$_SESSION['calling-number']=$_REQUEST['calling-number'];

效果很好。

当我稍后尝试使用以下方法从外部页面访问 $_SESSION 变量时:

//Bootstrap Drupal so we can use the SESSION variables, where we store the calling number for the
//duration of the logged in session
define('DRUPAL_ROOT', $_SERVER['DOCUMENT_ROOT']);
$base_url = 'http://'.$_SERVER['HTTP_HOST'];
require_once DRUPAL_ROOT . '/includes/bootstrap.inc';
drupal_bootstrap(DRUPAL_BOOTSTRAP_SESSION);

echo $_SESSION['calling-number'];

我什么也得不到。如果我查看这个新页面上的 $user,我可以看到这是因为它在匿名用户会话 (uid = 0) 下运行,而不是设置 $_SESSION 变量的登录用户 ID,因此它找不到。

任何想法为什么我不使用登录用户的会话?

编辑

不知道为什么会这样,但是只要两个外部文件位于不同的目录中,就可以正常工作。如果它们在同一目录中,则似乎开始了一个新会话而不访问现有会话。不知道为什么。

【问题讨论】:

  • 您无需引导 Drupal 即可访问 $_SESSION。
  • 刚试过没有引导。仍然没有运气 - 有什么想法吗?如果我删除引导程序,我将无法再访问 $user 或任何其他 Drupal 变量,因此看来我确实需要它。

标签: php session drupal drupal-7 session-variables


【解决方案1】:

如果我理解正确,您从 Drupal 提交一个表单,其中有一个经过身份验证的用户,到一个外部 PHP 文件。当您尝试从引导 Drupal 的外部页面访问会话时,会话不包含先前保存的值,并且用户被报告为匿名用户,而不是先前提交表单的经过身份验证的用户。

这通常是因为:

  • Drupal 找不到名称为 session_name()substr(session_name(), 1) 的 cookie。
    在这种情况下,drupal_session_initialize() 执行以下代码。

    // Set a session identifier for this request. This is necessary because
    // we lazily start sessions at the end of this request, and some
    // processes (like drupal_get_token()) needs to know the future
    // session ID in advance.
    
    $GLOBALS['lazy_session'] = TRUE;
    $user = drupal_anonymous_user();
    // Less random sessions (which are much faster to generate) are used for
    // anonymous users than are generated in drupal_session_regenerate() when
    // a user becomes authenticated.
    session_id(drupal_hash_base64(uniqid(mt_rand(), TRUE)));
    if ($is_https && variable_get('https', FALSE)) {
      $insecure_session_name = substr(session_name(), 1);
      $session_id = drupal_hash_base64(uniqid(mt_rand(), TRUE));
      $_COOKIE[$insecure_session_name] = $session_id;
    }
    
  • Drupal 在其会话数据库表中找不到与传递给会话读取回调 (_drupal_session_read()) 的 $sid 参数值相等的 sid(或 ssid)的记录。如果会话已过期,也可能发生这种情况。

    if ($is_https) {
      $user = db_query("SELECT u.*, s.* FROM {users} u INNER JOIN {sessions} s ON u.uid = s.uid WHERE s.ssid = :ssid", array(':ssid' => $sid))->fetchObject();
      if (!$user) {
        if (isset($_COOKIE[$insecure_session_name])) {
          $user = db_query("SELECT u.*, s.* FROM {users} u INNER JOIN {sessions} s ON u.uid = s.uid WHERE s.sid = :sid AND s.uid = 0", array(
            ':sid' => $_COOKIE[$insecure_session_name],
          ))
          ->fetchObject();
        }
      }
    }
    else {
      $user = db_query("SELECT u.*, s.* FROM {users} u INNER JOIN {sessions} s ON u.uid = s.uid WHERE s.sid = :sid", array(':sid' => $sid))->fetchObject();
    }
    

当 PHP 关闭时,Drupal 总是通过_drupal_session_write() 为当前用户保存会话。当前用户是匿名用户时也会这样做。

   if (!drupal_save_session()) {
      // We don't have anything to do if we are not allowed to save the session.
      return;
    }

    // Check whether $_SESSION has been changed in this request.
    $last_read = &drupal_static('drupal_session_last_read');
    $is_changed = !isset($last_read) || $last_read['sid'] != $sid || $last_read['value'] !== $value;

    // For performance reasons, do not update the sessions table, unless
    // $_SESSION has changed or more than 180 has passed since the last update.
    if ($is_changed || !isset($user->timestamp) || REQUEST_TIME - $user->timestamp > variable_get('session_write_interval', 180)) {
      // Either ssid or sid or both will be added from $key below.
      $fields = array(
        'uid' => $user->uid, 
        'cache' => isset($user->cache) ? $user->cache : 0, 
        'hostname' => ip_address(), 
        'session' => $value, 
        'timestamp' => REQUEST_TIME,
      );

      // Use the session ID as 'sid' and an empty string as 'ssid' by default.
      // _drupal_session_read() does not allow empty strings so that's a safe
      // default.
      $key = array(
        'sid' => $sid,
        'ssid' => '',
      );

      // ...

      db_merge('sessions')
        ->key($key)
        ->fields($fields)
        ->execute();
    }

【讨论】:

    【解决方案2】:

    对于那些在使用外部页面时遇到同样问题的人:

    你只需要在代码中添加更多参数

    事实上,你必须精确你的drupal目录。

    例如。对于您的 drupal 目录之前的目录中的页面

    // Definine the path to "DRUPAL_ROOT" which is used throughout bootstrap.inc
    
    define('DRUPAL_ROOT', getcwd() . '/your_drupal_directory');
    
    // you could write like this too
    
    // define('DRUPAL_ROOT', $_SERVER['DOCUMENT_ROOT'] . '/your_drupal_directory');
    
    // Define the $base_url which will be used by Drupal to make sure we are on the same domain
    
    $base_url = 'http://'.$_SERVER['HTTP_HOST']. '/your_drupal_directory';
    
    require_once DRUPAL_ROOT . '/includes/bootstrap.inc';
    drupal_bootstrap(DRUPAL_BOOTSTRAP_SESSION);
    
    echo $_SESSION['calling-number'];
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-24
      • 1970-01-01
      • 1970-01-01
      • 2023-04-09
      相关资源
      最近更新 更多