至尊技术网 https://www.zzwws.cn/ 专注活动、软件、源码、教程,乐于分享! php curl无法获得https网页内容 https://www.zzwws.cn/archives/6415/ 2024-01-05T19:14:00+08:00 程序员最经常使用的curl,在php下面也是经常用的到。但是,博主友情提示您:用curl获取https的网页内容的时候,也是需要用到证书的。而这么多年,估计大家从来都没有察觉过任何更新证书的动作,证明这可能是有自动renew操作的。而目前博主手头的centos系统,却存在有使用curl无法获取https内容的问题。利用curl或者file_get_contents获取远程http的内容时,成功。但是获取https的内容时,失败。错误提示文字类似于:SSL operation failed with code 1. OpenSSL Error messages: error:14090086: SSL routines:ssl3_get_server_certificate:certificate vertify failed 解决方法1、保证php.ini里面的openssl扩展肯定要打开。这个操作比较基础,不做赘述。extension=openssl.so 2、查看一下openssl证书的默认位置,检测openssl的证书位置的代码:php -r "print_r(openssl_get_cert_locations());" default_cert_file是默认位置。3、下载更新证书下载网址:https://curl.haxx.se/docs/caextract.html选择一个最新的perm证书下载即可,下载好的证书要放置在上述默认位置或者自定义好的位置,重启php后,就应该可以解决问题了。 使用fail2ban防止ssh爆破 https://www.zzwws.cn/archives/6411/ 2024-01-04T15:20:00+08:00 fail2ban 是一个更加强大和灵活的工具,它可以监控多种日志文件,并根据用户自定义的规则进行拉黑。例如,可以监控 SSH、FTP、Apache 等服务的日志文件,根据设定的规则来判断恶意访问行为,如登录失败、多次访问不存在的 URL、频繁访问等,然后自动拉黑恶意 IP 地址。fail2ban 的优点是功能强大,可以对多种恶意行为进行处理;缺点是配置比较繁琐,需要用户自定义规则,并且可能会误判合法访问。Fail2ban目录结构如下:/etc/fail2ban/action.d ----- iptables 、mail 等动作文件目录/etc/fail2ban/fail2ban.conf ----- 定义日志级别、日志、sock文件位置等/etc/fail2ban/filter.d ----- 条件匹配(过滤器)文件目录,过滤日志关键内容/etc/fail2ban/jail.conf ----- 主配置文件,主要设置启用ban动作的服务及动作阀值,不建议修改/etc/fail2ban/jail.d/ ----- fail2ban模块化子配置文件安装fail2banepel_release源安装fail2ban# 安装epel_release源 yum install -y epel-release # 建立缓存 yum makecache # 安装fail2ban yum install -y fail2ban fail2ban-firewalld fail2ban-systemd # Centos7支持tcpd,需要安装fail2ban-hostsdeny yum install -y fail2ban-hostsdeny # 现在启动并开机自启 systemctl enable --now fail2ban 源码安装fail2ban版本 1.0/0.11/0.10(和旧的 0.9)将仍然基于 python2.7版本1.01及以后以后使用python3# 安装sqlite3 yum install -y sqlite # 安装依赖 yum install -y python2 python3 # 下载Fail2ban源码 wget -c https://github.com/fail2ban/fail2ban/archive/refs/tags/1.0.2.tar.gz # 解压Fail2ban tar xvf 1.0.2.tar.gz # 进入解压后的Fail2ban目录 cd fail2ban-1.0.2 # 安装Fail2ban python3 setup.py install --record fail2ban_install.log # 如果是1.0以下低版本,请使用python2安装 python2 setup.py install --record fail2ban_install.log #复制fail2ban服务脚本 cp /root/fail2ban-1.0.2/files/redhat-initd  /etc/init.d/fail2ban #设置fail2ban服务为自启动服务 systemctl enable fail2ban  #启动fail2ban服务 systemctl start fail2ban # 卸载Fail2ban cat fail2ban_install.log | xargs rm -rf 全局配置白名单IP(非必须)vim /etc/fail2ban/filter.d/jail.local # 全局配置 [DEFAULT] # 要忽略的 IP 地址。 IP 地址列表可以使用 CIDR 表示法 ignoreip = 10.0.0.0/24 # 封禁IP时间(以秒为单位)。负数-1为“永久”禁止 ## 86400秒=1天 bantime = 86400 findtime = 300 maxretry = 5 # banaction = iptables-multiport backend = systemd 子配置启用sshd保护策略vim /etc/fail2ban/jail.d/sshd_jail.local [sshd] # 启用防护 enabled = true # 选择过滤器 filter = sshd # 启用抗攻击防护模式--防护策略敏感度最高 # 正常(默认)、ddos、额外或 aggressive (攻击性 全部组合)。 ## normal (default), ddos, extra or aggressive (combines all). # 有关使用示例和详细信息,请参阅“tests/files/logs/sshd”或“filter.d/sshd.conf”。 mode = aggressive # 禁止 IP 的持续时间(以秒为单位)。负数-1为“永久”禁止。 ## 86400秒为1天 bantime = 86400 ## 如果在“findtime”秒内未找到匹配,则计数器设置为零。默认 600s findtime = 300 # ssh登录失败阈值默认为 3 maxretry = 5 # 指定封禁的端口,默认为0:65535,也就是所有端口,但可以在jail中设定 port = ssh # 使用哪个工具方法阻止IP ## firewall防火墙: firewallcmd-ipset ## iptables防火墙: iptables 或 iptables-multiport ## 拉黑到/etc/hosts.deny: hostsdeny banaction = iptables-multiport hostsdeny # 日志路径 logpath = %(sshd_log)s # 指定用于修改日志文件的后端 #backend = %(sshd_backend)s backend = systemd 常用命令# 启动Fail2ban systemctl start fail2ban # Fail2ban设置为开机自启动 systemctl enable fail2ban # 重新加载配置或重启服务 systemctl reload-or-restart fail2ban.service # 查看服务是否正常运行 systemctl status fail2ban.service -l # 查看哪些IP被ban fail2ban-client status sshd # 将IP从黑名单中移除 fail2ban-client set sshd unbanip 8.8.8.8 # 将IP添加到黑名单中 fail2ban-client set sshd banip 8.8.8.8 # 清空黑名单 fail2ban-client unban --all uni-app 安卓锁屏后程序后台运行 https://www.zzwws.cn/archives/6410/ 2023-06-27T21:42:00+08:00 借助安卓的WakeLock机制,我们可以实现让APP在后台运行。实现代码如下:var g_wakelock = null; //允许程序后台运行 function wakeLock() { var main = plus.android.runtimeMainActivity(); var Context = plus.android.importClass("android.content.Context"); var PowerManager = plus.android.importClass("android.os.PowerManager"); var pm = main.getSystemService(Context.POWER_SERVICE); g_wakelock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ANY_NAME"); g_wakelock.acquire(); } //结束程序后台运行 function releaseWakeLock() { if(g_wakelock != null && g_wakelock.isHeld()) { g_wakelock.release(); g_wakelock = null; } } 在需要允许后台运行的时候调用wakeLock(),在希望停止的时候调用releaseWakeLock()只需要程序后台运行,放到App.vue里的onLaunchvar g_wakelock = null; var main = plus.android.runtimeMainActivity(); var Context = plus.android.importClass("android.content.Context"); var PowerManager = plus.android.importClass("android.os.PowerManager"); var pm = main.getSystemService(Context.POWER_SERVICE); g_wakelock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ANY_NAME"); g_wakelock.acquire(); 利用node.js反编译脚本获得微信小程序源码 https://www.zzwws.cn/archives/6408/ 2023-06-19T15:17:00+08:00 一、node.js运行环境1、安装node.js地址:https://nodejs.org/zh-cn/安装后在控制台输入:node -v, 如果显示版本号则安装成功2、安装npm一般情况下nodejs安装好后自带npm可以在控制台输入:npm -v, 如果显示版本号则安装成功。二、下载反编译脚本https://gitee.com/moduo_412/wxappUnpacker三、安装模拟器下载夜神模拟器或其他模拟器安装RE文件管理器,使用解密工具可以不用安装模拟器,找到__APP__.wxapkg,不确定是哪个目录可以把当前目录删除,再重新打开小程序四、在本地找到小程序源文件包/data/data/com.tencent.mm/MicroMsg/一串32位的16进制字符串文件夹/appbrand/pkg/小程序源文件包这个目录下就是你的小程序源文件了,小程序格式就是wxapkg,根据时间找到源文件包压缩后发送到电脑五、反编译解包1、打开nodejs命令窗口2、用cd命令进入反编译脚本根目录下3、在node命令窗口中依次安装如下// 安装 npm install // 安装依赖 npm install esprima npm install css-tree npm install cssbeautify npm install vm2 npm install uglify-es npm install js-beautify 4、安装好依赖之后,就是最后一步了,反编译 .wxapkg 文件在当前目录下输入命令:node wuWxapkg.js _163200311_32.wxapkg_163200311_32.wxapkg是你需要反编译的源文件,输入前几个字符可以按tab键补全在当前目录找到_163200311_32文件夹(如果不是想要的,请换一个.wxapkg文件):5、报错处理Cannot find module 'xxx' 模块未安装运行命令:npm install xxx如果这种错误,请重新换一个.wxapkg文件执行脚本中可能会出现以下报错1、修改wuWxss.js文件31行if (!importCnt[id]) importCnt[id] = 1, statistic(pureData[id]); // 替换为 if(!importCnt[id]){ if(pureData){ importCnt[id]=1; statistic(pureData[id]); } } 2、修改wuWxss.js文件243行pureData = vm.run(code + "\n_C"); // 替换为 pureData = vm.run(code + "}"); uni-app 部署到二级目录,打包H5空白页面或者刷新404 https://www.zzwws.cn/archives/6395/ 2023-04-28T09:37:45+08:00 部署到二级目录打包H5空白页面或者刷新4041、uni-app 打包H5空白页面或者刷新404,加入下面伪静态就可以解决了;2、如果不想分2个域名去配置,想和后端thinkphp代码放在一起的话,可以在后端创建一个H5目录来放前端的文件,增加对应H5目录的伪静态重写规则,就可以正常访问了;3、以下是伪静态的配置。Nginx配置location /h5/ { try_files $uri $uri/ /h5/index.html; } Apache配置在h5目录里增加一个.htaccess文件<IfModule mod_rewrite.c> Options +FollowSymlinks -Multiviews RewriteEngine On RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^(.*)$ /h5/index.html [L] IfModule> 如果单独配置一个前端域名的话,域名指向是h5目录的话,重写规则不需要带/h5 Nginx负载均衡 https://www.zzwws.cn/archives/6393/ 2023-04-12T10:44:00+08:00 1、轮询轮询是upstream模块负载均衡默认的策略,每个请求会按时间顺序逐个被分配到不同的后端服务器。轮询不需要额外的配置。# 代理服务器 # 设置服务器组 upstream backend { server 111.173.115.2:80; server 111.173.115.3:80; server 111.173.115.4:80; } server { listen 80; server_name 111.173.115.1; location / { # backend 就是服务器组的名称 proxy_pass http://backend/; } } 2、weight加权(加权轮询)weight=number:用来设置服务器的权重,默认为1,权重数字越大,被分配到请求的几率越大。该权重值主要是针对实际工作环境中不同的后端服务器硬件配置进行调整的,所有此策略比较适合服务器的硬件配置差别比较大的情况。# 代理服务器 # 设置服务器组 upstream backend { server 111.173.115.2:80 weight=10; server 111.173.115.3:80 weight=8; server 111.173.115.4:80 weight=6; } server { listen 80; server_name 111.173.115.1; location / { # backend 就是服务器组的名称 proxy_pass http://backend/; } } 3、ip_hash当对后端的多台动态应用服务器做负载均衡时,ip_hash指令能够将某个客户端IP的请求通过哈希算法定位到同一台后端服务器上。这样,当来自某一个IP的用户在后端Web服务器A上登录后,再访问该站点的其他URL,能保证其访问的还是后端web服务器A。注意:使用ip_hash指令无法保证后端服务器的负载均衡,可能导致有些后端服务器接收到的请求多,有些后端服务器接受的请求少,而且设置后端服务器权重等方法将不起作用。# 代理服务器 # 设置服务器组 upstream backend { ip_hash; server 111.173.115.2:80; server 111.173.115.3:80; server 111.173.115.4:80; } server { listen 80; server_name 111.173.115.1; location / { # backend 就是服务器组的名称 proxy_pass http://backend/; } } 4、least_connleast_conn:最少连接,把请求转发给连接数较少的后端服务器。轮询算法是把请求平均地转发给各个后端,使它们的负载大致相同;但是,有些请求占用的时间很长,会导致其所在的后端负载较高。这种情况下,least_conn这种方式就可以达到更好的负载均衡效果。# 代理服务器 # 设置服务器组 upstream backend { least_conn; server 111.173.115.2:80; server 111.173.115.3:80; server 111.173.115.4:80; } server { listen 80; server_name 111.173.115.1; location / { # backend 就是服务器组的名称 proxy_pass http://backend/; } } 5、url_hash按访问url的hash结果来分配请求,使每个url定向到同一个后端服务器,要配合缓存命中来使用。同一个资源多次请求,可能会到达不同的服务器上,导致不必要的多次下载,缓存命中率不高,以及一些资源时间的浪费。而使用url_hash,可以使得同一个url(也就是同一个资源请求)会到达同一台服务器,一旦缓存住了资源,再次收到请求,就可以从缓存中读取。# 代理服务器 # 设置服务器组 upstream backend { hash $request_uri; server 111.173.115.2:80; server 111.173.115.3:80; server 111.173.115.4:80; } server { listen 80; server_name 111.173.115.1; location / { # backend 就是服务器组的名称 proxy_pass http://backend/; } } 6、fairfair采用的不是内建负载均衡使用的均衡算法,而是可以根据页面大小、加载时间长短智能地进行负载均衡。那么如何使用第三方模块的fair负载均衡策略?# 代理服务器 # 设置服务器组 upstream backend { fair; server 111.173.115.2:80; server 111.173.115.3:80; server 111.173.115.4:80; } server { listen 80; server_name 111.173.115.1; location / { # backend 就是服务器组的名称 proxy_pass http://backend/; } } 但是如果直接使用会报错,因为fair属于第三方模块实现的负载均衡。需要添加nginx-upstream-fair,如何添加对应的模块:1.下载nginx-upstream-fair模块。https://github.com/gnosek/nginx-upstream-fair2.将下载的文件上传到服务器并进行解压缩。unzip nginx-upstream-fair-master.zip3.重命名资源。mv nginx-upstream-fair-master fair4.使用./configure命令将资源添加到Nginx模块中。./configure --add-module=/root/fair5.编译。make-编译可能会出现如下错误: nginx_http_upstream_srv_conf_t结构中缺少default_port -解决方案 在Nginx的源码中src/http/nginx_http_upstream.h,找到ngx_http_upstream_srv_conf_s,在模块中添加default_port属性:in_port_t default_port 然后再进行make。6.更新Nginx。1、将sbin目录下的nginx进行备份mv /usr/local/nginx/sbin/nginx /usr/local/nginx/sbin/nginxold 2、将安装目录下的objs中的nginx拷贝到sbin目录cd objscp nginx /usr/local/nginx/sbin 3、更新cd ../make upgrade7.编译测试使用Nginx。 ThinkPHP6 excel表导入导出 https://www.zzwws.cn/archives/6389/ 2023-01-03T14:12:00+08:00 composer下载phpspreadsheetcomposer require phpoffice/phpspreadsheet PhpSpreadsheet中文简介phpexcel由于版本陈旧性能低下官方放弃维护,转而开发PhpSpreadsheet用了最新得psr标准因而对php版本不向下兼容需要注意!PhpSpreadsheet是一个用纯PHP编写的库,提供了一组类,使您可以读取和写入不同的电子表格文件格式PhpSpreadsheet提供了丰富的API接口,可以设置诸多单元格以及文档属性,包括样式、图片、日期、函数等等诸多应用,总之你想要什么样的Excel表格,PhpSpreadsheet都能做到使用PhpSpreadsheet开发的PHP要求7.1或更高版本,并且支持链式操作PhpSpreadsheet 支持的文件格式文件路径extend/Excel.php<?php use PhpOffice\PhpSpreadsheet\Cell\Coordinate; use PhpOffice\PhpSpreadsheet\IOFactory; use PhpOffice\PhpSpreadsheet\Spreadsheet; use think\exception\ValidateException; class Excel { /** * 导入excel表格 * @param array $file 文件路径 * @return array|string */ protected function importExcel($file) { try { // 截取后缀 $fileExtendName = substr(strrchr($file, '.'), 1); // 有Xls和Xlsx格式两种 if ($fileExtendName == 'xlsx') { $objReader = IOFactory::createReader('Xlsx'); } else { $objReader = IOFactory::createReader('Xls'); } // 设置文件为只读 $objReader->setReadDataOnly(TRUE); // 读取文件,tp6默认上传的文件,在runtime的相应目录下,可根据实际情况自己更改 $objPHPExcel = $objReader->load($_SERVER['DOCUMENT_ROOT'] . $file); //excel中的第一张sheet $sheet = $objPHPExcel->getSheet(0); // 取得总行数 $highestRow = $sheet->getHighestRow(); // 取得总列数 $highestColumn = $sheet->getHighestColumn(); Coordinate::columnIndexFromString($highestColumn); $lines = $highestRow - 1; if ($lines <= 0) { return '数据不能为空'; } // 直接取出excle中的数据 $data = $objPHPExcel->getActiveSheet()->toArray(); // 删除第一个元素(表头) array_shift($data); // 返回结果 return $data; } catch (ValidateException $e) { return $e->getMessage(); } } /** * 导出excel表格 * @param array $header 设置表头数据 * @param array $data 生成的表格数据 * @param bool $type 文件类型,true为Xlsx,false为Xls,默认为true * @param string $fileName 文件名,默认为数据 */ protected function export($header = [], $data = [], $type = true, $fileName = "数据") { // 实例化类 $preadsheet = new Spreadsheet(); // 创建sheet $sheet = $preadsheet->getActiveSheet(); // 生成表头字母 $letter = []; $n = 0; for ($i = 'A'; $i <= 'Z'; $i++) { if ($n<count($header)){ $letter[] = $i; }else{ break; } $n++; } // 循环设置表头数据 foreach ($header as $k => $v) { // 解决长数字自动转科学计数法 if(is_numeric($v) && strlen($v) > 11){ $sheet->setCellValueExplicit($letter[$k].'1',$v,'s'); } $sheet->setCellValue($letter[$k].'1', $v); } // 生成数据 $sheet->fromArray($data, null, "A2"); // 样式设置 $sheet->getDefaultColumnDimension()->setWidth(12); // 设置下载与后缀 if ($type) { header("Content-Type:application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); $type = "Xlsx"; $suffix = "xlsx"; } else { header("Content-Type:application/vnd.ms-excel"); $type = "Xls"; $suffix = "xls"; } // 激活浏览器窗口 header("Content-Disposition:attachment;filename=$fileName.$suffix"); //缓存控制 header("Cache-Control:max-age=0"); // 调用方法执行下载 $writer = IOFactory::createWriter($preadsheet, $type); // 数据流 $writer->save("php://output"); } } 调用$excel = new Excel(); // 导出 $header = ['姓名','性别']; $data = [['小王','男'],['小李','男']]; $excel->export($header,$data); // 导入 $data = $excel->importExcel('/storage/picture/20221222/77d80064c35db092c8124a13a7f6fcd5.xlsx'); if(is_array($data)){ print_r($data); }else{ echo $data; } HTML中的字符实体 https://www.zzwws.cn/archives/6387/ 2023-01-03T10:22:00+08:00 提示:需要把\去掉!字符说明字符实体名实体编号"双引号\&quot;\&#34;'撇号\&apos;(IE不支持)\&#39;<小于号\&lt;\&#60;>大于号\&gt;\&#62;&和号\&amp;\&#38;©版权(copyright)\&copy;\&#169;®注册商标\&reg;\&#174;™商标\&trade;\&#8482;×乘号\&times;\&#215;÷除号\&divide;\&#247;£镑(pound)\&pound;\&#163;¥元(yen)\&yen;\&#165; 竖条 \&#124;§小节\&sect;\&#167;Empty space不间断空格\&nbsp;\&#160;€欧元(euro)\&euro;\&#8364; 中文全角空格\&amp;\&#12288;·间隔符\&middot;\&#183;«左双尖括号\&laquo;\&#171;»右双尖括号\&raquo;\&#187;°度\&deg;\&#176;‰千分比\&permil;\&#8240; MySQL 小数类型 https://www.zzwws.cn/archives/6386/ 2022-12-28T15:53:00+08:00 定点数decimal能够保证数据精确的小数(小数部分可能不精确,超出长度会四舍五入),整数部分一定精确decimal(M, D), M表示总长度,最大值不能超过65,D代表小数部分长度,最长不能超过30浮点型又称为精度类型,是一种可能丢失精度的数据类型,数据可能不那么准确float 单精度类型4字节存储,7位精度,表示数据范围比整数大得多float 表示不指定小数位的浮点数float(M, D)表示一共存储M个有效数字,其中小数部分占D位double 双精度类型8个字节存储,表示范围更大,精度有15位左右double 表示不指定小数位的浮点数double(M, D)表示一共存储M个有效数字,其中小数部分占D位如何选择当需要存储的小数对精度要求不高时,可以选择FLOAT单精度浮点型,可以节省内存空间,提高计算速度。当需要进行高速数学计算、科学计算、卫星定位计算等对精度要求较高时,可以选择DOUBLE双精度浮点型。当需要进行精确计算,如工资结算、转账打款等财务类型的数据,可以选择DECIMAL定点型。 ThinkPHP6使用DOMDocument报错 https://www.zzwws.cn/archives/6385/ 2022-12-23T16:51:27+08:00 每一个载入浏览器都会生成一个 Document 对象。Document 对象使我们可以从脚本中对 HTML 页面中的所有元素进行访问。Document 对象是 Window 对象的一部分。我们项目中需要使用第三方支付,第三方支付文件使用了DOMDocument,如果直接使用DOMDocument的话会报错解决方法只需要在DOMDocument加上一个反斜杠就可以了$dom = new \DOMDocument(); $dom->loadXML($data);