PHP 服务器CPU飙升排查工具

1.使用top查询出占用资源最高的程序和pid

[root@VM-12-9-centos ~]# top
top - 10:34:51 up 151 days, 14:46,  4 users,  load average: 7.88, 8.00, 8.13
Tasks: 198 total,   8 running, 190 sleeping,   0 stopped,   0 zombie
%Cpu(s): 20.0 us, 79.8 sy,  0.0 ni,  0.1 id,  0.0 wa,  0.0 hi,  0.1 si,  0.0 st
KiB Mem :  8008644 total,   211792 free,  3804488 used,  3992364 buff/cache
KiB Swap:        0 total,        0 free,        0 used.  3859032 avail Mem 
PID to signal/kill [default pid = 8817] ill -9 
  PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND                                                                                                             
 8817 root      20   0  250904  33572   2688 R   3.0  0.4   6287:50 php                                                                                                                 
 9552 root      20   0  248128  34480   6296 S   2.7  0.4   5596:32 php                                                                                                                 
 9562 root      20   0  248128  34480   6296 S   2.7  0.4   5451:31 php                                                                                                                 
 9554 root      20   0  248128  34480   6296 S   2.3  0.4   5505:47 php                                                                                                                 
 9564 root      20   0  248128  34484   6296 S   2.3  0.4   5345:03 php                                                                                                                 
 3297 root      20   0  993820  77192  18748 S   1.3  1.0 140:27.37 YDService                                                                                                           
12284 root      20   0  156856   5616   4272 R   1.0  0.1   0:00.13 sshd                                                                                                                
15865 root      20   0  126348   1220   1008 R   1.0  0.0   0:00.14 strace                                                                                                              
17619 root      20   0  842824  19204   3068 S   1.0  0.2   2237:00 barad_agent                                                                                                         
27958 root      20   0  787048  86856  15340 S   0.7  1.1   0:40.60 BT-Panel                                                                                                            
 4473 root      20   0 1070600  13988   6592 S   0.3  0.2   1:49.62 YDLive                                                                                                              
28200 root      20   0 1384064  20300   6200 S   0.3  0.3   1:38.29 BT-Task                                                                                                             
    1 root      20   0   51916   4000   2456 S   0.0  0.0  43:41.89 systemd                                                                                                             
    2 root      20   0       0      0      0 S   0.0  0.0   0:07.34 kthreadd                                                                                                            
    4 root       0 -20       0      0      0 S   0.0  0.0   0:00.00 kworker/0:0H                                                                                                        
    6 root      20   0       0      0      0 S   0.0  0.0  60:43.14 ksoftirqd/0                                                                                                         
    7 root      rt   0       0      0      0 S   0.0  0.0   0:34.60 migration/0                                                                                                         
    8 root      20   0       0      0      0 S   0.0  0.0   0:00.04 rcu_bh                                                                                                              
    9 root      20   0       0      0      0 S   0.0  0.0 381:47.98 rcu_sched                                                                                                           
   10 root       0 -20       0      0      0 S   0.0  0.0   0:00.00 lru-add-drain                                                                                                       
   11 root      rt   0       0      0      0 S   0.0  0.0   3:03.63 watchdog/0                                                                                                          
   12 root      rt   0       0      0      0 S   0.0  0.0   3:04.37 watchdog/1                                                                                                          
   13 root      rt   0       0      0      0 S   0.0  0.0   0:35.39 migration/1                                                                                                         
   14 root      20   0       0      0      0 R   0.0  0.0  57:27.61 ksoftirqd/1                                                                                                         
   16 root       0 -20       0      0      0 S   0.0  0.0   0:00.00 kworker/1:0H                                                                                                        
   17 root      rt   0       0      0      0 S   0.0  0.0   3:02.59 watchdog/2                                                                                                          
   18 root      rt   0       0      0      0 S   0.0  0.0   0:35.17 migration/2                                                                                                         
   19 root      20   0       0      0      0 S   0.0  0.0  57:48.05 ksoftirqd/2                                                                                                         
   21 root       0 -20       0      0      0 S   0.0  0.0   0:00.00 kworker/2:0H                                                                                                        
   22 root      rt   0       0      0      0 S   0.0  0.0   3:10.39 watchdog/3                                                                                                          
   23 root      rt   0       0      0      0 S   0.0  0.0   0:34.69 migration/3                                                                                                         
   24 root      20   0       0      0      0 S   0.0  0.0  59:06.12 ksoftirqd/3                                                                                                         
   26 root       0 -20       0      0      0 S   0.0  0.0   0:00.00 kworker/3:0H                                                                                                        
   28 root      20   0       0      0      0 S   0.0  0.0   0:00.00 kdevtmpfs                                                                                                           
   29 root       0 -20       0      0      0 S   0.0  0.0   0:00.00 netns                                                                                                               
   30 root      20   0       0      0      0 S   0.0  0.0   0:07.67 khungtaskd        

