一个简单的php socket服务端

<?php

/**
 * 一个简单的socke服务端
 */
class Socket{
    public $address ="0.0.0.0";
    public $port=8081;
    private $_server;

    public function __construct(){
        echo "开始创建对象...".PHP_EOL;
        $socket = socket_create(AF_INET,SOCK_STREAM,SOL_TCP) or self::error($socket );
        echo "绑定端口:".$this->address.":".$this->port."...".PHP_EOL;
        $tmp = socket_bind($socket,$this->address,$this->port) or self::error($tmp);;
        echo "开始监听...".PHP_EOL;
        $tmp = socket_listen($socket, 4) or self::error($tmp );
        echo "服务启动成功".PHP_EOL;
        $this->_server = &$socket;
    }

    public static function error($server){
        die(socket_strerror(socket_last_error($server)) . "/n");
    }

    /**
     * 解析http报文为数组
     * @param $data
     * @return array
     */
    public function analysisBuffer($data){
        $herder =[];
        $lines = preg_split("/\r\n/",$data);
        foreach ($lines as $line){
            $row =explode(": ",$line);
            if(count($row) ==2){
                $herder[$row[0]] =$row[1];
            }
        }
        return $herder;
    }

    /**
     * 返回报文
     * @param $buffer
     * @param $client
     * @return bool
     */
    public function hand_shake($buffer,$client){
        $headers = $this->analysisBuffer($buffer);
        $key =$headers['Sec-WebSocket-Key'];
        $new_key = base64_encode(sha1($key."258EAFA5-E914-47DA-95CA-C5AB0DC85B11",true));
        $message = "HTTP/1.1 101 Switching Protocols\r\n";
        $message .= "Upgrade: websocket\r\n";
        $message .= "Sec-WebSocket-Version: 13\r\n";
        $message .= "Connection: Upgrade\r\n";
        $message .= "Sec-WebSocket-Accept: " . $new_key . "\r\n\r\n";
        socket_write($client,$message,strlen($message));
        return true;
    }

    /**
     * 加密
     * @param $message
     * @return string
     */
    public function encode($message){
        $len = strlen($message);
        if($len <=125){
            return "\x81".chr($len).$message;
        }elseif ($len<=65535){
            return "\x81".chr(126).pack("n",$len).$message;
        }else{
            return "\x81".chr(127).pack("xxxxN",$len).$message;
        }
    }

    /**
     * 解密
     * @param $buffer
     * @return string|null
     */
    public function decode($buffer){
        $len = $masks = $data = $decode =null;
        $len = ord($buffer[1]) & 127;
        if($len === 126){
            $masks = substr($buffer,4,4);
            $data = substr($buffer,8);
        }elseif ($len ===127){
            $masks = substr($buffer,10,4);
            $data = substr($buffer,14);
        }else{
            $masks = substr($buffer,2,4);
            $data = substr($buffer,6);
        }
        for ($index =0;$index <strlen($data);$index++){
            $decode .= $data[$index] ^ $masks[$index % 4];
        }
        return $decode;
    }

    public function run(){
        $clients = [$this->_server];
        do {
            $read =$clients;
            $write =null;
            $except =null;
            if (socket_select($read,$write,$except,null)>0){
                foreach ($read as $item){
                    if($item === $this->_server){
                        // 首次链接
                        if(!$socket_client = socket_accept($item)){
                            continue;
                        }else{
                            $client_data = @socket_read($socket_client,1024);
                            if($client_data=== false){
                                socket_close($socket_client);
                            }
                            // 建立握手
                            $this->hand_shake($client_data ,$socket_client);
                            // 获取客户端信息
                            socket_getpeername($socket_client,$ip,$port);
                            $clients[$ip.":".$port]=  $socket_client;
                            echo "有一个新的链接".$ip.":".$port."\n";
                        }
                    }else{
                        $result = @socket_recv($item,$msg,1024,0);

                        if($result === false){continue;}
                        if ($result ===0 ){
                            socket_close($item);
                            $key1 =array_search($item,$read);
                            unset($read[$key1]);
                            $key2 = array_search($item,$clients);
                            unset($clients[$key2]);
                        }else{
                            // 解码客户端消息
                            $web_msg= $this->decode($msg);
                            $id = array_search($item ,$clients);
                            echo "client:".$id ."说:".$web_msg."\n";
                            // 加密客户端消息
                            $response = $this->encode($web_msg);
                            // 广播
                            foreach ($clients as $client){
                                if($client != $this->_server ){
                                    if(false == @socket_write($client,$response,strlen($response))){
                                        socket_close($client);
                                        $key1 = array_search($client,$read);
                                        unset($read[$key1]);
                                        $key2 = array_search($client,$clients);
                                        unset($clients[$key2]);
                                    }
                                }
                            }
                        }
                    }
                }
            }
        } while (true);
    }
}

