php 会话随机丢失,无法理解为什么

2024-03-11

我付钱给一个程序员制作一个购物篮脚本来与 Spreadshirt API 一起使用。一切都运转良好,只是篮子不断地变空。我认为会话在某个时刻丢失了,因此脚本创建了另一个会话BasketId.

我试图找出发生这种情况是否有特定原因,但没有成功......我无法重现该错误。它只是随机发生,没有任何原因。关闭浏览器、重置 apache 甚至整个网络服务器都不会导致会话丢失。

我有两个不同的脚本在同一域上使用 cookie,它们没有任何问题(一个是用于管理员登录会话的 cookie,另一个 cookie 是保存用户上次在商店中查看的文章)

我尝试了在谷歌上找到的所有解决方案,但没有成功:编辑php.ini,通过 php 强制 ini 设置,尝试了htaccess方式, ...

这是我的 phpinfo 的“会话”部分:http://gyazo.com/168e2144ddd9ee368a05754dfd463021 http://gyazo.com/168e2144ddd9ee368a05754dfd463021

shop-ajax.php(会话处理@第18行)

ini_set('session.cookie_domain', '.mywebsite.com' );
header("Pragma: no-cache");
header("Cache-Control: no-store, no-cache, max-age=0, must-revalidate");
$language = addslashes($_GET['l']);
$shopid = addslashes($_GET['shop']);


// if($_SERVER['HTTP_X_REQUESTED_WITH'] != 'XMLHttpRequest') {
//  die("no direct access allowed");
// }



if(!session_id()) {
  $lifetime=60 * 60 * 24 * 365;
  $domain = ".mywebsite.com";
   session_set_cookie_params($lifetime,"/",$domain);
    @session_start();
}





// Configuration
$config['ShopSource'] = "com";
$config['ShopId'] = $shopid;
$config['ShopKey'] = "*****";
$config['ShopSecret'] = "*****";



/*
 * add an article to the basket
*/
if (isset($_POST['size']) && isset($_POST['appearance']) && isset($_POST['quantity'])) {
    /*
     * create an new basket if not exist
    */
    if (!isset($_SESSION['basketUrl'])) {
        /*
         * get shop xml
        */
        $stringApiUrl = 'http://api.spreadshirt.'.$config['ShopSource'].'/api/v1/shops/' . $config['ShopId'];
        $stringXmlShop = oldHttpRequest($stringApiUrl, null, 'GET');
        if ($stringXmlShop[0]!='<') die($stringXmlShop);
        $objShop = new SimpleXmlElement($stringXmlShop);
        if (!is_object($objShop)) die('Basket not loaded');

        /*
         * create the basket
        */
        $namespaces = $objShop->getNamespaces(true);
        $basketUrl = createBasket('net', $objShop, $namespaces);
        $_SESSION['basketUrl'] = $basketUrl;
        $_SESSION['namespaces'] = $namespaces;

        /*
         * get the checkout url
        */
        $checkoutUrl = checkout($_SESSION['basketUrl'], $_SESSION['namespaces']);

        // basket language workaround
        if ($language=="fr") {
            if (!strstr($checkoutUrl,'/fr')) {
                $checkoutUrl = str_replace("spreadshirt.com","spreadshirt.com/fr",$checkoutUrl);
            }
        }

        $_SESSION['checkoutUrl'] = $checkoutUrl;

    }



    /*
    Workaround for not having the appearance id :(
    */
    if ($_POST['appearance']==0) {
        $stringApiArticleUrl = 'http://api.spreadshirt.'.$config['ShopSource'].'/api/v1/shops/' . $config['ShopId'].'/articles/'.intval($_POST['article']).'?fullData=true';
        $stringXmlArticle = oldHttpRequest($stringApiArticleUrl, null, 'GET');
        if ($stringXmlArticle[0]!='<') die($stringXmlArticle);
        $objArticleShop = new SimpleXmlElement($stringXmlArticle);
        if (!is_object($objArticleShop)) die('Article not loaded');
        $_POST['appearance'] = intval($objArticleShop->product->appearance['id']);
    }


    /*
     * article data to be sent to the basket resource
    */
    $data = array(

            'articleId' => intval($_POST['article']),
            'size' => intval($_POST['size']),
            'appearance' => intval($_POST['appearance']),
            'quantity' => intval($_POST['quantity']),
            'shopId' => $config['ShopId']

    );

    /*
     * add to basket
    */
    addBasketItem($_SESSION['basketUrl'] , $_SESSION['namespaces'] , $data);

    $basketData = prepareBasket();


    echo json_encode(array("c" => array("u" => $_SESSION['checkoutUrl'],"q" => $basketData[0],"l" => $basketData[1])));
}




