admin 发布的文章

PhpStorm 2020.2 配置 xdebug 远程调试

WEB远程调试

Run > Web Server debug Validation 检查服务器 xdebug 配置

服务器安装 xdebug 扩展和 .ini 配置

zend_extension = xdebug.so
xdebug.remote_enable = 1
xdebug.remote_connect_back = 0 // 远程多IP调试 remote_addr 
xdebug.remote_host = 127.0.0.1 // 本地IP调试   远程调试使用ssh端口转发 ssh -g -N -R 9000:127.0.0.1:9000 user@server
xdebug.remote_port = 9000
xdebug.max_nesting_level = 512

Settings > Languages & Frameworks > PHP > Debug   配置本地监听端口9000
Settings > Languages & Frameworks > PHP > Servers 配置目录映射

Phpstorm > start listen for php debug connect 监听本地9000端口连接

接口调试携带 Cookie,触发 xdebug 启动:

curl -H "Cookie: XDEBUG_SESSION=PHPSTORM" http://example.com

CLI远程调试

Settings > Languages & Frameworks > PHP > Cli 配置CLI路径(本地/远程)

Run > Edit Configuration 添加 php 目标脚本,选择执行的 Cli 配置

Run > Debug 选择要调试的目标脚本、原理: 命令行携带 -d xdebug 相关参数执行触发调试

通过 dbgpProxy 实现多人调试

客户端 -> 中间机(启动dbgpProxy) -> 服务端

dbgpProxy.exe -i 127.0.0.1:9001 -s 0.0.0.0:9003 // -i 给ide链接、-s 给服务端xdebug链接

Settings > Languages & Frameworks > PHP > Debug > DBGp Proxy  设置 idekey / host / port (zhorz、127.0.0.1、9001)

服务端 xdebug 依然链接本地

xdebug.remote_host = 127.0.0.1
xdebug.remote_port = 9000

ssh -g -N -R 9000:127.0.0.1:9003 user@server // 中间机设置端口转发

Tool -> DBGp Proxy -> Register IDE Phpstorm // IDE注册,接收对应 idekey 转发的 debug 信息

Phpstorm > start listen for php debug connect 监听本地9000端口连接

接口调试携带 Cookie,触发 xdebug 启动:

curl -H "Cookie: XDEBUG_SESSION=zhorz" http://example.com

docker入门

docker linux的安装

# 下载
sudo wget -qO- https://get.docker.com/ | sh # 下载docker安装shell脚本

# 添加用户到docker用户组
sudo usermod -aG docker xbf # 用户xbf添加到docker用户组

# 安装后启动服务
service docker start

# 使用阿里云docker加速器
https://cr.console.aliyun.com/#/accelerator

docker命令

docker build # 建立一个新的image
docker pull nginx # 下载一个iamge
docker run -p 8080:80 -d nginx # 运行容器
docker ps # 查看运行的docker程容器
docker stop 容器ID # 停止运行
docker commit -m '备注' # 提交新的images
docker rmi image的ID # 删除image

编写简单文件自创docker镜像

# 新增文件夹下Dockerfile文件
FROM alpine:latest
MAINTAINER zhorz
CMD echo "Hello Docker"

# 在新建的文件夹下运行命令: docker build -t hello_docker . 

# dockerfile语法
FROM base image
RUN 执行命令
ADD 添加文件
COPY 拷贝文件
CMD 执行命令
EXPOSE 暴露端口
WORKDIR 指定路径
MAINTAINER 维护者
ENV 设定环境变量
ENTRYPOINT 容器入
USER 指定用户
VOLUME mount point

重新学习 20200628

更换 unbuntu 源 https://developer.aliyun.com/mirror/ubuntu?spm=a2c6h.13651102.0.0.11871b11drdcbT

docker 下载 和安装
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh

验证
apt list --installed | grep docker
sudo docker run hello-world

更换 docker 源 https://www.cnblogs.com/reasonzzy/p/11127359.html (最好用阿里云的,飞快)

重启使配置生效
sudo systemctl daemon-reload
sudo systemctl restart docker

windows 使用 docker : https://nickjanetakis.com/blog/setting-up-docker-for-windows-and-wsl-to-work-flawlessly

通过Dockerfile 安装