$server = new Socket();
$server->run();
Posted in php, socket | Leave a comment

php 拓展包,依赖包,可视化

php 解析composer依赖关系,生成视图

php 解析composer依赖关系,生成视图
use crud\models\Rely;
$model = new Rely();
$model->vendorDir = '/vendor');
//$model->env =false;
$model->baseComposerJson = "/composer.json";
$model->baseComposerLock = "/composer.lock";
echo $model-> renderHtml();
<?php


namespace crud\models;


use yii\base\Model;

/**
 * 生成composer 依赖关系图
 * @package crud\models
 */
class Rely extends Model
{

    public $vendorDir = '';
    public $baseComposerJson = '';
    public $baseComposerLock='';
    public $env = true;
    public $_require=[];
    public $projectName="shiguangxiaotou/wordpress";
    public $data =[
        "nodes" => [
//            [
//                "id" => "0",
//                "name" => "shiguangxiaotou/wordpress",
//                "symbolSize" => 20,
//                "value" => "1.3.0",
//                "category" => 0
//            ],
        ],
        "links" => [
//            "source" => $nodeId,
//            "target" => $fatherId
        ],
        "categories" => [
//            ['name'=>'adads']
        ]
    ];

    /**
     * 获取已安装拓展包已安装版本
     * @param $projectName
     * @return mixed|string
     */
    public function getVersion($projectName){
        $str_json = file_get_contents($this->baseComposerLock);
        $arr = json_decode($str_json,true);
        $packages = ($this->env) ? $arr['packages']:$arr['packages-dev'];
        $results ='';
        foreach ( $packages as $package){
            if($package['name']==$projectName){
                return $package['version'];
            }
        }
        return  $results;
    }

    /**
     * 获取composer.json的依赖包名称
     * @param $file
     * @param bool $env
     * @return array
     */
    public static function getRequire($file,$env=true){
        $requires = $names=[];
        if(file_exists($file)){
            $json = file_get_contents($file);
            $arr =json_decode($json,true);
            if($env){
                $requires = !empty($arr['require'])? $arr['require']:[];
            }else{
                $requires1 = !empty($arr['require'])? $arr['require']:[];
                $requires2 = !empty($arr['require-dev'])? $arr['require-dev']:[];
                $requires = array_merge($requires1,$requires2);
//                $requires = !empty($arr['require-dev'])? $arr['require-dev']:[];
//                logObject($requires2);
            }
            $names = array_keys($requires);
        }
        return $names;
    }

    /**
     * 递归获取所以第三方插件
     * @param array $data
     * @param $projectName
     */
    public  function getRely($projectName,&$data=[]){
        $tmp = self::getRequire($this->vendorDir.'/'.$projectName."/composer.json");
        if(!empty($tmp)) {
            foreach ($tmp as $value) {
                $data[$projectName][$value]=[] ;
                $tmp2 =self::getRequire($this->vendorDir.'/'.$value."/composer.json");
                if(!empty($tmp2)){
                    self::getRely($value,$data[$projectName][$value]);
                }

            }
        }
    }

    /**
     * 判断节点是否存在
     * @param $projectName
     * @return bool
     */
    public function isset_node($projectName){
        foreach ($this->data['nodes'] as $node){
            if($node['name'] == $projectName){
                return true;
            }
        }
        return  false;
    }

    /**
     * 获取节点id
     * @param $nodeName
     * @return mixed
     */
    public  function getNodeId($nodeName){
        foreach ($this->data['nodes'] as $node){
            if($node['name'] == $nodeName){
                return $node['id'];
            }
        }
    }