可以看到我前面的基本都是PHP程序

2.通过srrace -p PID 跟踪指定pid的系统调用及其接收的信号

root@VM-12-9-centos ~]# strace -p 8817
strace: Process 8817 attached
wait4(-1, [{WIFEXITED(s) && WEXITSTATUS(s) == 255}], WSTOPPED, NULL) = 15863
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=15863, si_uid=0, si_status=255, si_utime=0, si_stime=1} ---
lstat("/www/wwwroot/jys.bolinshe.com/service/vendor/workerman/workerman/../workerman.log", 0x7ffc3c6f0af0) = -1 ENOENT (No such file or directory)
lstat("/www/wwwroot/jys.bolinshe.com/service/vendor/workerman/workerman", 0x7ffc3c6f0820) = -1 ENOENT (No such file or directory)
lstat("/www/wwwroot/jys.bolinshe.com/service/vendor/workerman", 0x7ffc3c6f06a0) = -1 ENOENT (No such file or directory)
lstat("/www/wwwroot/jys.bolinshe.com/service/vendor", 0x7ffc3c6f0520) = -1 ENOENT (No such file or directory)
lstat("/www/wwwroot/jys.bolinshe.com/service", 0x7ffc3c6f03b0) = -1 ENOENT (No such file or directory)
open("/www/wwwroot/jys.bolinshe.com/service/vendor/workerman/workerman.log", O_WRONLY|O_CREAT|O_APPEND, 0666) = -1 ENOENT (No such file or directory)
fstat(1, {st_mode=S_IFCHR|0666, st_rdev=makedev(1, 3), ...}) = 0
ioctl(1, TCGETS, 0x7ffc3c6f3690)        = -1 ENOTTY (Inappropriate ioctl for device)
write(1, "file_put_contents(/www/wwwroot/j"..., 248) = 248
clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f779ac30a10) = 15874
wait4(-1, [{WIFEXITED(s) && WEXITSTATUS(s) == 255}], WSTOPPED, NULL) = 15874
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=15874, si_uid=0, si_status=255, si_utime=0, si_stime=1} ---
lstat("/www/wwwroot/jys.bolinshe.com/service/vendor/workerman/workerman/../workerman.log", 0x7ffc3c6f0af0) = -1 ENOENT (No such file or directory)
lstat("/www/wwwroot/jys.bolinshe.com/service/vendor/workerman/workerman", 0x7ffc3c6f0820) = -1 ENOENT (No such file or directory)
lstat("/www/wwwroot/jys.bolinshe.com/service/vendor/workerman", 0x7ffc3c6f06a0) = -1 ENOENT (No such file or directory)
lstat("/www/wwwroot/jys.bolinshe.com/service/vendor", 0x7ffc3c6f0520) = -1 ENOENT (No such file or directory)
lstat("/www/wwwroot/jys.bolinshe.com/service", 0x7ffc3c6f03b0) = -1 ENOENT (No such file or directory)
open("/www/wwwroot/jys.bolinshe.com/service/vendor/workerman/workerman.log", O_WRONLY|O_CREAT|O_APPEND, 0666) = -1 ENOENT (No such file or directory)
fstat(1, {st_mode=S_IFCHR|0666, st_rdev=makedev(1, 3), ...}) = 0
ioctl(1, TCGETS, 0x7ffc3c6f3690)        = -1 ENOTTY (Inappropriate ioctl for device)
write(1, "file_put_contents(/www/wwwroot/j"..., 248) = 248

