php docker 安装扩展

在php docker 中有如下命令,方便使用
1. docker-php-source
源码文件目录控制命令

ocker-php-source [extract | delete]

extract : 创建并初始化 /usr/src/php目录
delete : 删除 /usr/src/php目录

2. docker-php-ext-install
扩展安装命令,需要源码目录存在

#
docker-php-ext-install [扩展目录名(比如redis)]

3 docker-php-ext-enable
启动扩展命令

docker-php-ext-enable [扩展目录名(比如redis)]

4. docker-php-ext-configure
安装扩展时,自定义扩展配置的命令,提供了一个自定义扩展的方法,比如说安装gd库,配置基础库路径

docker-php-ext-configure gd --with-freetype-dir=/usr/include/ --with-jpeg-dir=/usr/include/ 
docker-php-ext-install -j$(nproc) gd #nproc系统最大内核数,-j编译时的参数,作用是提高编译速度
发表在 docker | php docker 安装扩展已关闭评论

堆排序php

关于堆排序的理论网上有许多,就不多做解释,一般在非常大的数据集中,按排序获取前面一段排序结果,使用堆排序。
堆排序的时间复杂度为:O(nlogn);
空间复杂度为常数:O(1)

/**
 * 堆排序
 * @param array $ary 待排序输入
 * @param $func $大顶堆func 或者 $小顶堆func
 * @param int $num 结果数量,比如说获取最小前10个数,默认返回所有排序
 * @return array
 */
function mysort($ary, $func, $num = 0)
{
    $length = count($ary);
    $_ = 0;
    while ($_++ < $num) {
        if ($length == 1) {
            break;
        }
        for ($index = floor($length / 2) - 1; $index >= 0; $index--) {
            if ($length - 1 >= (2 * $index + 2)) {
                $func($ary[$index], $ary[2 * $index + 1], $ary[2 * $index + 2]);
            } else {
                $func($ary[$index], $ary[2 * $index + 1]);
            }
        }

        list($ary[0], $ary[$length-1]) = [$ary[$length-1], $ary[0]];
        $length--;
    }
    return $num < count($ary) ? array_slice($ary, -$num) : $ary;
}

$大顶堆func = function (&$a1, &$a2, &$a3 = null) {
    if ($a1 < $a2) {
        list($a2, $a1) = [$a1, $a2];
    }

    if (!is_null($a3)) {
        if ($a1 < $a3) {
            list($a1, $a3) = [$a3, $a1];
        }
    }
};

$小顶堆func = function (&$a1, &$a2, &$a3 = null) {
    if ($a1 > $a2) {
        list($a2, $a1) = [$a1, $a2];
    }

    if (!is_null($a3)) {
        if ($a1 > $a3) {
            list($a1, $a3) = [$a3, $a1];
        }
    }
};

$ary = [ 1, 0, 2,10,8,21,3,6,7,5,11,121,43,-1];
$res = mysort($ary, $小顶堆func, 7);
echo print_r($res);
发表在 php, php函数集 | 标签为 | 堆排序php已关闭评论

OpenVPN 实现用户密码登录

1. server.conf中添加下面的设置

auth-user-pass-verify /opt/openvpn/checkpsw.sh via-env #密码验证脚本
script-security 3 
client-cert-not-required #不请求客户的CA证书,使用User/Pass验证,如果同时启用证书和密码认证,注释掉该行

username-as-common-name  #表示客户端认证时候需要用户名

2. 生成密码验证脚本
1)方法一:下载链接:http://openvpn.se/files/other/checkpsw.sh
2)方法二:checkpsw.sh 内容如下,自己创建到 /opt/openvpn/checkpsw.sh

#!/bin/sh

###########################################################

# checkpsw.sh (C) 2004 Mathias Sundman 

#

# This script will authenticate OpenVPN users against

# a plain text file. The passfile should simply contain

# one row per user with the username first followed by

# one or more space(s) or tab(s) and then the password.



PASSFILE="/opt/openvpn/psw-file"

LOG_FILE="/opt/openvpn/logs/openvpn-password.log"

TIME_STAMP=`date "+%Y-%m-%d %T"`



###########################################################



if [ ! -r "${PASSFILE}" ]; then

echo "${TIME_STAMP}: Could not open password file \"${PASSFILE}\" for reading." >> ${LOG_FILE}

exit 1

fi



CORRECT_PASSWORD=`awk '!/^;/&&!/^#/&&$1=="'${username}'"{print $2;exit}' ${PASSFILE}`



if [ "${CORRECT_PASSWORD}" = "" ]; then

echo "${TIME_STAMP}: User does not exist: username=\"${username}\", password=\"${password}\"." >> ${LOG_FILE}

exit 1

fi



if [ "${password}" = "${CORRECT_PASSWORD}" ]; then