    /**
     * 递归创建Echarts数据结构
     * @param $fatherId
     * @param $categoryId
     * @param $nodeName
     * @param $nodes
     * @param $data
     */
    public  function  recursionNodes($fatherId,$categoryId,$nodeName,$nodes,&$data){
        if(!$this->isset_node($nodeName)){
            $nodeId =count($data['nodes']);
            if($nodeId ==0){
                $data['nodes'][]=[
                    "id" => $nodeId,
                    "name" => $nodeName,
                    "symbolSize" => 20,
                    "value" => $this->getVersion($nodeName),
                    "category" => $categoryId
                ];
            }else{
                $data['nodes'][]=[
                    "id" => $nodeId,
                    "name" => $nodeName,
                    "value" => $this->getVersion($nodeName),
                    "category" => $categoryId
                ];
            }

            if($nodeId !==$fatherId){
                $data['links'][]=[
                    "source" => $nodeId,
                    "target" => $fatherId
                ];
            }
        }else{
            $nodeId = $this->getNodeId($nodeName);
            // 要现实复杂依赖关系,请取消注释
//            if($nodeId !==$fatherId){
//                $data['links'][]=[
//                    "source" => $nodeId,
//                    "target" => $fatherId
//                ];
//            }
        }



        if (!empty($nodes)){
            $categoryId = count( $this->data["categories"]);
            $this->data["categories"][]=["name"=>$nodeName];
            foreach ($nodes as $name=>$v){
                $this->recursionNodes($nodeId,$categoryId,$name,$v,$data);
            }
        }

    }


    /**
     * 解析依赖,并创建eCharts数据结构
     * @return array
     */
    public function getRequireAll(){
        // 获取所有加载的拓展
        $base = self::getRequire($this->baseComposerJson,$this->env);
        $this->_require[$this->projectName]=[];
        foreach ($base as $value){
            $this->_require[$this->projectName][$value]=[];
            $this->getRely($value, $this->_require[$this->projectName][$value]);
        }
        $results = $this->_require;
        $nodeId = $categoriesId = 0;
        foreach ($results as $key =>$value){
            $this->recursionNodes($nodeId,$categoriesId,$key,$value,$this->data);
            $categoriesId++;
        }
       return  $this->data;
    }

    /**
     * 直接生成html文件
     * @return string
     */
    public function renderHtml(){
        $json_str = json_encode( $this->getRequireAll(),true);
        return <<<HTML
<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
 <title>Document</title>
</head>
<body>
    <div id="container" style="width: 100%;height: 800px"></div>
</body>
<script type="text/javascript" src="https://fastly.jsdelivr.net/npm/jquery"></script>
<script type="text/javascript" src="https://fastly.jsdelivr.net/npm/[email protected]/dist/echarts.min.js"></script>
<script>
    var dom = document.getElementById('container');
    var myChart = echarts.init(dom, null, {
        renderer: 'canvas',useDirtyRect: false
    });
    var graph = {$json_str}
    var option= {
      tooltip: {},
      legend: [
        {
          data: graph.categories.map(function (a) {
            return a.name;
          })
        }
      ],
      series: [
        {
          name: 'shiguangxiaotou/crud',
          type: 'graph',
          layout: 'force',
          data: graph.nodes,
          links: graph.links,
          categories: graph.categories,
          roam: true,
          label: {
            show: true,
            position: 'right',
            formatter: '{b}'
          },
          labelLayout: {
            hideOverlap: true
          },
          scaleLimit: {
            min: 2,
            max: 10
          },
          lineStyle: {
            color: 'source',
            curveness: 0.3
          }
        }
      ]
    };
    myChart.showLoading();
    myChart.hideLoading();
    myChart.setOption(option);
    if (option && typeof option === 'object') {
      myChart.setOption(option);
    }
    window.addEventListener('resize', myChart.resize);
</script>
</html>
HTML;
    }

}
Posted in php | Tagged | Leave a comment

快捷指令:自动登录,上报健康,填写表单,上传图片

Posted in 快捷指令 | Leave a comment

Php在不实话化类的情况下,获取类的所有方法和形参

/**
 * 获取一个类的某个方法的形参名称
 * @param $className
 * @param $methodName
 * @return false|array
 */
