任务命令行
-
~~~
<?php
/**
* @Author: 陈静
* @Date: 2018/04/18 22:13:03
* @Description:
*/
namespace app\console;
use app\base\controller\Redis;
use think\Config;
use think\console\Command;
use think\console\Input;
use think\console\Output;
use think\Exception;
use think\Log;
/**
* Created by PhpStorm.
* Power by Mikkle
* QQ:776329498
* Date: 2017/6/12
* Time: 15:07
*/
class Task extends Command
{
protected $sleep = 10;
protected $redis;
protected $workerListName;
protected $pcntl;
public function __construct($name= null)
{
parent::__construct($name);
$this->redis=Redis::instance(Config::get("redis"));
$this->workerListName = "worker_list";//任务名(同执行命令时,插入hash中的任务名)
$this->pcntl =true;//是否开启多进程处理任务
}
protected function configure()
{
$this->setName('task:queue')->setDescription('Here is the task\'s command ');
}
protected function execute(Input $input, Output $output)
{
while(true){
//标记后端服务运行中
$this->signWorking();
echo "==================================================".PHP_EOL;
$this->autoClass();
echo "==================================================".PHP_EOL;
$this->sleep();
}
}
/**
* @Author: 陈静
* @Date: 2018/04/21 14:15:56
* @Description: 开始标记命令执行中,存入redis
*/
public function signWorking(){
$this->redis->set("command","true");
$this->redis->setExpire("command",10);
}
/**
* 自动执行
* Power: Mikkle
* Email:776329498@qq.com
* @return bool
*/
protected function autoClass()
{
$works = $this->getWorks();
if ($works) {
foreach ($works as $item => $work) {
if ($this->pcntl) {
$this->pcntlWorker($work, $item);
} else {
$this->runWorker($work, $item);
}
}
} else {
return false;
}
}
public function getWorks(){
try{
return $this->redis->hget($this->workerListName);
}catch (Exception $e){
return false;
}
}
/**
* 检测执行方法是否存在
* Power: Mikkle
* Email:776329498@qq.com
* @param $work
* @param $item
* @return bool
*/
protected function checkWorkerExists($work,$item){
if (class_exists($work)){
if(method_exists($work,'run')){
return true;
}else{
return false;
}
}
}
/**
* 运行任务
* Power: Mikkle
* Email:776329498@qq.com
* @param $work
* @param $item
*/
protected function runWorker($work,$item){
try{
if($this->checkWorkerExists($work, $item)) {
echo "执行[{$work}]任务" . PHP_EOL;
$work::run();
Log::notice("执行[{$work}]任务");
}else{
echo "执行[{$work}]任务的run方法不存在".PHP_EOL;
$this->redis->hdel($this->workerListName,$item);
}
}catch (Exception $e){
echo "执行[{$work}]任务失败" . PHP_EOL;
Log::notice($e->getMessage());
if ($this->pcntl) {
$this->pcntlKill();
}
}
}
/**
* 分进程
* Power: Mikkle
* Email:776329498@qq.com
* @param $work
* @param $item
*/
protected function pcntlWorker($work,$item)
{
try{
// 通过pcntl得到一个子进程的PID
$pid = pcntl_fork();
if ($pid == -1) {
// 错误处理:创建子进程失败时返回-1.
die ('could not fork');
} else if ($pid) {
// 父进程逻辑
// 等待子进程中断,防止子进程成为僵尸进程。
// WNOHANG为非阻塞进程,具体请查阅pcntl_wait PHP官方文档
pcntl_wait($status, WNOHANG);
} else {
// 子进程逻辑
$pid_2 = pcntl_fork();
if ($pid_2 == -1) {
// 错误处理:创建子进程失败时返回-1.
die ('could not fork');
} else if ($pid_2) {
// 父进程逻辑
echo "父进程逻辑开始" . PHP_EOL;
// 等待子进程中断,防止子进程成为僵尸进程。
// WNOHANG为非阻塞进程,具体请查阅pcntl_wait PHP官方文档
pcntl_wait($status, WNOHANG);
echo "父进程逻辑结束" . PHP_EOL;
} else {
// 子进程逻辑
echo "子进程逻辑开始" . PHP_EOL;
$this->runWorker($work,$item);
echo "子进程逻辑结束" . PHP_EOL;
$this->pcntlKill();
}
$this->pcntlKill();
}
}catch (Exception $e){
Log::error($e->getMessage());
}
}
/**
* Kill子进程
* Power: Mikkle
* Email:776329498@qq.com
*/
protected function pcntlKill(){
// 为避免僵尸进程,当子进程结束后,手动杀死进程
if (function_exists("posix_kill")) {
posix_kill(getmypid(), SIGTERM);
} else {
system('kill -9' . getmypid());
}
exit ();
}
public function sleep($second=""){
$second = $second ? $second : $this->sleep;
// sleep(sleep($second)); //TP5的命令行 sleep($second) 不生效
sleep($second);
echo "睡眠{$second}秒成功!当前时间:" . date('h:i:s') . PHP_EOL;
}
/**
* @return int
*/
public function getSleep()
{
return $this->sleep;
}
/**
* @param int $sleep
* @return void
*/
public function setSleep($sleep)
{
$this->sleep = $sleep;
}
}
~~~
worker基类源码
-
~~~
<?php
/**
* @Author: 陈静
* @Date: 2018/04/18 23:08:29
* @Description:
*/
namespace app\worker\controller;
use app\base\controller\Redis;
use think\Config;
abstract class Base
{
protected $redis;
protected $workerListName;
protected $workerName;
public static $instance;
/**
* Base constructor.
* @param array $options
*/
public function __construct($options=[])
{
$this->redis = $this->redis();
$this->workerListName = "worker_list";
$this->workerName = get_called_class();
}
/**
* redis加载自定义Redis类
* Power: Mikkle
* Email:776329498@qq.com
* @param array $options
* @return Redis
*/
protected static function redis($options=[]){
$options = empty($options) ? $redis = Config::get("redis") : $options;
return Redis::instance($options);
}
/**
* 标注命令行执行此任务
* Power: Mikkle
* Email:776329498@qq.com
*/
public function runWorker(){
$this->redis->hset($this->workerListName,$this->workerName,$this->workerName);
}
/**
* 标注命令行清除此任务
* Power: Mikkle
* Email:776329498@qq.com
*/
public function clearWorker(){
$this->redis->hdel($this->workerListName,$this->workerName);
}
/**
* Power: Mikkle
* Email:776329498@qq.com
* @param array $options
* @return static
*/
static public function instance($options=[]){
if (isset(self::$instance)){
return self::$instance;
}else{
return new static($options);
}
}
}
~~~
控制器,添加任务类
-
~~~
<?php
/**
* @Author: 陈静
* @Date: 2018/04/20 22:54:12
* @Description:
*/
namespace app\worker\controller;
use think\Exception;
use think\Log;
class RecordLog extends Base
{
protected $options=[];
protected $listName;
public function __construct($options=[])
{
parent::__construct();
$this->listName = md5($this->workerName);
}
/**
* 检测命令行是否执行中
* Power: Mikkle
* Email:776329498@qq.com
* @return bool
*/
static public function checkCommandRun(){
return self::redis()->get("command") ? true :false;
}
/**
* @Author: 陈静
* @Date: 2018/04/21 14:48:09
* @Description: 将数据压入栈中
* @param $data
* @param array $options
*/
static public function add($data,$options=[]){
$instance = self::instance($options);
//检查命令是否执行中
// if (self::checkCommandRun()) {
$instance->redis->lpush($instance->listName, $data);
$instance->runWorker();
// }
}
/**
* 命令行执行的方法
* Power: Mikkle
* Email:776329498@qq.com
*/
static public function run(){
$instance = self::instance();
try{
$i = 0;
while(true){
$data = $instance->redis->rpop($instance->listName);
if ($data){
$re=$instance->sendMessage($data);
Log::notice($re);
}else{
break;
}
$i++;
sleep(1);
}
$instance->clearWorker();
echo "执行了{$i}次任务".PHP_EOL;
}catch (Exception $e){
Log::error($e);
$instance->clearWorker();
die($e->getMessage());
}
}
/**
* 发送模版消息的方法
* Power: Mikkle
* Email:776329498@qq.com
* @param $data
* @return bool
*/
protected function sendMessage($data){
$no = $data;
if ($no){
Log::notice("发送成功[{$no}]");
return true ;
}else{
Log::notice("发送失败[{$no}]");
$this->failed($data);
};
}
/**
* 出错执行的回调方法
* Power: Mikkle
* Email:776329498@qq.com
* @param $data
*/
protected function failed($data){
}
}
~~~
Redis类,使用的是mikkle的,感谢
-
~~~
<?php
namespace app\base\controller;
use think\Exception;
use think\Log;
/**
* Class Redis redis操作类,集成了redis常用的操作方法
*/
class Redis
{
public $redisObj = null;//redis实例化时静态变量
static protected $instance;
protected $sn;
protected $index = 0;
protected $port = 6379;
protected $auth = "";
protected $host = "127.0.0.1";
public function __construct($options = [])
{
$host = trim(isset($options["host"]) ? $options["host"] : $this->host);
$port = trim(isset($options["port"]) ? $options["port"] : $this->port);
$auth = trim(isset($options["auth"]) ? $options["auth"] : $this->auth);
$index = trim(isset($options["index"]) ? $options["index"] : $this->index);
if (!is_integer($index) && $index > 16) {
$index = 0;
}
$sn = md5("{$host}{$port}{$auth}{$index}");
$this->sn = $sn;
if (!isset($this->redisObj[$this->sn])) {
try {
$this->redisObj[$this->sn] = new \Redis();
$this->redisObj[$this->sn]->connect($host, $port);
$this->redisObj[$this->sn]->auth($auth);
$this->redisObj[$this->sn]->select($index);
} catch (Exception $e) {
Log::notice($e->getMessage());
try {
$this->redisObj[$this->sn] = new \Redis();
$this->redisObj[$this->sn]->connect($host, $port);
$this->redisObj[$this->sn]->auth($auth);
$this->redisObj[$this->sn]->select($index);
} catch (Exception $e) {
Log::error($e->getMessage());
}
}
}
$this->redisObj[$this->sn]->sn = $sn;
$this->index = $index;
}
/**
* Power: Mikkle
* Email:776329498@qq.com
* @param array $options
* @return Redis
*/
public static function instance($options = [])
{
if (self::$instance == null){
return self::$instance = new Redis($options);
}
return self::$instance;
}
public function getKeys($key = '*')
{
return $this->redisObj[$this->sn]->getKeys($key);
}
public function setExpire($key, $time = 0)
{
if (!$key) {
return false;
}
switch (true) {
case ($time == 0):
return $this->redisObj[$this->sn]->expire($key, 0);
break;
case ($time > time()):
$this->redisObj[$this->sn]->expireAt($key, $time);
break;
default:
return $this->redisObj[$this->sn]->expire($key, $time);
}
}
/*------------------------------------start 1.string结构----------------------------------------------------*/
/**
* 增,设置值 构建一个字符串
* @param string $key KEY名称
* @param string $value 设置值
* @param int $timeOut 时间 0表示无过期时间
* @return true【总是返回true】
*/
public function set($key, $value, $timeOut = 0)
{
$setRes = $this->redisObj[$this->sn]->set($key, $value);
if ($timeOut > 0) $this->redisObj[$this->sn]->expire($key, $timeOut);
return $setRes;
}
/**
* 查,获取 某键对应的值,不存在返回false
* @param $key ,键值
* @return bool|string ,查询成功返回信息,失败返回false
*/
public function get($key)
{
$setRes = $this->redisObj[$this->sn]->get($key);//不存在返回false
if ($setRes === 'false') {
return false;
}
return $setRes;
}
/*------------------------------------1.end string结构----------------------------------------------------*/
/*------------------------------------2.start list结构----------------------------------------------------*/
/**
* 增,构建一个列表(先进后去,类似栈)
* @param String $key KEY名称
* @param string $value 值
* @param $timeOut |num 过期时间
*/
public function lPush($key, $value, $timeOut = 0)
{
// echo "$key - $value \n";
$re = $this->redisObj[$this->sn]->LPUSH($key, $value);
if ($timeOut > 0) $this->redisObj[$this->sn]->expire($key, $timeOut);
return $re;
}
/**
* 增,构建一个列表(先进先去,类似队列)
* @param string $key KEY名称
* @param string $value 值
* @param $timeOut |num 过期时间
*/
public function rPush($key, $value, $timeOut = 0)
{
// echo "$key - $value \n";
$re = $this->redisObj[$this->sn]->RPUSH($key, $value);
if ($timeOut > 0) $this->redisObj[$this->sn]->expire($key, $timeOut);
return $re;
}
/**
* 查,获取所有列表数据(从头到尾取)
* @param string $key KEY名称
* @param int $head 开始
* @param int $tail 结束
*/
public function lRanges($key, $head, $tail)
{
return $this->redisObj[$this->sn]->lrange($key, $head, $tail);
}
/**
* Power by Mikkle
* QQ:776329498
* @param $key
* @return mixed
*/
public function rPop($key)
{
return $this->redisObj[$this->sn]->rPop($key);
}
public function lPop($key)
{
return $this->redisObj[$this->sn]->lpop($key);
}
/*------------------------------------2.end list结构----------------------------------------------------*/
/*------------------------------------3.start set结构----------------------------------------------------*/
/**
* 增,构建一个集合(无序集合)
* @param string $key 集合Y名称
* @param string|array $value 值
* @param int $timeOut 时间 0表示无过期时间
* @return
*/
public function sAdd($key, $value, $timeOut = 0)
{
$re = $this->redisObj[$this->sn]->sadd($key, $value);
if ($timeOut > 0) $this->redisObj[$this->sn]->expire($key, $timeOut);
return $re;
}
/**
* 查,取集合对应元素
* @param string $key 集合名字
*/
public function sMembers($key)
{
$re = $this->redisObj[$this->sn]->exists($key);//存在返回1,不存在返回0
if (!$re) return false;
return $this->redisObj[$this->sn]->smembers($key);
}
/*------------------------------------3.end set结构----------------------------------------------------*/
/*------------------------------------4.start sort set结构----------------------------------------------------*/
/*
* 增,改,构建一个集合(有序集合),支持批量写入,更新
* @param string $key 集合名称
* @param array $score_value key为scoll, value为该权的值
* @return int 插入操作成功返回插入数量【,更新操作返回0】
*/
public function zadd($key, $score_value, $timeOut = 0)
{
if (!is_array($score_value)) return false;
$a = 0;//存放插入的数量
foreach ($score_value as $score => $value) {
$re = $this->redisObj[$this->sn]->zadd($key, $score, $value);//当修改时,可以修改,但不返回更新数量
$re && $a += 1;
if ($timeOut > 0) $this->redisObj[$this->sn]->expire($key, $timeOut);
}
return $a;
}
/**
* 查,有序集合查询,可升序降序,默认从第一条开始,查询一条数据
* @param $key ,查询的键值
* @param $min ,从第$min条开始
* @param $max,查询的条数
* @param $order ,asc表示升序排序,desc表示降序排序
* @return array|bool 如果成功,返回查询信息,如果失败返回false
*/
public function zRange($key, $min = 0, $num = 1, $order = 'desc')
{
$re = $this->redisObj[$this->sn]->exists($key);//存在返回1,不存在返回0
if (!$re) return false;//不存在键值
if ('desc' == strtolower($order)) {
$re = $this->redisObj[$this->sn]->zrevrange($key, $min, $min + $num - 1);
} else {
$re = $this->redisObj[$this->sn]->zrange($key, $min, $min + $num - 1);
}
if (!$re) return false;//查询的范围值为空
return $re;
}
/**
* 返回集合key中,成员member的排名
* @param $key,键值
* @param $member,scroll值
* @param $type ,是顺序查找还是逆序
* @return bool,键值不存在返回false,存在返回其排名下标
*/
public function zrank($key, $member, $type = 'desc')
{
$type = strtolower(trim($type));
if ($type == 'desc') {
$re = $this->redisObj[$this->sn]->zrevrank($key, $member);//其中有序集成员按score值递减(从大到小)顺序排列,返回其排位
} else {
$re = $this->redisObj[$this->sn]->zrank($key, $member);//其中有序集成员按score值递增(从小到大)顺序排列,返回其排位
}
if (!is_numeric($re)) return false;//不存在键值
return $re;
}
/**
* 返回名称为key的zset中score >= star且score <= end的所有元素
* @param $key
* @param $member
* @param $star,
* @param $end ,
* @return array
*/
public function zrangbyscore($key, $star, $end)
{
return $this->redisObj[$this->sn]->ZRANGEBYSCORE($key, $star, $end);
}
/**
* 返回名称为key的zset中元素member的score
* @param $key
* @param $member
* @return string ,返回查询的member值
*/
function zScore($key, $member)
{
return $this->redisObj[$this->sn]->ZSCORE($key, $member);
}
/*------------------------------------4.end sort set结构----------------------------------------------------*/
/*------------------------------------5.hash结构----------------------------------------------------*/
public function hSetJson($redis_key, $field, $data, $timeOut = 0)
{
$redis_info = json_encode($data); //field的数据value,以json的形式存储
$re = $this->redisObj[$this->sn]->hSet($redis_key, $field, $redis_info);//存入缓存
if ($timeOut > 0) $this->redisObj[$this->sn]->expire($redis_key, $timeOut);//设置过期时间
return $re;
}
public function hGetJson($redis_key, $field)
{
$info = $this->redisObj[$this->sn]->hget($redis_key, $field);
if ($info) {
$info = json_decode($info, true);
} else {
$info = false;
}
return $info;
}
public function hSet($redis_key, $name, $data, $timeOut = 0)
{
$re = $this->redisObj[$this->sn]->hset($redis_key, $name, $data);
if ($timeOut > 0) $this->redisObj[$this->sn]->expire($redis_key, $timeOut);
return $re;
}
public function hSetNx($redis_key, $name, $data, $timeOut = 0)
{
$re = $this->redisObj[$this->sn]->hsetNx($redis_key, $name, $data);
if ($timeOut > 0) $this->redisObj[$this->sn]->expire($redis_key, $timeOut);
return $re;
}
/**
* 增,普通逻辑的插入hash数据类型的值
* @param $key ,键名
* @param $data |array 一维数组,要存储的数据
* @param $timeOut |num 过期时间
* @return $number 返回OK【更新和插入操作都返回ok】
*/
public function hMset($key, $data, $timeOut = 0)
{
$re = $this->redisObj[$this->sn]->hmset($key, $data);
if ($timeOut > 0) $this->redisObj[$this->sn]->expire($key, $timeOut);
return $re;
}
/**
* 查,普通的获取值
* @param $key ,表示该hash的下标值
* @return array 。成功返回查询的数组信息,不存在信息返回false
*/
public function hVals($key)
{
$re = $this->redisObj[$this->sn]->exists($key);//存在返回1,不存在返回0
if (!$re) return false;
$vals = $this->redisObj[$this->sn]->hvals($key);
$keys = $this->redisObj[$this->sn]->hkeys($key);
$re = array_combine($keys, $vals);
foreach ($re as $k => $v) {
if (!is_null(json_decode($v))) {
$re[$k] = json_decode($v, true);//true表示把json返回成数组
}
}
return $re;
}
/**
*
* @param $key
* @param $filed
* @return bool|string
*/
public function hGet($key, $filed = [])
{
if (empty($filed)) {
$re = $this->redisObj[$this->sn]->hgetAll($key);
} elseif (is_string($filed)) {
$re = $this->redisObj[$this->sn]->hget($key, $filed);
} elseif (is_array($filed)) {
$re = $this->redisObj[$this->sn]->hMget($key, $filed);
}
if (!$re) {
return false;
}
return $re;
}
public function hDel($redis_key, $name)
{
$re = $this->redisObj[$this->sn]->hdel($redis_key, $name);
return $re;
}
public function hLan($redis_key)
{
$re = $this->redisObj[$this->sn]->hLen($redis_key);
return $re;
}
public function hIncre($redis_key, $filed, $value = 1)
{
return $this->redisObj[$this->sn]->hIncrBy($redis_key, $filed, $value);
}
/**
* 检验某个键值是否存在
* @param $keys keys
* @param string $type 类型,默认为常规
* @param string $field 若为hash类型,输入$field
* @return bool
*/
public function hExists($keys, $field = '')
{
$re = $this->redisObj[$this->sn]->hexists($keys, $field);//有返回1,无返回0
return $re;
}
/*------------------------------------end hash结构----------------------------------------------------*/
/*------------------------------------其他结构----------------------------------------------------*/
/**
* 设置自增,自减功能
* @param $key ,要改变的键值
* @param int $num ,改变的幅度,默认为1
* @param string $member ,类型是zset或hash,需要在输入member或filed字段
* @param string $type,类型,default为普通增减 ,还有:zset,hash
* @return bool|int 成功返回自增后的scroll整数,失败返回false
*/
public function incre($key, $num = 1, $member = '', $type = '')
{
$num = intval($num);
switch (strtolower(trim($type))) {
case "zset":
$re = $this->redisObj[$this->sn]->zIncrBy($key, $num, $member);//增长权值
break;
case "hash":
$re = $this->redisObj[$this->sn]->hincrby($key, $member, $num);//增长hashmap里的值
break;
default:
if ($num > 0) {
$re = $this->redisObj[$this->sn]->incrby($key, $num);//默认增长
} else {
$re = $this->redisObj[$this->sn]->decrBy($key, -$num);//默认增长
}
break;
}
if ($re) return $re;
return false;
}
/**
* 清除缓存
* @param int $type 默认为0,清除当前数据库;1表示清除所有缓存
*/
function flush($type = 0)
{
if ($type) {
$this->redisObj[$this->sn]->flushAll();//清除所有数据库
} else {
$this->redisObj[$this->sn]->flushdb();//清除当前数据库
}
}
/**
* 检验某个键值是否存在
* @param $keys keys
* @param string $type 类型,默认为常规
* @param string $field 若为hash类型,输入$field
* @return bool
*/
public function exists($keys, $type = '', $field = '')
{
switch (strtolower(trim($type))) {
case 'hash':
$re = $this->redisObj[$this->sn]->hexists($keys, $field);//有返回1,无返回0
break;
default:
$re = $this->redisObj[$this->sn]->exists($keys);
break;
}
return $re;
}
/**
* 删除缓存
* @param string|array $key 键值
* @param $type 类型 默认为常规,还有hash,zset
* @param string $field ,hash=>表示$field值,set=>表示value,zset=>表示value值,list类型特殊暂时不加
* @return int | 返回删除的个数
*/
public function delete($key, $type = "default", $field = '')
{
switch (strtolower(trim($type))) {
case 'hash':
$re = $this->redisObj[$this->sn]->hDel($key, $field);//返回删除个数
break;
case 'set':
$re = $this->redisObj[$this->sn]->sRem($key, $field);//返回删除个数
break;
case 'zset':
$re = $this->redisObj[$this->sn]->zDelete($key, $field);//返回删除个数
break;
default:
$re = $this->redisObj[$this->sn]->del($key);//返回删除个数
break;
}
return $re;
}
//日志记录
public function logger($log_content, $position = 'user')
{
$max_size = 1000000; //声明日志的最大尺寸1000K
$log_dir = './log';//日志存放根目录
if (!file_exists($log_dir)) mkdir($log_dir, 0777);//如果不存在该文件夹,创建
if ($position == 'user') {
$log_filename = "{$log_dir}/User_redis_log.txt"; //日志名称
} else {
$log_filename = "{$log_dir}/Wap_redis_log.txt"; //日志名称
}
//如果文件存在并且大于了规定的最大尺寸就删除了
if (file_exists($log_filename) && (abs(filesize($log_filename)) > $max_size)) {
unlink($log_filename);
}
//写入日志,内容前加上时间, 后面加上换行, 以追加的方式写入
file_put_contents($log_filename, date('Y-m-d_H:i:s') . " " . $log_content . "\n", FILE_APPEND);
}
function flushDB()
{
$this->redisObj[$this->sn]->flushDB();
}
function __destruct()
{
$this->redisObj[$this->sn]->close();
}
/**
* 魔术方法 有不存在的操作的时候执行
* @access public
* @param string $method 方法名
* @param array $args 参数
* @return mixed
*/
public function __call($method, $args)
{
call_user_func_array([$this->redisObj[$this->sn], $method], $args);
}
}
~~~
本来想实现的是队列发消息记录日志,发送邮件通知的,结果发现sentry自带异步通知机制,所以先保存下来。
- PHP7新特性
- 优雅的写代码
- 常见的代码优化
- 常用的工具类
- PHP原生生成EXCEL
- PHP地理位置计算
- PHP获取服务器状态
- 驼峰转下划线
- 百度地图两点坐标距离计算
- 判断是否是url
- PHP常见header头
- 邮件发送类
- 阿拉伯数字转化为大写
- 获取汉字首个拼音
- 根据身份证号获取星座
- 生成验证码类
- 生成唯一ID
- 身份证验证类
- PHP中文转拼音
- Nginx配置文件
- curl获取网页内容
- 快递查询api
- 上传图片类
- 股票类
- 找回密码类
- 字符串助手函数
- 校验数据规则
- PHP获取收集相关信息
- 字符串截取助手函数
- 网页中提取关键字
- 检测浏览器语言
- 微信相关类
- 微信获取access_token
- 获取用户基本信息
- 代码规范
- 编程规范(psr-1,2)
- 编程规范(原作者的建议)
- 经验
- 常用函数地址
- 函数集合
- 一些常识
- MYSQL相关知识
- 常用sql
- mysql事务隔离级别
- Read uncommitted
- Read committed
- Repeatable read
- Serializable
- 高性能MYSQL读书笔记
- 第一章MYSQL的架构
- mysql逻辑架构
- redis相关知识
- 1.安装redis
- 3.php操作redis
- 队列
- 悲观锁
- 乐观锁
- 发布
- 订阅
- redis实战-文章投票
- 设计模式
- 创建模型实例
- 单例模式
- 工厂模式
- AnimalInterface.php
- Chicken.php
- Factory.php
- Farm.php
- Pig
- SampleFactory.php
- Zoo
- 抽象工厂模式
- AnimalFactory
- Factory
- FarmInterface
- Income
- PandaZoo
- PeonyZoo
- PigFarm
- PlantFactory
- RiceFarm
- ZooInterface
- 原型模式
- 建造者模式
- 结构型模式实例
- 桥接模式
- 享元模式
- 外观模式
- 适配器模式
- 装饰器模式
- 组合模式
- 代理模式哦
- 过滤器模式
- 行为型模式实例
- 模板模式
- 策略模式
- 状态模式
- 观察者模式
- 责任链模式
- 访问者模式
- 解释器模式
- 空对象模式
- 中介者模式
- 迭代器模式
- 命令模式
- 备忘录模式
- 网络知识
- 互联网协议概述
- nginx简易交互过程
- HTTP知识
- LINUX相关知识
- swoole学习
- 1.初识swoole
- 2.WebSocket PHP 即时通讯开发
- 3.异步多进程的 CURL
- 4.异步非阻塞多进程的 Http 服务器
- 5.TCP 服务器
- 5.1同步 TCP 客户端
- 5.2异步 TCP 客户端
- 6.UDP 服务器
- 7.异步多任务处理
- 8.毫秒定时器
- 9.高并发投票
- ThinkPHP5学习
- 命令行操作
- 所有命令行中用到的基类
- 1.base
- 2.WorkerBase
- 3.TimeWorkerBase
- 4.CycleWorkerBase
- 5.WorkerCommandBase
- 6.WorkerHookBase
- 1.基础命令实现
- 2.建立Linux上的守护源码
- 3.发送模板消息
- 4.基于命令行实现自己的队列模式
- 5.发送定时短信
- thinkphp5使用sentry
- sentry通知,记录日志
- 高级查询
- Kafka相关
- 1.安装
- 2.为php打扩展
- 3.kafka实现
- 一些工具搭建
- sentry日志收集系统搭建
- walle搭建
- php实现定时任务
- 检测文件变化