FROM php:7.4.6-fpm-buster
# 设置阿里云源
RUN echo 'deb http://mirrors.aliyun.com/debian/ buster main non-free contrib\n\
deb-src http://mirrors.aliyun.com/debian/ buster main non-free contrib\n\
deb http://mirrors.aliyun.com/debian-security buster/updates main\n\
deb-src http://mirrors.aliyun.com/debian-security buster/updates main\n\
deb http://mirrors.aliyun.com/debian/ buster-updates main non-free contrib\n\
deb-src http://mirrors.aliyun.com/debian/ buster-updates main non-free contrib\n\
deb http://mirrors.aliyun.com/debian/ buster-backports main non-free contrib\n\
deb-src http://mirrors.aliyun.com/debian/ buster-backports main non-free contrib' > /etc/apt/sources.list
RUN apt-get update
# gd库
RUN apt-get install -y \
        libfreetype6-dev \
        libjpeg62-turbo-dev \
        libpng-dev \
    && docker-php-ext-configure gd --with-freetype --with-jpeg \
    && docker-php-ext-install -j$(nproc) gd
# pdo
RUN apt-get update && docker-php-ext-install pdo_mysql
# yaf
RUN pecl install yaf && docker-php-ext-enable yaf
# redis 
RUN pecl install redis && docker-php-ext-enable redis
# apcu 
RUN pecl install apcu && docker-php-ext-enable apcu
# pcntl
RUN docker-php-ext-install pcntl
# 生产环境 dev 要改成  product
RUN echo '[yaf]\n\
yaf.environ="dev"\n\
yaf.use_namespace=On\n\
yaf.use_spl_autoload=1' >> /usr/local/etc/php/conf.d/docker-php-ext-yaf.ini

docker build -t sm:php74_v2 .

交互式进入容器
sudo docker run -it -v /home/vagrant:/home/vagrant sm:php74_v2 /bin/bash

启动php-fpm

docker run --name php74 -d -p 9000:9000 -v /home/vagrant:/home/vagrant sm:php74_v2 /usr/local/sbin/php-fpm

修改 nginx 端口指向

function php74(){
tty=
tty -s && tty=--tty
sudo docker run
$tty
--interactive
--rm
--volume $PWD:/home/vagrant
--workdir /home/vagrant
sm:php74_v2 php "$@"
}

更改全局composer源 composer config -g repo.packagist composer https://mirrors.aliyun.com/composer/

php composer.phar -vvv --ignore-platform-reqs install

问题 php:7.4.6-fpm-buster 镜像缺少 pcntl、git

  1. Dockerfile 中添加 docker-php-ext-install pcntl
  2. 从源码编译

sudo docker history php:7.4.6-fpm-buster --no-trunc --format "{{.CreatedBy}}"
得知源码地址 https://www.php.net/distributions/php-7.4.6.tar.gz

cd /path/to/php-source-code/ext/pcntl
phpize
./configure --enable-pcntl --with-php-config=/path/to/php-config
make && make install
php.ini 中 引入 extension=pcntl.so

es6中的promise相关

// 例子1
  const testPromise = new Promise(function (resolve, reject) {
    let a = 5
    if (a === 5) {
      resolve('success')
    } else {
      reject('catch error2')
    }
  })
  // resolve 结果没法处理,一直抛出去
  testPromise.then(null, (res) => {
    console.log(res, 1)
  }).then(null, res => {
    console.log(res, 2)
  }).then(res => {
    console.log(res, 3)
  })

// 例子2
const testPromise = new Promise(function (resolve, reject) {
    let a = 5
    if (a === 5) {
      resolve('success')
    } else {
      reject('catch error2')
    }
  })
  testPromise.then(res => { console.log('res1', res); return 123}, err => { console.log('err1', err)})
    .then(res => { console.log('res2', res)}, err => { console.log('err2', err); return Promise.reject(456);})
    .then(res => { console.log('res3', res)}, err => { console.log('err3', err)})
    .then(res => { console.log('res4', res)}, err => { console.log('err4', err)})

87BCF1C372C9D7FF8013EB6EC00D8517.png

AF1C4ADC74288ED1B08554A85194FF08.png

react学习笔记

阮一峰入门教程