function getMethodArgs($className, $methodName){
    try {
        $ref = new ReflectionMethod($className, $methodName);
    } catch (ReflectionException $e) {
        return false;
    }
    $paramsName = [];
    foreach ($ref->getParameters() as $param) {
        $paramsName[] = $param->name;
    }
    return $paramsName;
}

/**
 * 获取类的方法和形参名称
 * @param $className
 * @return array
 */
function getClassInfo($className){
    $results =[];
    $methods = get_class_methods($className);
    if(!empty($methods)){
        foreach ($methods as $method){
            $results[$method] = getMethodArgs($className,$method);
        }
    }
    return $results;
}
Posted in php | Tagged | Leave a comment

php 获取函数或方法的形参和实参

// 定义一个函数
funcrion my_fun($a,$b,$c,$d,$e,$n){
  my_fun2($args);
}
// 有时有需要将函数my_fun的多个参数合并传入另一个函数时,
// 特别麻烦需要一个手写合并为一个数组,当参数太多时,特别麻烦

解决方法一:func_num_args() 将参数合并

funcrion my_fun($a,$b,$c,$d,$e,$n){
  my_fun2(func_get_args());
}
var_dump(my_fun("asd1","asd2","asd3","asd4","asd5","asd6"));

输出

[
"asd1","asd2","asd3","asd4","asd5","asd6"
]

缺点

func_get_args 返回的是一个数字索引数组,如何返回key=>value 的关联数组呢

解决方法二:new ReflectionFunction 将参数合并

funcrion my_fun($a,$b,$c,$d,$e,$n){
  my_fun2(getFunctionArgs(__FUNCTION__));
}
/**
 * 获取函数的的形参名称
 * @param $functionName
 * @return false|array
 */
function getFunctionArgs($functionName){
    if (function_exists($functionName)) {
        try {
            $fun = new  ReflectionFunction($functionName);
        } catch (ReflectionException $e) {
            return false;
        }
        $paramsName = [];
        foreach ($fun->getParameters() as $parameter) {
            $paramsName[] = $parameter->name;
        }
        return $paramsName;
    }
}
var_dump(my_fun("asd1","asd2","asd3","asd4","asd5","asd6"));

输出

[
  "a"=>"asd1","b"=>"asd2",
  "c"=>"asd3","d"=>"asd4",
  "e"=>"asd5","n"=>"asd6"
]

缺点

ReflectionFunction 虽然返回了关联数组但是,只能用于函数,对象的方法不行

解决方法三:ReflectionMethod 对象方法的形参实参合并

funcrion my_fun($a,$b,$c,$d,$e,$n){
  my_fun2(getParams());
}
/**
 * 获取函数的的形参名称
 * @param $functionName
 * @return false|array
 */
function getFunctionArgs($functionName){
    if (function_exists($functionName)) {
        try {
            $fun = new  ReflectionFunction($functionName);
        } catch (ReflectionException $e) {
            return false;
        }
        $paramsName = [];
        foreach ($fun->getParameters() as $parameter) {
            $paramsName[] = $parameter->name;
        }
        return $paramsName;
    }
}

/**
 * 获取一个类的某个方法的形参名称
 * @param $className
 * @param $methodName
 * @return false|array
 */
function getMethodArgs($className, $methodName){
    try {
        $ref = new ReflectionMethod($className, $methodName);
    } catch (ReflectionException $e) {
        return false;
    }
    $paramsName = [];
    foreach ($ref->getParameters() as $param) {
        $paramsName[] = $param->name;
    }
    return $paramsName;
}

/**
 * 兼容对象和函数的写法
 * @return array|mixed
 */
function getParams(){
    $backtrace = debug_backtrace()[1];
    $functionName = $backtrace['function'];
    if (isset($backtrace["class"])) {
        $paramsNames = getMethodArgs($backtrace["class"], $functionName);
    } else {
        $paramsNames = getFunctionArgs($functionName);
    }
    return ($paramsNames and !empty($paramsNames))
        ? array_combine($paramsNames, $backtrace["args"])
        : $backtrace["args"];
}

var_dump(my_fun("asd1","asd2","asd3","asd4","asd5","asd6"));

输出

[
  "a"=>"asd1","b"=>"asd2",
  "c"=>"asd3","d"=>"asd4",
  "e"=>"asd5","n"=>"asd6"
]

最终

getParams() 函数通过兼容写法ReflectionMethod 类和 ReflectionFunction类,实现快速合并形参实参