发现是这个站点的workerman导致的
3.先kill掉进程,恢复服务器性能,在到站点排查具体的问题

另外:如果是Java程序有大厂开发的 arthas 工具,可以找到Java程序具体第几行出现问题

PHP调试函数

  • 该函数可以替代var_dump
  • 每次使用会输出调用地址
function ds($val,...$param) {
    $call_info = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
    if (isset($call_info[0]['file'])) {
        $call_info = "{$call_info[0]['file']} | {$call_info[0]['line']}";
    }else{
        $call_info = '';
    }

    echo "<font size='1'>{$call_info}</font>";
    echo "<pre>";
    dump($val,...$param);
    echo "</pre>";
    exit("exit ^");
}

PHP日志记录函数2

//创建日志保存所需目录
function make_dir($folder)
{
    $reval = false;
    if(!file_exists($folder))
    {
        /* 如果目录不存在则尝试创建该目录 */
        @umask(0);
        /* 将目录路径拆分成数组 */
        preg_match_all('/([^\/]*)\/?/i', $folder, $atmp);
        /* 如果第一个字符为/则当作物理路径处理 */
        $base = ($atmp[0][0] == '/') ? '/' : '';
        /* 遍历包含路径信息的数组 */
        foreach ($atmp[1] AS $val)
        {
            if ('' != $val)
            {
                $base .= $val;
                if ('..' == $val || '.' == $val)
                {
                    /* 如果目录为.或者..则直接补/继续下一个循环 */
                    $base .= '/';
                    continue;
                }
            }
            else
            {
                continue;
            }
            $base .= '/';
            if (!file_exists($base))
            {
                /* 尝试创建目录,如果创建失败则继续循环 */
                if (@mkdir(rtrim($base, '/'), 0777))
                {
                    @chmod($base, 0777);
                    $reval = true;
                }
            }
        }
    }
    else
    {
        /* 路径已经存在。返回该路径是不是一个目录 */
        $reval = is_dir($folder);
        /** 如果是文件夹,则强制改为0777 **/
        if($reval){ @chmod($folder, 0777); }
    }
    clearstatcache();
    return $reval;
}
//生成日志文件,并设置权限777
function chmod_custom($filename, $mode = 0777)
{
    return file_exists($filename)? chmod($filename, $mode) : FALSE;
}

//写入日志
function log_message($level = 'error', $message, $dir_path = '', $file_affix = '')
{
    // 验证允许记录的日志类型
    $level = strtoupper($level);

    $dir_path = trim($dir_path);
    $dir_path = storage_path("logs/{$dir_path}");
    // 如果创建文件夹失败,则返回FALSE
    
    if(!make_dir($dir_path)){
        return FALSE;
    }

    $cache_file_path = $dir_path . '/' . $file_affix. '.log';
    /** 如果文件已存在,则强制改为可写状态 **/
    chmod_custom($cache_file_path, 0777);
    $message =  $level . ' - ' . date('Y-m-d H:i:s') . ' --> ' . $message . "\r\n";
    return file_put_contents($cache_file_path, $message, FILE_APPEND | LOCK_EX);
}

PHP 表格导入时间字段处理

使用 PhpOffice 导入 2020/1/1 这类的格式 的时候 最终获取到的 是 45000 类的数字,要将数组转为实际的日期

在excel中:40847对应2011-10-31,是日期的数值型表现形式。
在PHP中,echo date('Y-m-d H:i:s',40847);//结果1970-01-01 11:52:30

原因:

PHP 的时间函数是从1970-1-1日开始计算的,单位是秒数。但是 EXCEL的是从1900-1-1日开始算的单位是天数。
如果只计算1970以后的时间的话,就好处理了。
先获得 EXCEL中 1970-1-1 代表的数字,我查了是25569。
现在要把excel中的40947,在php中用函数正确的显示出来
代码如下:

  $time = (42747 – 25569) * 24*60*60; //获得秒数
  echo date('Y-m-d', $time);   //出来 2020-01-31