jsx 基本语法规则 遇到 HTML 标签(以 < 开头),就用 HTML 规则解析;遇到代码块(以 { 开头),就用 JavaScript 规则解析

// 组件的使用
class HelloMessage extends React.Component {
    constructor(props) {
        super(props)
        this.state = {
            liked: false
        }
    }
    static propTypes = {
        title: PropTypes.string.isRequired, // 验证属性
    }
    static defaultProps = {
        name: 'zhorz' // 设置默认属性 
    }
    toggle() {
        this.setState({liked: this.state.liked}) // 重新渲染组件
    }
    render() {
        return <h1>hello {this.props.name} <button onClick={this.toggle.bind(this)}>change</button></h1> 
        // 只能包含一个顶层标签,属性通过 this.props 对象获取
        // 通过 this.props.children (可以用React.Children代替) 可以获取组件子节点,vue中使用插槽 solt 实现
    }
}

// 注意属性名 class -> className,for -> htmlFor
ReactDOM.render(<HelloMessage name="zhorz"/>, document.getElementById('example'))


// react 获取 dom 的几种方式

class HelloMessage extends React.Component {
    handleClick() {
        this.refs.my.focus()
    }
    render() {
        return (
            <div>
                <input type="text" ref="my" />
                <input type="button" value="Focus the text input" onClick={this.handleClick.bind(this)} />
            </div>
        );
    }
}

class HelloMessage extends React.Component {
    constructor(props) {
        super(props)
        this.my = React.createRef()
    }
    handleClick() {
        this.my.current.focus()
    }
    render() {
        return (
            <div>
                <input type="text" ref={this.my} />
                <input type="button" value="Focus the text input" onClick={this.handleClick.bind(this)} />
            </div>
        );
    }
}

class HelloMessage extends React.Component {
    handleClick() {
        this.my.focus()
    }
    handleClick2 = () => {
        this.my.focus() // 使用箭头 函数,这种方式就不用 bind 了,this 指向定义时所在的对象
    }
    render() {
        return (
            <div>
                <input type="text" ref={(el) => { this.my = el}} />
                <input type="button" value="Focus the text input" onClick={this.handleClick2} />
            </div>
        );
    }
}

ReactDOM.render(
    <HelloMessage name="zhorz" />,
    document.getElementById('example')
);

style={{opacity: this.state.opacity}}
// 因为 React 组件样式是一个对象,所以第一重大括号表示这是 JavaScript 语法,第二重大括号表示样式对象

极客时间demo

create-react-app 模块按需加载

create-react-app 引入组件

php+redis实现令牌桶限流

<?php
class RateLimit
{
    private $minNum = 60; //单个用户每分访问数
    private $dayNum = 10000; //单个用户每天总的访问量

    public function minLimit($uid)
    {
        $minNumKey = $uid . '_minNum';
        $dayNumKey = $uid . '_dayNum';
        $resMin    = $this->getRedis($minNumKey, $this->minNum, 60);
        $resDay    = $this->getRedis($minNumKey, $this->minNum, 86400);
        if (!$resMin['status'] || !$resDay['status']) {
            exit($resMin['msg'] . $resDay['msg']);
        }
    }

    public function getRedis($key, $initNum, $expire)
    {
        $nowtime  = time();
        $result   = ['status' => true, 'msg' => ''];
        $redisObj = $this->di->get('redis');
        $redis->watch($key); // redis watch 处理并发
        $limitVal = $redis->get($key);
        if ($limitVal) {
            $limitVal = json_decode($limitVal, true);
            $newNum   = min($initNum, ($limitVal['num'] - 1) + (($initNum / $expire) * ($nowtime - $limitVal['time'])));
            if ($newNum > 0) {
                $redisVal = json_encode(['num' => $newNum, 'time' => time()]);
            } else {
                return ['status' => false, 'msg' => '当前时刻令牌消耗完!'];
            }
        } else {
            $redisVal = json_encode(['num' => $initNum, 'time' => time()]);
        }
        $redis->multi();
        $redis->set($key, $redisVal);
        $rob_result = $redis->exec();
        if (!$rob_result) {
            $result = ['status' => false, 'msg' => '访问频次过多!'];
        }
        return $result;
    }
}