Posted in php | Leave a comment

免费的东西 你凭什么收费 “氧化钙” “化钙” “氧化钙”

Posted in 未分类 | Leave a comment

我要创建“创建您自己的证书颁发机构”,看官方文档缺少选项。请极速回复

系统版本

按照你们官网教程,找不到“证书助理”

教程url:https://support.apple.com/zh-cn/guide/keychain-access/kyca2686/11.0/mac/12.0

我本机打开是这样的

Posted in 未分类 | Leave a comment

jvectorMap 地理数据包整理集合

jvectormap 地图数据整理 一些年久失修的好东西

jVectorMap 是一个基于矢量、跨浏览器和跨平台的组件,用于在 Web 上进行与地理相关的交互式数据可视化。它提供了许多功能,如平滑缩放和平移、完全可定制的样式、标记、标签和工具提示。

您可以在 官方网站上找到地图、文档、示例等。示例子位于 ??

安装

$ npm install jvectormap-maps-data
$ git clone [email protected]:shiguangxiaotou3/jvectormap-maps-data.git
$ composer require shiguangxiaotou/jvectormap-maps-data

使用

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="./../dist/css/jquery-jvectormap.css">
</head>
<body>
     <div id="world-map" style="height: 500px; width: 100%;"></div>
</body>
<!-- jvectormap -->
<script src="./../node_modules/jquery/dist/jquery.js"></script>
<script src="./js/jquery-jvectormap-1.2.2.min.js"></script>
<script src="./js/jquery-mousewheel.js"></script>
<script>
    jQuery(function ($) {
        let visitorsData = {
            US: 398, GB: 320, RU: 3000,
            SA: 400, CA: 1000, IN: 800
        };
        $('#world').vectorMap({
            map: 'world-merc',
            backgroundColor: 'transparent',
            regionStyle: {
                initial: {
                    fill: '#e4e4e4',
                    'fill-opacity': 1,
                    stroke: 'none',
                    'stroke-width': 0,
                    'stroke-opacity': 1
                }
            },
            series: {
                regions: [
                    {
                        values: visitorsData,
                        scale: ['#ebf4f9', '#92c1dc'],
                        normalizeFunction: 'polynomial'
                    }
                ]
            },
            onRegionLabelShow: function (e, el, code) {
                if (typeof visitorsData[code] != 'undefined')
                    el.html(el.html() + ': ' + visitorsData[code] + ' new visitors');
            }
        });
</script>
</html>
Posted in package | Leave a comment

GitHub Desktop for Mac 汉化语言包

适用范围

  • MacBook Air macOS Monterey 12.6 (m1)
  • GitHub DeskTop for Mac 3.1.1 (arm64)
# 下载
npm install github-desktop-for-mac-language-zh-cn
# 安装 
# cd you project root path run:
sudo bash install.sh 
# or
sudo bash install.sh install
# 还原
sudo bash install.sh uninstall
github desktop 汉化包
Posted in package | Leave a comment

Vue项目中定时器动态修改时间间隔

<script>
export default {
  name: "IndexVue",
  data() {
    return {
      // 定时器标识
      mySetInterval:"",
      // 定时任务序列
      sequence:[
        {n:1,time:300,options:{}},
        {n:2,time:300,options:{}},
        {n:3,time:300,options:{}},
        {n:4,time:300,options:{}},
      ]
  },
  methods: {
  // 开启定时器
    openMySetInterval(callback){
      this.mySetInterval =setInterval(
        this.mySetIntervalCallback,0,callback
      );
    },
    // 定时器回调函数
    mySetIntervalCallback(callback,options=""){
      if (this.sequence.length > 0) {
         // 复制一份数据
         let n = this.sequence[0].n ;
         let time = this.sequence[0].time;
         let options = this.sequence[0].options;
         // 删除第一个元素
         this.sequence.shift();
         // 销毁定时器重新赋值
         clearInterval(this.mySetInterval);
         this.mySetInterval =setInterval(
           this.mySetIntervalCallback,
           time,callback,options
         );
      }else{
        // 销毁定时器
        clearInterval(this.mySetInterval);
       // 执行定时器结束的回调
       callback();
      }
    }
  }
}
</script>
Posted in js, Vue | Leave a comment