解决TP5在命令行创建文件没有权限写入的方法

例如workerman指定user为www运行
在cli模式下创建的文件是root权限的,无法写入log导致程序无法执行

找到 thinkphp\library\think\log\driver\File.php 文件
write 方法中 最后一行添加以下代码

try {
//判断操作文件不是0777权限 就修改
if (substr(base_convert(fileperms($destination),10,8),-4) != '0777') {
  chmod($destination, 0777);
}
            
} catch (\Exception $e) {

}

php生成 ssl 证书

<?php 
//需要开启 openssl 扩展
$privkeypass = 'qqpp123cqs'; //私钥密码

$config = array(
    "private_key_bits" => 1024,                     //字节数    512 1024  2048   4096 等
    "private_key_type" => OPENSSL_KEYTYPE_RSA,     //加密类型
    // "config" => "D:/phpStudy/PHPTutorial/Apache/conf/openssl.cnf"  //注意 openssl.cnf 文件所在位置
);

$privkeypass = $privkeypass;
$numberofdays = 365;     //有效时长
$cerpath = "./test.cer"; //生成证书路径
$pfxpath = "./test.pfx"; //密钥文件路径

$dn = array(
    "countryName" => "UK",                                  //所在国家
    "stateOrProvinceName" => "Somerset",                    //所在省份
    "localityName" => "Glastonbury",                        //所在城市
    "organizationName" => "The Brain Room Limited",         //注册人姓名
    "organizationalUnitName" => "PHP Documentation Team",   //组织名称
    "commonName" => "Wez Furlong",                          //公共名称
    "emailAddress" => "wez@example.com"                     //邮箱
);

// 生成公钥私钥资源
$res = openssl_pkey_new($config);

// 导出私钥 $priKey
openssl_pkey_export($res, $priKey,null,$config);

//  导出公钥 $pubKey
$pubKey = openssl_pkey_get_details($res);
$pubKey = $pubKey["key"];
//print_r($priKey); 私钥
//print_r($pubKey); 公钥

//直接测试私钥 公钥
echo '-------------------公私钥加解密-START---------------------','<br>';
$data = '测试公私钥加解密成功!';
// 公钥加密
openssl_public_encrypt($data, $encrypted, $pubKey);
// 私钥解密
openssl_private_decrypt($encrypted, $decrypted, $priKey);

echo '公钥加密:',base64_encode($encrypted),'私钥解密:','<br>',$decrypted,'<br>';
echo '-------------------公私钥加解密-END---------------------','<br>';

//生成文件
$csr = openssl_csr_new($dn, $priKey,$config); //基于$dn生成新的 CSR (证书签名请求)
$sscert = openssl_csr_sign($csr, null, $priKey, 365,$config);//根据配置自己对证书进行签名
openssl_x509_export($sscert, $csrkey); //将公钥证书存储到一个变量 $csrkey,由 PEM 编码格式命名。
openssl_pkcs12_export($sscert, $privatekey, $priKey, $privkeypass); //将私钥存储到名为的出 PKCS12 文件格式的字符串。 导出密钥$privatekey

//生成证书文件
$fp = fopen($cerpath, "w");
fwrite($fp, $csrkey);
fclose($fp);
//生成密钥文件
$fp = fopen($pfxpath, "w");
fwrite($fp, $privatekey);
fclose($fp);


echo '<br>','<br>','<br>','<br>';
echo '----------------------自签名验证-START----------------------','<br>';
// 测试私钥 秘钥
$privkeypass = $privkeypass; //私钥密码
$pfxpath = "./test.pfx"; //密钥文件路径
$priv_key = file_get_contents($pfxpath); //获取密钥文件内容
$data = "测试数据!"; //加密数据测试test
//私钥加密
openssl_pkcs12_read($priv_key, $certs, $privkeypass); //读取公钥、私钥
$prikeyid = $certs['pkey']; //私钥
openssl_sign($data, $signMsg, $prikeyid,OPENSSL_ALGO_SHA1); //注册生成加密信息
$signMsg = base64_encode($signMsg); //base64转码加密信息


