//创建日志保存所需目录
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);
}
MySQL死锁排查
查询正打开的表
show OPEN TABLES where In_use > 0;
查询正在进行的进程
show processlist;
查看当前运行的所有事务
select * from information_schema.INNODB_TRX;
查看存储引擎的状态
show engine innodb status
查询死锁表
-- 查询死锁表 8.0之前
SELECT * from INFORMATION_SCHEMA.INNODB_LOCKS;
-- 查询死锁等待时间 8.0之前
select * from information_schema.INNODB_LOCK_waits;
-- 查询死锁表 8.0之后
select * from performance_schema.data_locks;
-- 查询死锁等待时间 8.0之后
select * from performance_schema.data_lock_waits;
编写shell脚本快速切换PHP版本
由于我是在windows的wsl搭建的PHP环境,包括7.3、7.4、8.0多个PHP版本,测试的时候,有的程序需要某个版本才能运行,手动创建环境变量太麻烦,于是写了我的第一个shell,于是记录下
#!/bin/bash
#第一次提示
read -p "请输入版本号【7.3】、【7.4】、【8】:" version
#如果未输入,则强制要求输入
while [ ! "$version" ]
do
if [ ! -n "$version" ]; then
read -p "必须输入版本号【7.3】、【7.4】、【8】:" version
fi
done
#先删除现在的环境
rm -rf /usr/bin/php
rm -rf /usr/bin/phpize
rm -rf /usr/bin/php-fpm
#根据输入的版本号创建新的环境变量
case $version in
7.3)
#echo "你输入了${version} (7.3 对吗?)"
ln -s /usr/local/php/bin/php /usr/bin/php
ln -s /usr/local/php/bin/phpize /usr/bin/phpize
ln -s /usr/local/php/sbin/php-fpm /usr/bin/php-fpm
;;
7.4)
#echo "你输入了${version}(7.4对吗)"
ln -s /usr/php/74/bin/php /usr/bin/php
ln -s /usr/php/74/bin/phpize /usr/bin/phpize
ln -s /usr/php/74/sbin/php-fpm /usr/bin/php-fpm
;;
8)
#echo "你输入了${version}(8对吗)"
ln -s /usr/local/php8/bin/php /usr/bin/php
ln -s /usr/local/php8/bin/phpize /usr/bin/phpize
ln -s /usr/local/php8/sbin/php-fpm /usr/bin/php-fpm
;;
*)
echo "当前系统未安装此版本号的PHP,无法切换"
;;
esac
#检查下是否成功切换
echo "你已成功切换到${version}"![微信截图_20211029113209.png][1]
echo "======================================================"
php -v
echo "======================================================"
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"
}
}
杀掉程序
fuser -k 443/tcp