echo "${TIME_STAMP}: Successful authentication: username=\"${username}\"." >> ${LOG_FILE}

exit 0

fi



echo "${TIME_STAMP}: Incorrect password: username=\"${username}\", password=\"${password}\"." >> ${LOG_FILE}

exit 1

3. 创建账户密码文件

touch /opt/openvpn/logs/psw-file
chown nobody:nobody /opt/openvpn/psw-file 

psw-file文件内容是:

username1 pwd1
username2 pwd2

4.重启openvpn

5. 客户端配置添加配置

auth-user-pass

其他注意事项:
1. 没有密码访问日志没有日志
解决方案,权限不对,openvpn是用 nobody:nobody,日志文件使用nobody:nobody

服务器配置文件如下:
server_user_pwd_conf

发表在 VPN, 运维 | 标签为 , | OpenVPN 实现用户密码登录已关闭评论

阿里云配置OpenVPN

通过好些天的研究,终于把OpenVPN配置成功了。记录一下遇到的坑
1. 按照网上找的安装步骤一步一步安装,但是最终链接不上VPN。提示权限错误。
解放方案:
A. 配置中未加上 tls-auth ta.key 0,生成方式:openvpn --genkey --secret ta.key,客户端添加配置:tls-auth ta.key 1

B. 使用的客户端版本不对,使用Tunnelblick,openVPN的版本不对,改使用Viscosity,链接成功
同时命令行客户端的链接命令为:/usr/local/Cellar/openvpn/2.4.8/sbin/openvpn tdvpnuser.ovpn

2. 客户端报错:
WARNING: Split DNS is being used however no DNS domains are present. The DNS server/s for this connection may not be used. For more information please see: https://www.sparklabs.com/support/kb/article/warning-split-dns-is-being-used-however-no-dns-domains-are-present/
解决方案:DOS设置的不对,使用了阿里的DNS,添加配置: push "dhcp-option DNS 223.5.5.5",

3. 连上VPN后,并没有使用VPN上网
解决方案:去掉配置注释:push "redirect-gateway def1 bypass-dhcp"

4. 链接上VPN只能ping通虚拟IP,不能ping通openvpn server上的物理网卡上的ip
解决方案:因为openvpen的路由设置错误,在配置中添加。 push "route 172.17.0.0 255.255.240.0"
因为物理网卡的网址的淹码是255.255.240.0,所以想了很长时间算出IP所在的网段(扔了好长时间的知识),IP网段设置好后,就可以ping通物理网卡的IP了

5. 不能上网,也不能ping通与openvpn server同网络的其他其他的ip
解决方案:添加路由规则:iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE
iptables非常好的教程

下面分别是配置文件
server配置

client配置.ovpn

6. 如果需要多个用户使用同一个证书,打开 duplicate-cn 配置。

至于怎么生成的加密文件,请自行搜索,网上有很多教程

发表在 VPN, 运维 | 标签为 , | 阿里云配置OpenVPN已关闭评论

企业微信-测试安装问题解决

1. 服务商的secret,在服务商管理后台可见
应用管理,通用开发参数中获取

2. 测试安装,提示“redirect_uri 与配置的授权完成回调域名不一致”
a. 需要调用接口“设置授权配置”,参数auth_type=1。这个设置在一段时间内会自动恢复成正式授权,要再次调用该接口重新配置。
b. "授权完成回调域名",就是安装回调域名,只要保证域名一样就行,可以自己配置路径
c. 要点击跳转到授权安装页面,能复制授权链接直接打开,授权页面会检查referer的域名的正确性

3. 调用企业服务接口的方法
我使用的是easyWeChat,用下面的方法拿到的具柄就可以使用企业服务接口了。比如说获取部门、获取用户列表等等

 $work = $app->work('授权企业的corp_id','授权企业的永久授权码');
发表在 企业微信 | 企业微信-测试安装问题解决已关闭评论

mysql 查询某个sql非常慢的方法

1. show processlist; 执行了时间,和观察因为某个进程导致之后的sql卡死的原因
2. SELECT trx_rows_locked,trx_mysql_thread_id FROM information_schema.innodb_trx;查看线程锁定的行数,和线程id

发表在 mysql | mysql 查询某个sql非常慢的方法已关闭评论

java 解决中文乱码的糟心之旅

在单位接手一个项目,java开发的,做开发多年,解决过各种奇葩问题,没想到差点在java中文乱码这跌跟头。

背景:

java项目是在另一个部门移过来的线上的工程,使用maven构建开发。迁移过来后在本地打包,传到服务器上遇到提交中文到数据库中是乱码的问题。

尝试解决方案:

1. 查看jdbc链接属性: jdbc:mysql://xxx.xxx.xxx.xxx:3306/xxx?useUnicode=true
确认使用参数testUnicode=true

