零艺江湖 - 行到水穷处,坐看云起时 | 个人生活记录 | 零艺客 - PHP
<?php $data = array ( "name" => 'test_name' , "content" => 'test_con' ); $data = http_build_query( $data ); $opts = array ( 'http' => array ( 'method' => "POST" , 'header' => "Content-type: application/x-www-form-urlencoded\r\n" . "Content-length:" . strlen ( $data ). "\r\n" . "Cookie: foo=bar\r\n" . "\r\n" , 'content' => $data , ) ); $cxContext = stream_context_create( $opts ); $sFile = file_get_contents ( "http://127.0.0.1/reponse.php" , false, $cxContext ); echo $sFile ; ?> // 结果 string(132) "array(2) { ["content"]=> string(8) "test_con" ["name"]=> string(9) "test_name" } array(1) { ["foo"]=> string(3) "bar" } "
序[scode type="share"]没什么好说的，蹭个热度，燃鹅解密，直接上代码。[/scode]PHP版<?php /* * @Author: ZeroArt * @Date: 2021-02-25 21:41:02 * @Link: http://lykep.com * @LastEditors: ZeroArt * @LastEditTime: 2021-02-25 21:41:30 * @Description: */ class rane { // utf8编码 function decodeUtf8($bytes) { $encoded = ""; for ($i = 0; $i < count($bytes); $i++) { $encoded .= '%' . dechex($bytes[$i]); } return urldecode($encoded); } // 数组转字符串 function dec($t) { if (is_string($t)) { return $t; } else { $n = []; for ($i = 0; $i < count($t); $i++) { $n[] = $t[$i]; } } return $this->decodeUtf8($n); } // hex字符串转数组 public function n($t) { $e = 0; $n = strlen($t); if ($n % 2 != 0) { return null; } else { $n /= 2; $o = []; for ($i = 0; $i < $n; $i++) { $r = substr($t, $e, 2); $a = hexdec($r); $o[] = $a; $e += 2; } $os = []; foreach ($o as $key => $value) { $os[] = $value; } return $os; } } // 加解密核心算法 function m($t, $e) { $a = []; $n = ""; $o = count($e); $i = ($t ^ $o) % 255; $r = (($o & $i) + ($t ^ $i)) % 255; $a = []; $s = 0; for ($s = 0; $s < $o; $s++) { $i -= ($r * $o ^ $t) % 255; $t -= $r; $n = 255 & (($n = $e[$s]) ^ ($r = $i % 255)); $a[] = $n; } return $a; } } $rane = new rane(); // 常规模式 if (isset($_GET['t']) && isset($_GET['v'])) { echo ($rane->dec($rane->m($_GET['t'], $rane->n($_GET['v'])))); exit(); } // JOSN格式 if (isset($_GET['json']) || isset($_POST['json'])) { $param = json_decode($_REQUEST['json'], true); echo ($rane->dec($rane->m($param['t'], $rane->n($param['v'])))); exit(); } // 案例 if (isset($_GET['dome'])) { echo ($rane->dec($rane->m('59131814', $rane->n('ad88eff390bd7706d24a93f04727c0d61f886f3f4922680c5cb7f8716073379a625845875d6708477d3014f31e575098b983ce709bd1f7f3f7fa63f6e12eb216ade7a43e314048cc80d73c18d6a8d72cb1f231593b4aa9ef56a170fbf9db23d07048589053d56fa4bafdbbe8b52720d938f6b4f85a2dd0092805fc2c6aa4c8fd3b92a89c7786368eb0e979d96c03831412d23d008a491b68295d893c77251902dba8ee84fe390efbee01d65815254bd9bbe1bd7e12b1fc0542bfc893d0ac83c3b7abafbc6328aa37f89a378fce83e01d49d19ef4ed20893993870501fdef066e092a27fc45a7ce8c0d54fa0244f6b7a2388be2a7fba0aa80cbe313194886d0ace13ab730f0288e987fa31088d4f559d74a14a8f057254e070b8b')))); exit; } // 提示 $msg = [ [ "JSON请求" => "?json={'t'=>'59131814','v'=>'xxxxxx'}" ], [ "常规请求" => "?t=59131814&v=xxxxxx" ] ]; echo " "; var_dump($msg); echo " "; Js版（可加密）// utf8编码 function decodeUtf8(bytes) { var encoded = ""; for (var i = 0; i < bytes.length; i++) { encoded += '%' + bytes[i].toString(16); } return decodeURIComponent(encoded); } // 数组转字符串 function dec(t) { if ("string" == typeof t) return t; for (var n = [], i = 0; i < t.length; i++) { n.push(t[i]); } return decodeUtf8(n); } // hex字符串转数组 function n(t) { var e = 0, n = t.length; if (n % 2 != 0) return null; n /= 2; for (var o = [], i = 0; i < n; i++) { var r = t.substr(e, 2), a = parseInt(r, 16); o.push(a), e += 2; } return o; } // 加解密核心算法 function m(t, e) { for (var n, o = e.length, i = (t ^ o) % 255, r = ((o & i) + (t ^ i)) % 255, a = [], s = 0; s < o; s++) { i -= (r * o ^ t) % 255, t -= r, n = 255 & ((n = e[s]) ^ (r = i % 255)), a.push(n); } return a; } // 字符串转字节 function stringToByte(t) { var e, n, o = new Array(); e = t.length; for (var i = 0; i < e; i++) { (n = t.charCodeAt(i)) >= 65536 && n <= 1114111 ? (o.push(n >> 18 & 7 | 240), o.push(n >> 12 & 63 | 128), o.push(n >> 6 & 63 | 128), o.push(63 & n | 128)) : n >= 2048 && n <= 65535 ? (o.push(n >> 12 & 15 | 224), o.push(n >> 6 & 63 | 128), o.push(63 & n | 128)) : n >= 128 && n <= 2047 ? (o.push(n >> 6 & 31 | 192), o.push(63 & n | 128)) : o.push(255 & n); } return o; } // 数组转hex字符串 function parseByte2HexStr(t) { for (var e = "", n = 0; n < t.length; n++) { var o = t[n].toString(16); 1 == o.length && (o = "0" + o), e += o; } return e; } // 解密数据，a和b分别为t和v function decode(a, b) { return dec(m(a, n(b))) } // 加密数据，e和n分别为t和v function encode(e, n) { return parseByte2HexStr(m(e, stringToByte(n))) } // t值,v值 decode("59131814",'xxxxxx');
序个人对于Curl还是蛮常用的，偶然发现一个封装这么完全的，记录下。代码<?php /** * @author 教书先生 * @link https://blog.oioweb.cn * @date 2020年11月12日18:00:30 * @msg PHPCurl封装的方法 */ function teacher_curl($url, $paras = array()) { $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); if (@$paras['Header']) { $Header = $paras['Header']; } else { $Header[] = "Accept:*/*"; $Header[] = "Accept-Encoding:gzip,deflate,sdch"; $Header[] = "Accept-Language:zh-CN,zh;q=0.8"; $Header[] = "Connection:close"; } curl_setopt($ch, CURLOPT_HTTPHEADER, $Header); if (@$paras['ctime']) { // 连接超时 curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $paras['ctime']); } else { curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30); } if (@$paras['rtime']) { // 读取超时 curl_setopt($ch, CURLOPT_TIMEOUT, $paras['rtime']); } if (@$paras['post']) { curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, $paras['post']); } if (@$paras['header']) { curl_setopt($ch, CURLOPT_HEADER, true); } if (@$paras['cookie']) { curl_setopt($ch, CURLOPT_COOKIE, $paras['cookie']); } if (@$paras['refer']) { if ($paras['refer'] == 1) { curl_setopt($ch, CURLOPT_REFERER, 'http://m.qzone.com/infocenter?g_f='); } else { curl_setopt($ch, CURLOPT_REFERER, $paras['refer']); } } if (@$paras['ua']) { curl_setopt($ch, CURLOPT_USERAGENT, $paras['ua']); } else { curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36"); } if (@$paras['nobody']) { curl_setopt($ch, CURLOPT_NOBODY, 1); } curl_setopt($ch, CURLOPT_ENCODING, "gzip"); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); if (@$paras['GetCookie']) { curl_setopt($ch, CURLOPT_HEADER, 1); $result = curl_exec($ch); preg_match_all("/Set-Cookie: (.*?);/m", $result, $matches); $headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE); $header = substr($result, 0, $headerSize); //状态码 $body = substr($result, $headerSize); $ret = [ "Cookie" => $matches, "body" => $body, "header" => $header, 'code' => curl_getinfo($ch, CURLINFO_HTTP_CODE) ]; curl_close($ch); return $ret; } $ret = curl_exec($ch); if (@$paras['loadurl']) { $Headers = curl_getinfo($ch); $ret = $Headers['redirect_url']; } curl_close($ch); return $ret; }使用方法文档GET访问echo teacher_curl("https://api.oioweb.cn/api/beian.php?url=qq.com");POST访问echo teacher_curl("https://api.oioweb.cn/api/beian.php",[ 'post'=>[ 'url'=>'qq.com' ] ]);或echo teacher_curl("https://api.oioweb.cn/api/beian.php",[ 'post'=>'url=qq.com' ]);携带Cookie访问echo teacher_curl("https://api.oioweb.cn/api/beian.php?url=qq.com",[ 'cookie'=>'cookie内容' ]);模拟访问来源Referecho teacher_curl("https://api.oioweb.cn/api/beian.php?url=qq.com",[ 'refer'=>'https://api.oioweb.cn' ]);模拟UseaAgentecho teacher_curl("https://api.oioweb.cn/api/beian.php?url=qq.com",[ 'ua'=>'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36' ]);文件上传echo teacher_curl("https://api.oioweb.cn/api/beian.php?url=qq.com",[ 'post'=>[ 'file'=>new CURLFile(realpath("Curl.jpg")) ] ]);或echo teacher_curl("https://api.oioweb.cn/api/beian.php?url=qq.com",[ 'post'=>new CURLFile(realpath("Curl.jpg")) ]);获取301跳转地址echo teacher_curl("https://mmbizurl.cn/s/RNHSo6Dek",[ 'loadurl'=>1 ]);查看返回Header信息echo teacher_curl("https://api.oioweb.cn/api/beian.php?url=qq.com",[ 'header'=>1 ]);设置请求头信息echo teacher_curl("https://api.oioweb.cn/api/beian.php?url=qq.com",[ 'Header'=>[ 'accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3 accept-encoding: gzip, deflate, br accept-language: zh-CN,zh;q=0.9 cache-control: max-age=0' ] ]);获取请求的全部信息echo teacher_curl("https://api.oioweb.cn/api/beian.php?url=qq.com",[ 'post'=>[ 'user'=>123456, 'pwd'=>123 ], 'GetCookie'=>1 ]);最后还有其他的功能，自己研究吧！还是很强大的！码云仓库https://gitee.com/jsxs599928887/PHP_Curl更新日志2020年11月30日16:25:50增加GetCookie返回状态码
序[scode type="share"]网站上需要用到打包文件的可以使用，代码已验证，记录下。[/scode]实现代码[scode type="blue"]//在指定路径创建一个空的压缩包 例如 当前路径 创建 pack.zip // 获取压缩文件清单 $fileList = file_list(__DIR__."/temp/img"); // 打包文件名称 $_filename = date('YmdHis') . '.zip'; // 打包文件保存路径 $filename = __DIR__ .'/temp/'. $_filename; // 如果复制空压缩包成功则加入压缩文件 if (copyFile(__DIR__ . '/pack.zip', $filename)) { // 实例化压缩类 $zip = new \ZipArchive(); // 打开压缩包 if ($zip->open($filename, \ZipArchive::CREATE)) { foreach ($fileList as $file) { //向压缩包中添加文件 $zip->addFile($file, basename($file)); } //关闭压缩包 $zip->close(); exit('打包完成'); } else { exit('打包失败'); } } else { exit('压缩包创建失败'); } //自定义方法补充 // 获取所有文件夹 function file_list($path, $complete = true) { //设置空数组 $arr = array(); //判断文件是否存在 if (is_file($path)) { } else { //判断是否是路径 if (is_dir($path)) { //获取目录下所有文件和目录 $data = scandir($path); //判断是否为空 if (!empty($data)) { //循环取出文件 foreach ($data as $value) { //过滤特殊文件 if ($value != '.' && $value != '..') { //判断是返回完整路径还是仅文件名 if ($complete) { $sub_path = $path . "/" . $value; } else { $sub_path = $value; } //判断是否存在二级目录 if (is_dir($sub_path)) { //递归二级目录文件 $temp = file_list($sub_path); $arr = array_merge($temp, $arr); } else { $arr = array_merge([$sub_path], $arr); } } } } } } //返回数据 return $arr; } // 复制文件 function copyFile($filepath, $tofilepath) { //复制文件地址 复制文件到地址 return copy($filepath, $tofilepath); } [/scode]
序[scode type="share"]有时候某些资源不好走直链或者需要设置下载限制的时候可以使用以下方法来达到目的，已实践代码，记录下。[/scode]实现代码[scode type="blue"]//下载的文件名称 $downname = date('Ymd').'.zip'; //需要下载文件所存放的目录 $file_name = __DIR__.'/temp/123.zip'; $fp = fopen($file_name, "r"); //获取文件的字节 $file_size = filesize($file_name); // 下载文件需要设置的协议头 Header("Content-type: application/octet-stream"); Header("Accept-Ranges: bytes"); Header("Accept-Length:" . $file_size); Header("Content-Disposition: attachment; filename=$downname"); //设置一次读取的字节数，每读取一次，就输出数据（即返回给浏览器） $buffer = 1024; $file_count = 0; //读取的总字节数 while (!feof($fp) && $file_count < $file_size) { $file_con = fread($fp, $buffer); $file_count += $buffer; echo $file_con; } fclose($fp); [/scode]
序[scode type="share"]水友定做的一个收作业管理系统，基于Thinkphp框架编写。程序为私人定制，不做开源仅用于项目展示。[/scode]下载功能[scode type="blue"]后台1.同学管理包含：同学CRUD同学数据导出文件同学数据打印2.学科管理包含：学科CRUD任命课代表3.作业发布包含：作业CRUD以科目为单位，对以添加同学发布作业（可设置作业提交格式、到期时间）4.作业管理包含：当此作业一键打包作业查看作业上交情况上交名单导出文件上交名单数据打印5.网站设置包含：网站基础信息设置6.其他模块包含：资源访问伪装资源打包下载三级操作权限前台1.作业上传[/scode]
序[scode type="share"]隔壁AE站点看到的，代码放在程序最开始，可以快速定位错误文件、行数、原因。预计以后会用到，先记录下吧i[]~(￣▽￣)~*[/scode]代码// 代码 register_shutdown_function(function(){ print_r(error_get_last()); }); // 异常信息 array ( ltype] =>4 [message] =>synt ax error，umnexpected ''site_info'’(T_CONSTANT_ENCAPSED_STRLNG)，expecting ']' [file]=> D:iphpStudyiPHPTutorialiWWidemoltemplateladminisetting.php [line] => 24 )
序[scode type="share"]最近写的项目基本都基于前后端分离，写完接口还要去编写文档，两边折腾太累了，找了这么个解决方案Swagger-php，能够在写接口的时候通过注解的方式实现自动生成文档，花了不少时间总算折腾出来了，记录下！[/scode]技术点[scode type="yellow"]1.composer//更新指令 composer update 2.swagger-ui//git下载 git clone https://github.com/swagger-api/swagger-ui.git 3.swagger-php[/scode]安装步骤[scode type="blue"]1.安装swagger-php后端进入你的tp5框架找到根目录下,打开composer.json找到require项，添加一行(注意，每行用逗号分隔)。"zircote/swagger-php": "*" 使用更新命令composer update 使用安装指令（这里安装以下这个版本，测试时安装了N个版本，唯独这个成功了( ╯□╰ )）composer require "zircote/swagger-php:2.0.13" 2.生成swagger.json文件(这里需要先建立存放swagger.json的文件夹swagger-docs，这个文件夹名称随意，存放位置也随意 )//第1个路径是你安装成功后组件的路径； //第2个路径是你想要生成这个目录下所有用swagger方式注释的php文件，把所有注释生成api文档； //第3个路径是你存放生成swagger.json的路径。 php ./vendor/zircote/swagger-php/bin/swagger ./vendor/zircote/swagger-php/Examples -o ./swagger-docs/swagger.json 3.swagger-ui加载生成的json文件<?php namespace app\index\controller; use think\Controller; use Swagger\Annotations as SWG; class Index extends Controller { public function index(){ // APP_PATH tp框架5.1不再提供常量，自己定义根目录 // 测试dome在vendor/zircote/swagger-php/Examples/dynamic-reference 自行复制测试 $path = APP_PATH.'/application/dynamic-reference'; //你想要哪个文件夹下面的注释生成对应的API文档 $swagger = \Swagger\scan($path); $swagger_json_path = APP_PATH.'/swagger-docs/swagger.json'; // 检测模板目录 $dir = dirname($swagger_json_path); if (!is_dir($dir)) { mkdir($dir, 0755, true); } // 更新文档 $myfile = fopen($swagger_json_path, "w") or die("Unable to open file!"); $swagger=json_encode($swagger, true); fwrite($myfile, $swagger); fclose($myfile); // 跳转到文档页面 $this->redirect('/swagger-ui/index.html'); } } 5.下载swagger-ui执行下面命令git clone https://github.com/swagger-api/swagger-ui.git 克隆下来后将dist文件夹内的文件 复制到例如public目录下新建文件夹Swagger-Ui中，修改Swagger-Ui中的index.html文件 在控制器中新建方法，使上方文档能读取到json数据 public function swagger() { echo file_get_contents(APP_PATH . '/swagger-docs/swagger.json'); } [/scode]
序[scode type="share"]基于Laravel框架写的程序需要跟其他端进行交互，需要使用到jwt令牌，试了框架的第三方包感觉好麻烦，网上找了好久终于找到了(●ˇ∀ˇ●)，困扰许久的问题就这么解决了，记录一下。[/scode]代码<?php //框架中使用解除下面命名空间 //namespace App\Http\Controllers\User; /** * PHP实现jwt */ class JwtControler { //头部 private static $header = array( 'alg' => 'HS256', //生成signature的算法 'Type' => 'Jwt' //类型 ); //使用HMAC生成信息摘要时所使用的密钥 private static $key = 'crow'; /** * 获取jwt token * @param array $payload jwt载荷 格式如下非必须 * [ * 'iss'=>'jwt_admin', //该JWT的签发者 * 'iat'=>time(), //签发时间 * 'exp'=>time()+7200, //过期时间 * 'nbf'=>time()+60, //该时间之前不接收处理该Token * 'sub'=>'www.admin.com', //面向的用户 * 'jti'=>md5(uniqid('JWT').time()) //该Token唯一标识 * ] * @return bool|string */ public static function getToken(array $payload) { if (is_array($payload)) { $base64header = self::base64UrlEncode(json_encode(self::$header, JSON_UNESCAPED_UNICODE)); $base64payload = self::base64UrlEncode(json_encode($payload, JSON_UNESCAPED_UNICODE)); $token = $base64header . '.' . $base64payload . '.' . self::signature($base64header . '.' . $base64payload, self::$key, self::$header['alg']); return $token; } else { return false; } } /** * 验证token是否有效,默认验证exp,nbf,iat时间 * @param string $Token 需要验证的token * @return bool|string */ public static function verifyToken(string $Token) { $tokens = explode('.', $Token); if (count($tokens) != 3) return false; list($base64header, $base64payload, $sign) = $tokens; //获取jwt算法 $base64decodeheader = json_decode(self::base64UrlDecode($base64header), JSON_OBJECT_AS_ARRAY); if (empty($base64decodeheader['alg'])) return false; //签名验证 if (self::signature($base64header . '.' . $base64payload, self::$key, $base64decodeheader['alg']) !== $sign) return false; $payload = json_decode(self::base64UrlDecode($base64payload), JSON_OBJECT_AS_ARRAY); //签发时间大于当前服务器时间验证失败 if (isset($payload['iat']) && $payload['iat'] > time()) return false; //过期时间小宇当前服务器时间验证失败 if (isset($payload['exp']) && $payload['exp'] < time()) return false; //该nbf时间之前不接收处理该Token if (isset($payload['nbf']) && $payload['nbf'] > time()) return false; return $payload; } /** * base64UrlEncode https://jwt.io/ 中base64UrlEncode编码实现 * @param string $input 需要编码的字符串 * @return string */ private static function base64UrlEncode(string $input) { return str_replace('=', '', strtr(base64_encode($input), '+/', '-_')); } /** * base64UrlEncode https://jwt.io/ 中base64UrlEncode解码实现 * @param string $input 需要解码的字符串 * @return bool|string */ private static function base64UrlDecode(string $input) { $remainder = strlen($input) % 4; if ($remainder) { $addlen = 4 - $remainder; $input .= str_repeat('=', $addlen); } return base64_decode(strtr($input, '-_', '+/')); } /** * HMACSHA256签名 https://jwt.io/ 中HMACSHA256签名实现 * @param string $input 为base64UrlEncode(header).".".base64UrlEncode(payload) * @param string $key * @param string $alg 算法方式 * @return mixed */ private static function signature(string $input, string $key, string $alg = 'HS256') { $alg_config = array( 'HS256' => 'sha256' ); return self::base64UrlEncode(hash_hmac($alg_config[$alg], $input, $key, true)); } } //用户ID 设备号 过期时间 $payload = array('uid' => '11', 'deviceNo' => 'web', 'expire_time' => 1594902222000); $jwt = new JwtControler; $token = $jwt->getToken($payload); echo $token;
序[scode type="share"]对于网站某些链接或者某些站点不方便公示出地址的，利用Nginx反向代理可以很好的解决，花了点时间测试得到以下结果。[/scode]代码#不跳转源站 location / { #rewrite ^/(.*)$1 break; proxy_pass http://tv.lessh.cn/; } #跳转部分格式下的源站 location / { proxy_pass http://tv.lessh.cn; proxy_redirect off; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Host $host; } #不跳转源站 location /{ proxy_pass http://tv.lessh.cn; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Host $host; } #类型过滤 location ~ .*\.(php|php5)?$ { } #类型缓存 location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$ { expires 30d; }