//公钥解密
$unsignMsg=base64_decode($signMsg);//base64解码加密信息
openssl_pkcs12_read($priv_key, $certs, $privkeypass); //读取公钥、私钥
$pubkeyid = $certs['cert']; //公钥
$res = openssl_verify($data, $unsignMsg, $pubkeyid); //验证
echo $res?'证书测试成功!':'证书测试失败!';echo '<br>'; //输出验证结果,1:验证成功,0:验证失败

echo '-----------------------签名验证-END------------------------','<br>';








function sha1_thumbprint($file)
 {
    $file = preg_replace('/\-+BEGIN CERTIFICATE\-+/','',$file);
    $file = preg_replace('/\-+END CERTIFICATE\-+/','',$file);
    $file = trim($file);
    $file = str_replace( array("\n\r","\n","\r"), '', $file);
    $bin = base64_decode($file);
    return sha1($bin);
 }

$fingerprint = str_replace("SHA1 Fingerprint=", '', system('openssl x509 -noout -in /path/to/your/cert.pem -fingerprint'));

//查看sha1指纹
var_dump(sha1_thumbprint(file_get_contents('./test.cer')));

php批量检测文件bom头

有时候在ajax返回的json数据前多出一些不明的字符,就是所谓的bom头,导致javascript解析json格式失败,下面贴出一段PHP代码实现检测和去除bom头。

<?php
header('content-Type: text/html; charset=utf-8');
if (isset($_GET['dir'])) { //设置文件目录,如果没有设置,则自动设置为当前文件所在目录
    $basedir = $_GET['dir'];
} else {
    $basedir = '.';
}
$auto = 0;/*设置为1标示检测BOM并去除,设置为0标示只进行BOM检测,不去除*/

echo '当前查找的目录为:' . $basedir . '当前的设置是:';
echo $auto ? '检测文件BOM同时去除检测到BOM文件的BOM<br />' : '只检测文件BOM不执行去除BOM操作<br />';

checkdir($basedir);
function checkdir($basedir)
{
    if ($dh = opendir($basedir)) {
        while (($file = readdir($dh)) !== false) {
            if ($file != '.' && $file != '..') {
                if (!is_dir($basedir . '/' . $file)) {
                    echo '文件: ' . $basedir . '/' . $file . checkBOM($basedir . '/' . $file) . ' <br>';
                } else {
                    $dirname = $basedir . '/' . $file;
                    checkdir($dirname);
                }
            }
        }
        closedir($dh);
    }
}

function checkBOM($filename)
{
    global $auto;
    $contents = file_get_contents($filename);
    $charset[1] = substr($contents, 0, 1);
    $charset[2] = substr($contents, 1, 1);
    $charset[3] = substr($contents, 2, 1);
    if (ord($charset[1]) == 239 && ord($charset[2]) == 187 && ord($charset[3]) == 191) {
        if ($auto == 1) {
            $rest = substr($contents, 3);
            rewrite($filename, $rest);
            return (' <font color=red>找到BOM并已自动去除</font>');
        } else {
            return (' <font color=red>找到BOM</font>');
        }
    } else {
        return (' 没有找到BOM');
    }
}

function rewrite($filename, $data)
{
    $filenum = fopen($filename, 'w');
    flock($filenum, LOCK_EX);
    fwrite($filenum, $data);
    fclose($filenum);
}

PHP图片按等比压缩