2.确认数据库及表的编码(数据库也是从原部门直接dump过来的)
1)查看数据库编码:database encoding='utf-8 unicode';database collation='utf-8 unicode'
2)确认表、行编码,也是utf8;

3. 确认入参编码格式问题:
1)准备参数,通过浏览器拿到提交表单的curl命令
2)把curl的目标地址换成原部门测试环境,结果中文不会乱码,再把目标地址换回本地环境,结果中文乱码

4. 确认代码
1)跟原部门确认,代码是线上的,maven配置也是和线上环境一直的,线上一直没问题

5. 确认容器问题:
1)开始查看tomcat容器,tomcat用的是9(最新的)。在server.xml中设置 Connector 添加属性URIEncoding="UTF-8"(据说在tomcat8之后默认就是utf8了),结果不行
2)修改tomcat catalina.sh 文件,添加 JAVA_OPTS="$JAVA_OPTS -Dfile.encoding=UTF-8",结果不行
3)从原部门要来tomcat包(线上的),使用他们的tomcat,结果不行
4)原部门包分别执行5、6步骤,结果不行
5)yum下载tomcat重新部署,不行,分别执行5、6步骤,不行

到现在为止,已经过去了1天的时间,确定了入参、容器、代码还是没有解决问题(555555),从头开始。。。
1. 确认jdbc链接参数,发现useUnicode=true,但是没有写characterEncoding=utf-8,添加该参数,结果成功了,中文不再是乱码

已经找到了问题,是数据库链接的问题,为什么同样的数据库链接配置在原部门可用,在我们这就不行呢?继续~,去server上看my.cof,发现mysqld中没有设置默认编码,于是在[mysqld]中添加:character-set-server=utf8,重启mysql;从jdbc中拿掉characterEncoding参数,重新打包发布;结果ok。

后记心得:

1. 在部署mysql时,不要偷懒,一定要确认编码格式
2. 在代码中链接数据时,一定要显示指明编码情况,仅仅useUnicode=true是不够的(不能依赖数据库的配置)
3. 老生长谈的话,没有灵异的事件,只有没有发现的细节,慢慢来!!
4. 要有空杯心态,不要盲目的相信经验。解决不了的问题多余人交流。

发表在 java | 标签为 , | java 解决中文乱码的糟心之旅已关闭评论

go 发布

go的交叉编译,比如 我用的mac,需要编译的可执行文件在linux上,如下

CGO_ENABLED=0 GOOS=linux GOARCH=amd64 GOROOT=/usr/local/go GOPATH=/Users/wangchanghong/go go build -i -o ~/out/[文件名] 【编译目标】

#CGO_ENABLED 开启交叉编译
#GOOS 执行系统 linux
#GOARCH 运行目标版本 (可通过uname -a 获取)

发表在 go | go 发布已关闭评论

go 构建时提示 cannot find package “golang.org/x/[…]” 的解决办法

比如说 提示 cannot find package "golang.org/x/net"
1. 尝试执行下面的命令

go get golang.org/x/net

如果不成功则继续
2.

mkdir -p $GOPATH/src/golang.org/x
cd $GOPATH/src/golang.org/x
git clone https://github.com/golang/net.git

golang 在 github 上建立了一个镜像库,如 https://github.com/golang/net 对应的是 https://golang.org/x/net,其他亦然。。

发表在 go | go 构建时提示 cannot find package “golang.org/x/[…]” 的解决办法已关闭评论

php模式之装饰器模式2

在上一篇文章中,介绍了如何在代码架构之初,为了以后的扩展方便做的考虑,那么在现实中大部分的情况不是如此,那么我们需要重构这块么?不一定,今天我们使用另一种方式来实现装饰器。
假设现在我们处在产品的第二个阶段,有下面第一阶段代码来实现需求

class User{
    function loadData(){
        $res = 'load ...' . PHP_EOL;
        return $res;
    }
}

还是同样的,怎么在不改变调用逻辑 和 User::loadData 的基础上来扩展呢。php给我们提供了一个方案:Trait

//首先,我们先实现一个trait
trait Count{
     function loadData(){
         $res = parent::loadData();
         //count 的逻辑
         return $res;
     }
}
//接下来,把User类更名为UserBase
class UserBase {
    function loadData(){
        echo 'load ...' . PHP_EOL;
    }
}
//紧接着,重新写一个User类来继承 UserBase(如果不这样做,代码使用者估计打死你的),并且使用 Count
class User extends UserBase{
     use Count;
}

这样,我们就完成装饰器的功能,甚至能在不改变原来代码的情况下偷梁换柱做一些更加彻底的操作。

发表在 php, 设计模式 | php模式之装饰器模式2已关闭评论