自定义会话处理程序已纳入站点后,PHP购物车会话未更新



我正在整理一个带有基本购物车的基本网站,我们计划将来将敏感信息存储在会话中,因此现在进行排序是一个明智的选择。

没有自定义会话处理程序,一切正常,对于某些上下文,会话处理代码如下:

function decrypt($edata, $password) {
$data = base64_decode($edata);
$salt = substr($data, 0, 16);
$ct = substr($data, 16);
$rounds = 3; // depends on key length
$data00 = $password.$salt;
$hash = array();
$hash[0] = hash('sha256', $data00, true);
$result = $hash[0];
for ($i = 1; $i < $rounds; $i++) {
    $hash[$i] = hash('sha256', $hash[$i - 1].$data00, true);
    $result .= $hash[$i];
 }
    $key = substr($result, 0, 32);
    $iv  = substr($result, 32,16);
    return openssl_decrypt($ct, 'AES-256-CBC', $key, true, $iv); 
   } 
   function encrypt($data, $password) {
// Set a random salt
$salt = openssl_random_pseudo_bytes(16);
$salted = '';
$dx = '';
// Salt the key(32) and iv(16) = 48
while (strlen($salted) < 48) {
  $dx = hash('sha256', $dx.$password.$salt, true);
  $salted .= $dx;
}
$key = substr($salted, 0, 32);
$iv  = substr($salted, 32,16);
$encrypted_data = openssl_encrypt($data, 'AES-256-CBC', $key, true, $iv);
return base64_encode($salt . $encrypted_data);
 }
 class SecureSessionHandler extends SessionHandler {
 
protected $name, $cookie;
private  $key;
public function __construct($key, $name = 'MY_SESSION', $cookie = [])
       { 
    $this->key = $key;
    $this->name = $name;
    $this->cookie = $cookie;
    $this->cookie += [
        'lifetime' => 0,
        'path'     => ini_get('session.cookie_path'),
        'domain'   => ini_get('session.cookie_domain'),
        'secure'   => isset($_SERVER['HTTPS']),
        'httponly' => true
    ];
     $iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length('aes-256- 
     cbc'));
    $this->setup();
}
private function setup()
{
    ini_set('session.use_cookies', 1);
    ini_set('session.use_only_cookies', 1);
    session_name($this->name);
    session_set_cookie_params(
        $this->cookie['lifetime'],
        $this->cookie['path'],
        $this->cookie['domain'],
        $this->cookie['secure'],
        $this->cookie['httponly']
    );
}
public function start()
{
    if (session_id() === '') {
        if (session_start()) {
            return mt_rand(45, 99) === 55 ? $this->refresh() : true; // 1/5
        }
    }
    return false;
}
public function forget()
{
    if (session_id() === '') {
        return false;
    }
    $_SESSION = [];
    setcookie(
        $this->name,
        '',
        time() - 42000,
        $this->cookie['path'],
        $this->cookie['domain'],
        $this->cookie['secure'],
        $this->cookie['httponly']
    );
    return session_destroy();
}
public function refresh()
{
    return session_regenerate_id(false);
}
 public function write($id, $data)
{
     $data = encrypt($data, $this->key);
    return parent::write($id, $data);
    
}
public function read($id)
{
     $data = parent::read($id);
    if (!$data) {
        return "";
    } else {
        return decrypt($data, $this->key);
    }
}
public function isExpired($ttl = 30)
{
    $last = isset($_SESSION['_last_activity'])
        ? $_SESSION['_last_activity']
        : false;
    if ($last !== false && time() - $last > $ttl * 60) {
        return true;
    }
    $_SESSION['_last_activity'] = time();
    return false;
}
public function isFingerprint()
{
    $hash = md5(
        $_SERVER['HTTP_USER_AGENT'] .
        (ip2long($_SERVER['REMOTE_ADDR']) & ip2long('255.255.0.0'))
    );
    if (isset($_SESSION['_fingerprint'])) {
        return $_SESSION['_fingerprint'] === $hash;
    }
    $_SESSION['_fingerprint'] = $hash;
    return true;
}
public function isValid()
{
    return ! $this->isExpired() && $this->isFingerprint();
}
public function get($name)
{
    $parsed = explode('.', $name);
    $result = $_SESSION;
    while ($parsed) {
        $next = array_shift($parsed);
        if (isset($result[$next])) {
            $result = $result[$next];
        } else {
            return null;
        }
    }
    return $result;
}
public function put($name, $value)
{
    $parsed = explode('.', $name);
    $session =& $_SESSION;
    while (count($parsed) > 1) {
        $next = array_shift($parsed);
        if ( ! isset($session[$next]) || ! is_array($session[$next])) {
            $session[$next] = [];
        }
        $session =& $session[$next];
    }
    $session[array_shift($parsed)] = $value;
    }
    }
    $key = file_get_contents('./key.pem', FILE_USE_INCLUDE_PATH);
     $session = new SecureSessionHandler($key);
    ini_set('session.save_handler', 'files');
    session_set_save_handler($session, true);
    session_save_path(__DIR__ . '/sessions');
   $session->start('cheese');
   if ( ! $session->isValid(5)) {
   $session->destroy('cheese');
    }

有完整的会话处理程序和加密/解密方法,总体上一切正常,但是问题是在浏览我的购物车代码并将所有$ _Session变量更改为$ session-&GT;获得对象时,我设法设法替换每个$ _Session,然后我需要更改的最后一个造成致命错误:

更改&quot&quot&quot$ _session ['cart_contents'] = $ this-&gt; cart_contents;;to'$ session-&gt; get('cart_contents')= $ this-&gt; cart_contents;&quort; quot'

导致:

致命错误:在C: xampp htdocs teck teck teck teck cart.php中,无法使用方法返回值375

下面提到了其余的重要代码,我确保没有遗漏任何内容,最好有一个漫长的帖子,所有细节都比为一个小帖子打火的小帖子丢失了所有细节。

您可以调整数量的页面是viewcart.php,此页面重要的代码如下:

 <input type="number" class="form-control text-center" value="<?php echo 
 $item["qty"]; ?>" onchange="updateCartItem(this, '<?php echo 
 $item["rowid"]; ?>')">

和同一页面上的脚本(viewcart.php)引发警报如下:

  <script>
  function updateCartItem(obj,id){
    $.get("cartAction.php", {action:"updateCartItem", id:id, qty:obj.value}, 
  function(data){
        if(data == 'ok'){
            location.reload();
        }else{
            alert('Cart update failed, please try again.');
        }
    });
}
</script>

现在终于cartaction.php," updatecartitem"的操作代码。如下:

 }elseif($_REQUEST['action'] == 'updateCartItem' && !empty($_REQUEST['id']))
 {
    $itemData = array(
        'rowid' => $_REQUEST['id'],
        'qty' => $_REQUEST['qty']
    );
   $updateItem = $cart->update($itemData);
    echo $updateItem?'ok':'err';die;
    
}

cart.php中的更新功能:

  public function update($item = array()){
    if (!is_array($item) OR count($item) === 0){
        return FALSE;
    }else{
        if (!isset($item['rowid'], $this->cart_contents[$item['rowid']])){
            return FALSE;
        }else{
            // prep the quantity
            if(isset($item['qty'])){
                $item['qty'] = filter_var($item['qty'], 
      FILTER_VALIDATE_INT);
                // remove the item from the cart, if quantity is zero
                if ($item['qty'] == 0){
                    unset($this->cart_contents[$item['rowid']]);
                    return TRUE;
                }
            }
            
            // find updatable keys
            $keys = array_intersect(array_keys($this-
       >cart_contents[$item['rowid']]), array_keys($item));
            // prep the price
            if(isset($item['price'])){
                $item['price'] = filter_var($item['price'], 
    FILTER_VALIDATE_FLOAT);
            }
            // product id & name shouldn't be changed
            foreach(array_diff($keys, array('id', 'name')) as $key){
                $this->cart_contents[$item['rowid']][$key] = $item[$key];
            }
            // save cart data
            $this->save_cart();

            return TRUE;
        }
    }
  }

和最后但并非最不重要的一点是cart.php中的save_cart函数:

  protected function save_cart(){
    $this->cart_contents['total_items'] = $this->cart_contents['cart_total'] 
    = 0;
    foreach ($this->cart_contents as $key => $val){
        // make sure the array contains the proper indexes
        if(!is_array($val) OR !isset($val['price'], $val['qty'])){
            continue;
        }
 
        $this->cart_contents['cart_total'] += ($val['price'] * $val['qty']);
        $this->cart_contents['total_items'] += $val['qty'];
        $this->cart_contents[$key]['subtotal'] = ($this->cart_contents[$key]
        ['price'] * $this->cart_contents[$key]['qty']);
    }
    global $key;
    global $session;
    
    // if cart empty, delete it from the session
    if(count($this->cart_contents) <= 2){
        $session->forget();
        return FALSE;
    }else{

        // original code below
     $_SESSION['cart_contents'] = $this->cart_contents;
     


      // code below is what i think will clear everything up but throws the 
      //  error.
        $session->get('cart_contents') = $this->cart_contents;
        return TRUE;


    }
    }
    

上面的购物车代码与会话处理程序同一文件

有更多的解释,并带有"$ _session ['cart_contents'] = $ this-&gt; cart_contents;;(原始代码),

我按按钮 1将额外的项目添加到购物车中,文本字段增加了1,并且错误警报弹出"购物车更新失败,请重试",我单击确定,警报消失了,没有什么发生了,文本框中的项目数量保持更新,但是实际的CART数量不会更新,直到我刷新页面或单击链接。

使用标准的会话处理程序,这没有发生,一切都可以完美。

我必须将此$ _session ['cart_contents']变为$ session-&gt; get('cart_contents')?

我应该能够更改该脚本警报以正确更新购物车而无需发布警报,但是如果我离开一个会话变量,我的自定义会话处理程序会完美地工作吗?

我对漫长的帖子感到非常抱歉,但我想确保其他人也尽可能清楚地了解他们是否有类似的问题。

从这个角度来看,代码似乎确实很混乱,但是如果您要浏览整个网站,那么一切都会更有意义。

我已经在PHP上使用了大约2个月的最大值,现在尽我所能尽可能多地拿起,所以请忍受我,显然,大多数代码都不那么干净,但这是生产。<<<<<<<<<<<<<<

我在这个会话处理程序上度过了3-4天,我真的不想丢弃它,只是回到标准_Session。

all&amp;欢迎任何建议,建设性的批评将被轻轻地接受!

我真的很感谢您花的时间进行此操作,感谢您的努力!

您在line

上获得错误
$session->get('cart_contents') = $this->cart_contents;

在这里,我假设get函数返回参考。因此,如果要将$ this-> cart_contents存储到参考变量,则必须使用$$。例如$ temp = $ session-> get('cart_contents');并使用$$ temp = $ this-> cart_contents;

或如果要将$ this-> cart_contents分配给购物车值,则必须使用

$this->cart_contents = $session->get('cart_contents');

您不能只使用获取方法并为其分配一个值。

除了继续研究之外,我真的没有什么能做的,我可以做些什么才能使它起作用,但是有人可以让我知道这是否会使我的自定义SessionHandler无法按预期工作?

我更改了updatecartitem函数,因此没有语句直接调用该函数,然后重新加载页面。

 <script>
 function updateCartItem(obj,id){
 $.get("cartAction.php", {action:"updateCartItem", id:id, qty:obj.value}, 
 function(data){
        location.reload();
 });
 }</script>

这与SAVE_CART函数正常工作如下:

protected function save_cart(){
$this->cart_contents['total_items'] = $this->cart_contents['cart_total'] 
= 0;
foreach ($this->cart_contents as $key => $val){
    // make sure the array contains the proper indexes
    if(!is_array($val) OR !isset($val['price'], $val['qty'])){
        continue;
    }
    $this->cart_contents['cart_total'] += ($val['price'] * $val['qty']);
    $this->cart_contents['total_items'] += $val['qty'];
    $this->cart_contents[$key]['subtotal'] = ($this->cart_contents[$key]
    ['price'] * $this->cart_contents[$key]['qty']);
}
global $key;
global $session;
// if cart empty, delete it from the session
if(count($this->cart_contents) <= 2){
    $session->forget();
    return FALSE;
}else{
 $_SESSION['cart_contents'] = $this->cart_contents;
    return TRUE;
}
}

但是!$ _Session变量是否不应该被我的自定义会话处理程序呼叫替换吗?($ session-> get('cart_contents')= $ this-> cart_contents;)显然,如果我更改它,则会获得错误:(

一切似乎都可以在会话中奏效,但是这会在我的会话安全性中造成弱点吗?而且我应该能够在UpdateCartitem脚本中使用IF语句!必须有一种使用CustomSessionHandler调用的方法,而不是" $ _session ['cart_contents']。

最新更新