/**
        * desription 压缩图片
        * @param sting $imgsrc 图片路径
        * @param string $imgdst 压缩后保存路径
        */
    public function compressedImage($imgsrc, $imgdst) {
        list($width, $height, $type) = getimagesize($imgsrc);
        $new_width = $width; //压缩后的图片宽
        $new_height = $height; //压缩后的图片高
        if ($width >= 600) {
            $per = 600 / $width; //计算比例
            $new_width = $width * $per;
            $new_height = $height * $per;
        }
        switch ($type) {
        case 1:
            $giftype = check_gifcartoon($imgsrc);
            if ($giftype) {
                header('Content-Type:image/gif');
                $image_wp = imagecreatetruecolor($new_width, $new_height);
                $image = imagecreatefromgif($imgsrc);
                imagecopyresampled($image_wp, $image, 0, 0, 0, 0, $new_width, $new_height, $width, $height);
                            //90代表的是质量、压缩图片容量大小
                imagejpeg($image_wp, $imgdst, 90);
                imagedestroy($image_wp);
                imagedestroy($image);
            }
            break;
        case 2:
            header('Content-Type:image/jpeg');
            $image_wp = imagecreatetruecolor($new_width, $new_height);
            $image = imagecreatefromjpeg($imgsrc);
            imagecopyresampled($image_wp, $image, 0, 0, 0, 0, $new_width, $new_height, $width, $height);
                     //90代表的是质量、压缩图片容量大小
            imagejpeg($image_wp, $imgdst, 90);
            imagedestroy($image_wp);
            imagedestroy($image);
            break;
        case 3:
            header('Content-Type:image/png');
            $image_wp = imagecreatetruecolor($new_width, $new_height);
            $image = imagecreatefrompng($imgsrc);
            imagecopyresampled($image_wp, $image, 0, 0, 0, 0, $new_width, $new_height, $width, $height);
                     //90代表的是质量、压缩图片容量大小
            imagejpeg($image_wp, $imgdst, 90);
            imagedestroy($image_wp);
            imagedestroy($image);
            break;
        }
    }

微信公众号授权H5登录

第一步

进入微信公众号管理中心配置可信域名和回调域名以及服务器IP白名单

第二步

composer 安装 easywechat

第三步

    //发起授权地址
    public function warranty()
    {
        $config = [
            'app_id' => 'app_id',
            'secret' => 'secret',
            'response_type' => 'array',
        ];
        $app = Factory::officialAccount($config);
        /*return $app->oauth->scopes(['snsapi_userinfo'])->redirect(cdnurl('/visitor_api/user/login',true));*/
        //或者以下方法
        $oauth = $app->oauth;
        $oauth->redirect('您的回调地址')->send();
    }



   //授权成功后的回调地址
    public function login()
    {
        $config = [
            'app_id' => 'app_id',
            'secret' => 'secret',
            'response_type' => 'array',
        ];

        $app = Factory::officialAccount($config);
        $oauth = $app->oauth;
        // 获取 OAuth 授权结果用户信息
        $user = $oauth->user();
        
        dump($user);//打印用户信息 - 参见第四步
   }

第四步(处理用户信息)


