php 缓存token在session的问题?

作者站长头像
站长
· 阅读数 4

不知道为什么第一次请求的token为空(过期之后请求的第一次 ) 第二次就可以 请求大神帮忙看看我要把token保存起来,要不然请求的接口次数不够用

<?php
header("Content-type:text/html;charset=utf-8");
session_start();
//接收post过来的 json数据
$data = json_decode(file_get_contents('php://input'), true);
$userPhone=$data['userPhone'];
$message=$data['message'];
$serNumber=$data['serNumber'];//编号
$username=$data['username'];//发起人
$processCategory=$data['processCategory'];//流程类别
$remark=$data['remark'];//备注
$sendTimestr=$data['sendTimestr'];//发起时间

//var_dump($data);die;
//print_r($sendTimestr);die;

$conn = mysqli_connect("192.168.0.232", "root", "@jjgw6201", "user_wechat");
$wxresult=mysqli_query($conn,"select * from user_wechat where PHONE_NUM = '$userPhone'");
$result = mysqli_fetch_array($wxresult, MYSQLI_ASSOC);

if(!empty($_SESSION['access_token']) && $_SESSION['expire_time'] > time() ) {
    //var_dump($_SESSION['access_token']."|".$_SESSION['expire_time']."|".time());die();
    $url = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=" . $_SESSION['access_token'];
    // var_dump(date("Y-m-d H:i:s", $_SESSION["expire_time"]));die();
    $template = [
    'touser' => $result['OPEN_ID'],  //openid
    'template_id' => "Jg8Ow95NYuepZ08J91bDbNzyZM5e9SZSC4eJ4PCe3HA", //前面新增的模板id
    'data' => array(
    'first'    => ['value' => urlencode("$message")],
    'keyword1' => array('value' => urlencode("$serNumber")),//编号
    'keyword2' => array('value' => urlencode("$username")),//发起人
    'keyword3' => array('value' => "$sendTimestr"),  //发起时间
    'keyword4' => array('value' => urlencode("$processCategory")),  //流程类别
    'remark'   => array('value' => urlencode("$remark")) //备注
    )
                ];
    $json_template = json_encode($template);
    $json_template1 = urldecode($json_template);
    $curl = curl_init();
    curl_setopt($curl, CURLOPT_URL, $url);
    curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
    curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($curl,CURLOPT_POSTFIELDS,$json_template1);
    $output = curl_exec($curl);
    //curl_close($curl);
    $output = json_decode($output,true);
    var_dump($output);
}
else
{
    //echo "2";die;
    // 过期了
    //print_r($result['OPEN_ID']);die();
    $app_id = 'xxx';
    $app_secret = 'xxx';
    //请求微信接口获取access_token
    $token_url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={$app_id}&secret={$app_secret}";
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $token_url);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    // curl_setopt($ch, CURLOPT_HTTPHEADER,$headerArray);
    $output = curl_exec($ch);
    //curl_close($ch);
    $output = json_decode($output,true);
    //var_dump($output);
    $access_token = $output["access_token"];
    //存储session
    $_SESSION['access_token']=$access_token;
    $_SESSION['expire_time']=time()+120; //秒
    return $_SESSION['access_token'];
}
回复
1个回答
avatar
test
2024-07-09

恕我直言啊,你把这个token存session里没啥意义啊。

  1. 首先呢,这个token有效期为2个小时,也就是7200秒,那么你这120秒也降低不了多少请求。
  2. 你存session里,那么如果有1000个用户在线,你就要给1000个用户请求这个token并存进去,你这个请求数也降不下来啊。

另外呢,你这个if else判断,那么第一次没有access_token的时候,只执行access_token获取逻辑,然后根本不走业务代码的(参见else)里的逻辑;如果有session里有access_token才走业务逻辑;抛开以上不谈,正常人的做法不应该是:

  1. 如果没有access_token,请求access_token,然后继续执行业务逻辑;
  2. 如果有access_token,直接走业务逻辑就行了,也就是说只要加一个判断if(empty($_SESSION['access_token']) || $_SESSION['expire_time'] <= time() )然后取access_token就行了啊,根本不需要else

另外呢,你没有redis之类的缓存,还不如直接用文件缓存,所有用户用这个access_token就行,然后没隔7000秒(小于2小时,但是缓存时间又足够用,避免生成需要时间)。缓存的文件里的数据格式为都给你想好了:

cache_time access_token

然后读取这个文件,之后,把这文件里的这行数据:[$cacheTime, $accessToken] = explode(' ', $str);切割之后就能拿到上次生成时间,校验一下不过期就不重新取,另外这个文件里的字符为空就重新取(相当于初始化)。

另外这个文件缓存,为了防止并发读写错误,加上一个文件锁就行:flock;读的时候首先flock($filename,LOCK_SH);写的时候加一个写锁:flock($filename,LOCK_EX);

当然了,最好的方式是写一个定时脚本,每间隔7000秒更新一下这个文件里的数据,这样从根源上解决并发写的问题,至于读的话问题不大。

不过正常项目来说都是用定时任务执行脚本获取后把这个access_token放到redismemcached啊这种缓存里。

回复
likes
适合作为回答的
  • 经过验证的有效解决办法
  • 自己的经验指引,对解决问题有帮助
  • 遵循 Markdown 语法排版,代码语义正确
不该作为回答的
  • 询问内容细节或回复楼层
  • 与题目无关的内容
  • “赞”“顶”“同问”“看手册”“解决了没”等毫无意义的内容