// no call, just read basket if not empty
if (isset($_GET['basket'])) {
    if (array_key_exists('basketUrl',$_SESSION) && !empty($_SESSION['basketUrl'])) {

        $basketData = prepareBasket();

        echo json_encode(array("c" => array("u" => $_SESSION['checkoutUrl'],"q" => $basketData[0],"l" => $basketData[1])));
    } else {
        echo json_encode(array("c" => array("u" => "","q" => 0,"l" => "")));
    }
}






function prepareBasket() {

    $intInBasket=0;

    if (isset($_SESSION['basketUrl'])) {
        $basketItems=getBasket($_SESSION['basketUrl']);

        if(!empty($basketItems)) {
            foreach($basketItems->basketItems->basketItem as $item) {
                $intInBasket += $item->quantity;
            }
        }
    }

    $l = "";
    $pQ = parse_url($_SESSION['checkoutUrl']);
    if (preg_match("#^basketId\=([0-9a-f\-])*$#i", $pQ['query'])) {
        $l = $pQ['query'];
    }

    return array($intInBasket,$l);
}







// Additional functions
function addBasketItem($basketUrl, $namespaces, $data) {
    global $config;

    $basketItemsUrl = $basketUrl . "/items";

    $basketItem = new SimpleXmlElement('<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
            <basketItem xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://api.spreadshirt.net">
            <quantity>' . $data['quantity'] . '</quantity>
            <element id="' . $data['articleId'] . '" type="sprd:article" xlink:href="http://api.spreadshirt.'.$config['ShopSource'].'/api/v1/shops/' . $data['shopId'] . '/articles/' . $data['articleId'] . '">
            <properties>
            <property key="appearance">' . $data['appearance'] . '</property>
            <property key="size">' . $data['size'] . '</property>
            </properties>
            </element>
            <links>
            <link type="edit" xlink:href="http://' . $data['shopId'] .'.spreadshirt.' .$config['ShopSource'].'/-A' . $data['articleId'] . '"/>
            <link type="continueShopping" xlink:href="http://' . $data['shopId'].'.spreadshirt.'.$config['ShopSource'].'"/>
            </links>
            </basketItem>');

    $header = array();
    $header[] = createAuthHeader("POST", $basketItemsUrl);
    $header[] = "Content-Type: application/xml";
    $result = oldHttpRequest($basketItemsUrl, $header, 'POST', $basketItem->asXML());
}



function createBasket($platform, $shop, $namespaces) {

    $basket = new SimpleXmlElement('<basket xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://api.spreadshirt.net">
            <shop id="' . $shop['id'] . '"/>
            </basket>');

    $attributes = $shop->baskets->attributes($namespaces['xlink']);
    $basketsUrl = $attributes->href;
    $header = array();
    $header[] = createAuthHeader("POST", $basketsUrl);
    $header[] = "Content-Type: application/xml";
    $result = oldHttpRequest($basketsUrl, $header, 'POST', $basket->asXML());
    $basketUrl = parseHttpHeaders($result, "Location");

    return $basketUrl;

}






function checkout($basketUrl, $namespaces) {

    $basketCheckoutUrl = $basketUrl . "/checkout";
    $header = array();
    $header[] = createAuthHeader("GET", $basketCheckoutUrl);
    $header[] = "Content-Type: application/xml";
    $result = oldHttpRequest($basketCheckoutUrl, $header, 'GET');
    $checkoutRef = new SimpleXMLElement($result);
    $refAttributes = $checkoutRef->attributes($namespaces['xlink']);
    $checkoutUrl = (string)$refAttributes->href;

    return $checkoutUrl;

}

/*
 * functions to build headers
*/
function createAuthHeader($method, $url) {
    global $config;

    $time = time() *1000;
    $data = "$method $url $time";
    $sig = sha1("$data ".$config['ShopSecret']);

    return "Authorization: SprdAuth apiKey=\"".$config['ShopKey']."\", data=\"$data\", sig=\"$sig\"";

}


function parseHttpHeaders($header, $headername) {

    $retVal = array();
    $fields = explode("\r\n", preg_replace('/\x0D\x0A[\x09\x20]+/', ' ', $header));

    foreach($fields as $field) {

        if (preg_match('/(' . $headername . '): (.+)/m', $field, $match)) {
            return $match[2];
        }

    }

    return $retVal;

}

function getBasket($basketUrl) {

    $header = array();
    $basket = "";

    if (!empty($basketUrl)) {
        $header[] = createAuthHeader("GET", $basketUrl);
        $header[] = "Content-Type: application/xml";
        $result = oldHttpRequest($basketUrl, $header, 'GET');
        $basket = new SimpleXMLElement($result);
    }

    return $basket;

}




function oldHttpRequest($url, $header = null, $method = 'GET', $data = null, $len = null) {

    switch ($method) {

        case 'GET':

            $ch = curl_init($url);
            curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            curl_setopt($ch, CURLOPT_HEADER, false);

            if (!is_null($header)) curl_setopt($ch, CURLOPT_HTTPHEADER, $header);

            break;

        case 'POST':

            $ch = curl_init($url);
            curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            curl_setopt($ch, CURLOPT_HEADER, true);
            curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
            curl_setopt($ch, CURLOPT_POST, true); //not createBasket but addBasketItem
            curl_setopt($ch, CURLOPT_POSTFIELDS, $data);

            break;

    }

    $result = curl_exec($ch);
    curl_close($ch);

    return $result;

}
?>

该脚本还有另外 2 个部分:用于将示例 T 恤添加到购物篮的表单(example.php)和一个调用ajax的脚本(shop-controller.js)。如果需要的话可以发布它,但没有会话处理的东西。

更新 - 也许问题与会话无关。 BasketId 丢失,但 PHPSESSID 在浏览器 cookie 中保持不变。

最近3天我做了以下测试(使用不同的计算机和浏览器进行测试):

  • 清空浏览器 cookie,然后在下午开始新会话

  • 将 1 件商品添加到购物篮,我记下 BasketId 并检查浏览器 cookie 以记下 PHPSESSID

  • 通常总是在午夜左右,篮子自己空了

  • PHPSESSID 在我的浏览器 cookie 中保持不变,即使购物篮本身已空

  • 但是BASKETID不一样,下午用的丢失了,重新生成了一个新的

服务器是 CentOS 5.9 - PHP 版本 5.2.9(来自 OVH)。专用IP 上的专用服务器。


首先,您需要确定问题是否出在会话的垃圾收集中或代码中的逻辑错误。为此,您可以:

// Add this right after session_start()
if (!isset($_SESSION['mySessionCheck'])) {
    $_SESSION['mySessionCheck'] = "This session (" . session_id() . ") started " . date("Y-m-d H:i:s");
}

// For HTML pages, add this:
echo '<!-- ' . $_SESSION['mySessionCheck'] . ' -->';

// For AJAX pages, add "mySessionCheck" to the JSON response:
echo json_encode(
    array(
        "c" => array(
            "u" => $_SESSION['checkoutUrl'],
            "q" => $basketData[0],
            "l" => $basketData[1]
        ),
        "mySessionCheck" => $_SESSION['mySessionCheck']
    )
);

如果此消息在购物篮清空的同时发生变化,那么您就可以确定这是 PHP 会话的问题。

在这种情况下,您可以尝试以下几种方法:

1)你正在做

$lifetime=60 * 60 * 24 * 365;
$domain = ".mywebsite.com";
session_set_cookie_params($lifetime,"/",$domain);
@session_start();

但根据一个用户贡献的注释 http://php.net/manual/en/function.session-set-cookie-params.php#100657来自 PHP.net 文档:

PHP 的会话控制在使用时无法正确处理会话生命周期session_set_cookie_params().

所以你可以尝试使用setcookie()反而:

$lifetime=60 * 60 * 24 * 365;
session_start();
setcookie(session_name(),session_id(),time()+$lifetime);

尽管这是评论中指出的 4 年前的注释,但我对其进行了测试,它仍然会发生(我使用的是 PHP 5.5.7、Windows Server 2008、IIS/7.5)。仅有的setcookie()生成 HTTP 标头来更改到期日期(示例设置$lifetime至 600):

Set-Cookie: PHPSESSID=(the id); expires=Mon, 22-Jun-2015 15:03:17 GMT; Max-Age=600

2) 如果您使用 Debian 服务器或某些衍生产品,它们使用 cron 作业清除 PHP 会话 https://serverfault.com/questions/511609/why-does-debian-clean-php-sessions-with-a-cron-job-instead-of-using-phps-built,所以你可以尝试:

  • 增加服务器配置maxlifetime https://stackoverflow.com/questions/3865303/debian-based-systems-session-killed-at-30-minutes-in-special-cron-how-to-overri#3865334;
  • 将您的会话保存在其他地方 https://stackoverflow.com/questions/8372189/php-sessions-expire-too-soon#8372835;
  • Using 内存缓存 http://php.net/manual/en/memcached.sessions.php.

