我正在整理一个带有基本购物车的基本网站,我们计划将来将敏感信息存储在会话中,因此现在进行排序是一个明智的选择。
没有自定义会话处理程序,一切正常,对于某些上下文,会话处理代码如下:
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']。