object(Overtrue\Socialite\User)#134 (1) {
  ["attributes":protected] => array(10) {
    ["id"] => string(28) "o7Dzs337bEPl_pg886oVTgrab6Wg"
    ["name"] => string(12) "岁暮天寒"
    ["nickname"] => string(12) "岁暮天寒"
    ["avatar"] => string(132) "https://thirdwx.qlogo.cn/mmopen/vi_32/Q0j4TwGTfTLBVGiayuTS7ptprfHtSfwD43iaXY1Akkz27vq4qNPdxrESAxb9pHwXktCSibH6kE6Tia1RMtZrjgKfag/132"
    ["email"] => NULL
    ["original"] => array(10) {
      ["openid"] => string(28) "o7Dzs337bEPl_pg886oVTgrab6Wg"
      ["nickname"] => string(12) "岁暮天寒"
      ["sex"] => int(1)
      ["language"] => string(5) "zh_CN"
      ["city"] => string(6) "杭州"
      ["province"] => string(6) "浙江"
      ["country"] => string(6) "中国"
      ["headimgurl"] => string(132) "https://thirdwx.qlogo.cn/mmopen/vi_32/Q0j4TwGTfTLBVGiayuTS7ptprfHtSfwD43iaXY1Akkz27vq4qNPdxrESAxb9pHwXktCSibH6kE6Tia1RMtZrjgKfag/132"
      ["privilege"] => array(0) {
      }
      ["unionid"] => string(28) "ogN8NwK3ZHykG2tVtXHoG9oUEm_w"
    }
    ["token"] => string(89) "46_eD_Ghm0AfLLh54gdDTmvbN-7uIHweXCJbShx5OeBp_skNaPhArO_nEhi3yHJ2gQJK-Yfuk-hsX9vOg6K2AH_BQ"
    ["access_token"] => string(89) "46_eD_Ghm0AfLLh54gdDTmvbN-7uIHweXCJbShx5OeBp_skNaPhArO_nEhi3yHJ2gQJK-Yfuk-hsX9vOg6K2AH_BQ"
    ["refresh_token"] => string(89) "46_dv6nwCx5q3OLoaPtVMIuTiMREHZGcEV9tY2y5uqkjumHNDUC_6dvCZSxGRQ8fyo5XqdpqMtrRXNjyzN9a73oyQ"
    ["provider"] => string(6) "WeChat"
  }
}object(Overtrue\Socialite\User)#134 (1) {
  ["attributes":protected] => array(10) {
    ["id"] => string(28) "o7Dzs337bEPl_pg886oVTgrab6Wg"
    ["name"] => string(12) "岁暮天寒"
    ["nickname"] => string(12) "岁暮天寒"
    ["avatar"] => string(132) "https://thirdwx.qlogo.cn/mmopen/vi_32/Q0j4TwGTfTLBVGiayuTS7ptprfHtSfwD43iaXY1Akkz27vq4qNPdxrESAxb9pHwXktCSibH6kE6Tia1RMtZrjgKfag/132"
    ["email"] => NULL
    ["original"] => array(10) {
      ["openid"] => string(28) "o7Dzs337bEPl_pg886oVTgrab6Wg"
      ["nickname"] => string(12) "岁暮天寒"
      ["sex"] => int(1)
      ["language"] => string(5) "zh_CN"
      ["city"] => string(6) "杭州"
      ["province"] => string(6) "浙江"
      ["country"] => string(6) "中国"
      ["headimgurl"] => string(132) "https://thirdwx.qlogo.cn/mmopen/vi_32/Q0j4TwGTfTLBVGiayuTS7ptprfHtSfwD43iaXY1Akkz27vq4qNPdxrESAxb9pHwXktCSibH6kE6Tia1RMtZrjgKfag/132"
      ["privilege"] => array(0) {
      }
      ["unionid"] => string(28) "ogN8NwK3ZHykG2tVtXHoG9oUEm_w"
    }
    ["token"] => string(89) "46_eD_Ghm0AfLLh54gdDTmvbN-7uIHweXCJbShx5OeBp_skNaPhArO_nEhi3yHJ2gQJK-Yfuk-hsX9vOg6K2AH_BQ"
    ["access_token"] => string(89) "46_eD_Ghm0AfLLh54gdDTmvbN-7uIHweXCJbShx5OeBp_skNaPhArO_nEhi3yHJ2gQJK-Yfuk-hsX9vOg6K2AH_BQ"
    ["refresh_token"] => string(89) "46_dv6nwCx5q3OLoaPtVMIuTiMREHZGcEV9tY2y5uqkjumHNDUC_6dvCZSxGRQ8fyo5XqdpqMtrRXNjyzN9a73oyQ"
    ["provider"] => string(6) "WeChat"
  }
}

PHP日志记录函数



function logs($message,$data,$file_name = '',$path = 'work/'){
    if(is_array($data)){
        $data = json_encode($data,JSON_UNESCAPED_UNICODE);
    }elseif(is_object($data)) {
        $data = print_r($data,true);
    }else{
        $type = gettype($data);
        if ($type != 'string') {
            $data = var_export($data,true);
        }
    }
    
    
    

    if ($file_name == '') {
        $file_name = date('Y-m-d').'.log';
    }else{
        $date = date('Y-m-d');
        $file_name = "{$file_name}_{$date}.log";
    }

    $path = app()->getRuntimePath().$path;//tp6
    //$path = RUNTIME_PATH.$path;//tp5

    if (!is_dir($path)) {
        mkdir($path);
    }

    $date = date('Y-m-d H:i:s');
    $file_name = $path.$file_name;
    $text = $date.' '.$message . ' -> '.$data.PHP_EOL;
    file_put_contents($file_name,$text,FILE_APPEND);
}