3) 要查明是否有某些进程清除您的会话,您可以在存储会话文件的目录上放置监视(实际路径因服务器而异,使用session_save_path http://php.net/manual/en/function.session-save-path.php找出您的位置)。我不是服务器管理员,但我读过您可以使用auditctl https://serverfault.com/questions/144698/file-audit-in-linux-how-to-watch-directory-tree-for-deletions为此,只需确保您登录谁对您的文件进行了更改 http://www.cyberciti.biz/tips/linux-audit-files-to-see-who-made-changes-to-a-file.html.

4)如果您无权访问服务器配置,或者不想依赖服务器配置(如果您切换主机则很好),您可以实现自己的会话处理程序。看看这个佩德罗·吉梅诺的例子 https://stackoverflow.com/questions/8311320/how-to-change-the-session-timeout-in-php#18573350.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

php 会话随机丢失,无法理解为什么 的相关文章

  • Angular UI-Router:多个 URL 到单一状态

    我已经开始使用 Angular 的 ui router 并且我正在尝试弄清楚如何让多个 URL 引用单个状态 例如 orgs 12354 overview retyrns the same pages as org overview 我的
  • 在 PHP 中将整数转换为十六进制值

    如何将PHP中第一类中的数字转换为第二类中的数字 是否有内置函数来转换数字 也是我的标题 将整数转换为十六进制值 甚至正确 class Permission const READ 1 const UPDATE 2 const DELETE
  • 如何将本地文本文件上传到文本区域(网页内)

    我是一名新手程序员 需要一些帮助来弄清楚如何将本地文本文件上传到我正在构建的网站内的文本区域 我非常精通 HTML CSS 对 Javascript JQuery 有相当的了解 而且我刚刚学习 PHP 您能提供的任何帮助我将不胜感激 我有一
  • 通过 post 使用 php 发送 XML

    我知道有很多类似的问题 但我尝试过摆弄所有的解决方案 但似乎无法使其发挥作用 我正在尝试将 xml 直接发布到 Web 服务并获得响应 从技术上讲 我正在尝试连接到freightquote com 您可以在右上角找到该文档this http
  • 只保留 A-Z 0-9 并使用 javascript 从字符串中删除其他字符

    我正在尝试验证字符串以使它们成为有效的网址 我只需要保留 A Z 0 9 并使用以下命令从字符串中删除其他字符javascript or jquery 例如 贝儿餐厅 我需要将其转换为 百丽餐厅 所以字符被删除 只保留 A Z a z 0
  • 对使用“new”创建的数组上“map”的行为感到困惑[重复]

    这个问题在这里已经有答案了 我对结果感到困惑mapping 使用创建的数组new function returnsFourteen return 14 var a new Array 4 gt undefined x 4 in Chrome
  • Angular 2 将字符串转换为 md5 哈希

    我找到了ts md5 https www npmjs com package ts md5包 但在示例中它有一个hashStr方法 但现在不行了 类型上不存在属性 hashStr Md5 使用该错误后 该错误会记录在我的控制台中 我怎样才能
  • 如何在打字稿中使用外部js

    我通过 Typescript 代码生成 Angular JS 代码 在一种情况下 我需要将外部 JS 文件添加到我的打字稿文件中 并且需要访问 js 文件中的类 我像这样添加js文件
  • Yii 未检测到骆驼案例操作

    伊伊正在给我404 Error如果我声明这样的操作 站点控制器 php public function actionRegisterUser 这就是我在main php label gt Register User url gt site
  • 从检查元素隐藏 ''

    我有这个 HTML 和 PHP 联系表
  • ES6 静态方法引用 self? [复制]

    这个问题在这里已经有答案了 我有两节课 存储库和用户存储库 我想在 Repository 中定义一个静态方法 该方法在运行时调用 UserRepository 中的静态函数 有什么干净的方法可以做到这一点吗 class Repository
  • 2 使用我的代码在数组中查询

    我使用滑块来显示我的 WordPress 精选文章 它选择一个自定义类别并返回一定数量的帖子 如何将显示的第一篇帖子设为自定义帖子 我可以直接在滑块代码中添加特定帖子的 ID吗使该帖子首先出现 然后是原始查询返回的其他内容 例如 在页面上
  • 如何使用 Javascript 在 html 文件中搜索字符串?

    我有 5 个 html 文件 并且有一个搜索表单 我想用它来搜索这些 html 文件中的文本
  • 创建单个随机 Magento 优惠券

    我遇到了一些麻烦 我想要做的是每次有人订阅我们的时事通讯时 在 Magento 中自动生成一个随机优惠券代码 这张优惠券可减 10 美元 并且有exp 订阅后两周的日期 因此 我正在尝试编写一个简单的脚本 当提交 订阅我们的时事通讯 表单时
  • Javascript等待/异步执行顺序

    所以我试图把我的头脑集中在 Promise await async 上 我不明白为什么当 go 执行时 带有 finished 的警报会紧随 console log coffee 之后 当所有函数都使用等待 承诺时 为什么它只等待 getC
  • 从请求url获取hash参数

    我有这样的网址 http www coolsite com daily plan id 1 http www coolsite com daily plan id 1解析该字符串并读取哈希值 id 之后的值 的最简单方法是什么 谢谢 在客户
  • 使用 Xpath 进行部分匹配

    我正在尝试创建一个搜索功能 允许使用 Xpath 按歌曲标题或流派进行部分匹配 这是我的 XML 文件
  • 如何使用 fetch() 和 WhatWG 流获取文件上传进度

    注意 我并不是在寻找任何替代方案 我知道这可以通过 XMLHttpRequest 来完成 我也不关心浏览器支持 我只想了解新的 即将推出的标准 我有一个File https developer mozilla org en US docs
  • 如果 jquery 验证激活,如何在单选按钮中放置红色边框[重复]

    这个问题在这里已经有答案了 我的问题是 如果 jquery 验证像示例图片中那样激活 我无法使单选按钮具有红色边框 任何人都可以帮我解决这个问题吗 http i38 photobucket com albums e149 eloginko
  • Array.of 与“[ ]”。何时使用 Array.of 而不是“[ ]”?

    当我发现时我正在读一些书Array of https developer mozilla org en docs Web JavaScript Reference Global Objects Array of 根据 MDN Array o

随机推荐