在PHP中,为什么我的会话变量作为引用保持不变?

Here's the code. It's a simple operation to check that a session ID isn't being spoofed by verifying the IP address:

session_start();
$session_ip_address = $_SERVER['REMOTE_ADDR'];
if((!isset($_SESSION['SESSION_IP_ADDRESS'])) || !$_SESSION['SESSION_IP_ADDRESS']) {
    $_SESSION['SESSION_IP_ADDRESS'] = $session_ip_address;
}


if($_SESSION['SESSION_IP_ADDRESS'] != $_SERVER['REMOTE_ADDR']) {
    session_destroy();
    $_SESSION['security_error'] = true;
}

If I insert var_dump($_SESSION) right after session_start() and again at the end of the script, then the very first time I run the code (without a session cookie set) I see that at first the array is empty, then it has my IP address assigned to the key 'SESSION_IP_ADDRESS'. So far, so good. But when I run the code again, now it shows that 'SESSION_IP_ADDRESS' is stored as a reference immediately after the session starts (I can tell by the ampersand prepended to the string). When I run it a third time, I see that 'SESSION_IP_ADDRESS' is now a null reference ('SESSION_IP_ADDRESS' => &null) immediately after the session starts. What is going on?!

To reiterate, this is the output the first time:

array(0) {
}
array(1) {
  ["SESSION_IP_ADDRESS"]=>
  string(11) "xx.xx.xxx.x"
} 

This is the output the second time:

array(1) {
  ["SESSION_IP_ADDRESS"]=>
  &string(11) "xx.xx.xxx.x"
}
array(1) {
  ["SESSION_IP_ADDRESS"]=>
  &string(11) "xx.xx.xxx.x"
}

And the third time and every time from then on:

array(1) {
  ["SESSION_IP_ADDRESS"]=>
  &NULL
}
array(1) {
  ["SESSION_IP_ADDRESS"]=>
  &string(11) "xx.xx.xxx.x"
}

If I have:

<?php

$x = 'blah';
$_SESSION['blah'] = $x;

var_dump($_SESSION);

I get:

array(1) {
  ["blah"]=>
  string(4) "blah"
}

No references in sight. PHP 5.3.2 on Ubuntu 10.04.1

it does assign by value, the reference & next to $_SESSION has nothing to do with your expression $_SESSION['x'] = $x;

The only time your session variables are going to be references, is when you reference a session variable to another session variable (or if the original reference is still in scope).

Per example:

session_start();
$x = 'foo';
$_SESSION['x'] = &$x;

This will give you:

array(1) {
  ["x"]=>
  string(3) "foo"
}

While this:

$x = 'foo';
$_SESSION['x'] = $x;
$_SESSION['y'] = &$_SESSION['x']; // reference to another $_SESSION var

Or this:

session_start();
$x = 'foo';
$_SESSION['x'] = $x;
$_SESSION['y'] = &$x;
var_dump($_SESSION); // reference still in scope

Would give you:

array(2) {
  ["x"]=>
  string(3) "foo"
  ["y"]=>
  &string(3) "foo"
}

Either way, doing this:

session_start();
$y = $_SESSION['y'];
$y = 'bar';

Will not modify the y session variable. In order to do that, you'd have to do:

session_start();
$y = &$_SESSION['y'];
$y = 'bar';

One of my customers had a very similar problem.

Make sure your PHP configuration (PHP.ini) has register_globals Off otherwise regular variables overwrite superglobals including PHP sessions.