存档

‘PHP’ 分类的存档

诡异的Class_ZipArchive_not_found事件

2018年7月27日 评论已被关闭

最近在优化API的时候发现一个问题,百思不得其解,记录于此。

因业务需要,新开发了zip打包的API,但是耗时较长,想要做成异步/定时任务,于是开始在本地搭建环境,安装zip扩展,诡异的事情发生了,

报ZipArchive类不存在,

proj_not_found
在卸载了系统中原来版本比较低的libzip包(version 0.9)后,源码安装了https://nih.at/libzip/libzip-1.2.0.tar.gz的1.2.0版本,默认步骤,默认路径,
php对应的扩展也是使用源码目录下ext/zip安装好了,如图1
phpinfo_zip

 

 

cli模式下能看到有加载zip.so,

php-m

 

但是重新访问API还是报类不存在,经过几次测试,发现了些许线索。

a,在cli模式下是正常的,

b,php内置web服务器输出正常,

c,只有lnmp环境异常

php-s

normal

not_found

debug的方向就放在web服务器上了,

未完待续

 

 

 

分类: PHP 标签:

二分查找

2018年6月29日 评论已被关闭

二分查找也叫折半查找

[pcsh lang=”php” tab_size=”4″ message=”” hl_lines=”” provider=”manual”]

$a = [0,1,2,3,4,5,6];

function half($arr, $value){
	$low = 0;
	$high = count($arr)-1; //9

	if($value>$arr[$high] || $value<$arr[$low])
		return false;

	while($low <= $high){
		$mid = floor(($low+$high)/2);	//4
		if($value > $arr[$mid]){
			$low = $mid + 1;
		}
		elseif($value < $arr[$mid]){
			$high = $mid - 1;
		}
		else{
			return $mid;
		}

	}

	return -1;

	}

	$x = half($a, 2);
	var_dump($x);

[/pcsh]

分类: PHP 标签:

三大排序算法

2018年6月28日 评论已被关闭

冒泡排序

[pcsh lang=”php” tab_size=”4″ message=”” hl_lines=”” provider=”manual”]

function p(&$arr){
	$len = count($arr);
	for($i=0; $i<$len-1; $i++){
		for($j=0;$j<$len-1-$i;$j++){
			if($arr[$j]>$arr[$j+1]){
				$t = $arr[$j];
				$arr[$j] = $arr[$j+1];
				$arr[$j+1] = $t;
			}
		}
	}

}


$a = [8,1,6,3,5,0];

p($a);
print_r($a);

[/pcsh]

 

选择排序

[pcsh lang=”php” tab_size=”4″ message=”” hl_lines=”” provider=”manual”]

function s(&$arr){
	$len = count($arr);
	for($i=0; $i<$len-1; $i++){
		$min = $i;

		for($j=$i+1; $j<$len; $j++){
			if($arr[$min] > $arr[$j])
				$min = $j;
		}

		if($min != $i){
			$t = $arr[$min];
			$arr[$min] = $arr[$i];
			$arr[$i] = $t;
		}

	}

}

$a = [1,9,2,8,3,6,5,0];
s($a);
print_r($a);

[/pcsh]

 

插入排序

[pcsh lang=”php” tab_size=”4″ message=”” hl_lines=”” provider=”manual”]

function i(&$arr){
	$len = count($arr);
	for($i=1; $i<$len; $i++){
		$t = $arr[$i];

		for($j=$i-1; $j>=0 && $arr[$j] > $t; $j--){
			$arr[$j+1] = $arr[$j];
		}

		$arr[$j+1] = $t;

	}

}


$a = [1,9,2,8,3,7,4,6,0];
i($a);
print_r($a);

[/pcsh]

 

快速排序(递归)

[pcsh lang=”php” tab_size=”4″ message=”” hl_lines=”” provider=”manual”]

function quick($arr){
	if(count($arr) <= 1)
		return $arr;

	$mid = $arr[0];
	$left = [];
	$right = [];

	foreach($arr as $v){
		if($v > $mid)
			$right[] = $v;
		if($v < $mid)
			$left[] = $v;
	}

	return array_merge(quick($left), [$mid], quick($right));
}


$a = quick($a);
echo implode('-', $a), PHP_EOL;

[/pcsh]

//

分类: PHP 标签:

PHP下的“&”符号(一)

2016年7月6日 1 条评论

php的gc回收的bug,直接上图,先不要看图2,猜一下执行结果。

phpbug1

图1

 

phpbug2

图2

 

分类: PHP 标签:

PHP关于“\r\n”

2016年6月29日 评论已被关闭

今天偶然的情况下发现一个有意思的事情,图一的代码会生成图二的结果。

图一

图.1

 

 

图二

图.2

注意 点在最后的“len”和“nen”两行。

 

 

 

 

分类: PHP 标签:

解决PHPCLI进程长时间运行假死问题

2016年5月19日 评论已被关闭

解决办法之一,重启

[pcsh lang=”bash” tab_size=”4″ message=”” hl_lines=”” provider=”manual”]


01 01 * * * kill -USR2 `cat /usr/local/php7/var/run/php-fpm.pid`

[/pcsh]

或者

[pcsh lang=”bash” tab_size=”4″ message=”” hl_lines=”” provider=”manual”]


01 01 * * * kill -USR2 `ps -ef | grep -v grep | grep "php-fpm: master" | awk '{print $2}'`

[/pcsh]

 

 

分类: PHP 标签:

用PHP统计docx文章中的词频

2016年5月11日 评论已被关闭

一个初中同学现在在做英文文献的翻译,要我帮忙做一下单词的词频,以下

找了一下资料,需要用到一个叫做antiword的工具,下载地址如下

http://www.winfield.demon.nl/linux/antiword-0.37.tar.gz

Linux下直接make && make install 即可

但是是针对doc文件的,用office另存为选择doc格式就可以了,具体的PHP代码如下:

[pcsh lang=”php” tab_size=”4″ message=”” hl_lines=”” provider=”manual”]

<?php 

	$filename="/tmp/zhangyj.doc";

	//都是英文,不需要转utf8
	//$content = shell_exec('/root/bin/antiword -m UTF-8.txt '.$filedoc);
	$content = shell_exec('/root/bin/antiword '.$filename);

	//替换回车
	$content = strtolower( str_replace(chr(10), chr(32), $content) );

	//替换表格的竖线
	$content = preg_replace('/[|]+/',' ',$content);

	//替换多个空格为一个
	$content = preg_replace('/[ ]+/', ' ', $content);

	$wordArr = explode(' ', $content);

	$data = [];
	foreach($wordArr as $val) {

        $w = trim($val, '.,)(');
        
        if(array_key_exists($w, $data))
            $data[$w] ++;
        else
            $data[$w] = 1;
	}

	//保留索引,降序排列
	arsort($data);

	//一共有多少个词
	echo array_sum($data), PHP_EOL;

	print_r($data);
 

[/pcsh]

结果如下:

QQ20160511-2@2x

QQ20160511-3@2x

总字数9525,和word中给的9345误差不大。

分类: PHP 标签:

唯一随机数碰撞检测

2016年2月16日 2 条评论

在一个项目中,需要设计一个唯一的验证码用于线下的取票凭证,类似美团电影票取票码。要求是不能太长,太长了不方便用户记忆,太短的话重复几率太大。

其实计算机的随机数不是真正的随机数,是取的时钟的微秒纳秒之类的(忘了在哪看的过),只要样本数量够大是有碰撞的可能的,即便是md5加密,也不是有人出来说得到了md5的碰撞值。

怎么生成暂先不管,项目中的办法是随机数:

[pcsh lang=”php” tab_size=”4″ message=”” hl_lines=”” provider=”manual”]

rand(100000000,999999999)

[/pcsh]

为了检测到底在多大的订单量的时候发生唯一码碰撞,我写了下边的几行代码(PHP),需要用到pthread扩展支持多线程,php编译的时候也必须加上如下参数

–enable-maintainer-zts

由于会生成大量的码用于检测是否重复,这里用了memcached缓存

[pcsh lang=”php” tab_size=”4″ message=”随机码碰撞检测” hl_lines=”” provider=”manual”]

	$mem = new Memcached('certs-234432');
	$mem->addServer("192.168.37.7", 11211);
	$mem->flush();

//这里其实可以做单例写文件
	function record($str) {
		$f = '/tmp/log.cert';
		$handle = fopen($f, 'a+');
		fwrite($handle, $str);
		fclose($handle);
	}

	function work() {
		$mem = new Memcached('certs-234432');
		$mem->addServer("192.168.37.7", 11211);

		$f = false;
		$total = 10000000;
		$str = '';

		$t = microtime(true);

		for($i=0; $i<$total; $i++) {
		        $c = rand(100000000, 999999999);
		        if(!$mem->get($c)) {
					$mem->add($c, '1');
		        }else{
					$str = '循环次数'.number_format($total).",第".$i."\t次发生碰撞,". '碰撞的随机数是'.$c .",\t用时".( microtime(true) - $t ).'秒' .PHP_EOL;
					$f = true;
					echo $str;
					record($str);
					break;
		        }
		}

		if(!$f){
			$str = '循环次数'.number_format($total).",没有发生碰撞,";
			$str .= '用时:'.( microtime(true) - $t ).'秒' . PHP_EOL;
			record($str);
			echo $str ;
		}
	}

	class cert_threads extends Thread {
		public function run() {
			work(); 
		}
	}

	$res = array();

	for($j=0; $j<4; $j++) {
		$res[$j] = new cert_threads();
		$res[$j]->start();
	}

[/pcsh]

1000万次循环(1000万随机码)跑出来的结果是

1000万

1000万循环(随机码)

100万的结果是

100万

100万

可以明显的看出,100万一下数据量基本不会发生碰撞,发生的几次碰撞基本在104万,400万,500万,800万,所以,如果月订单量是百万级别,最好在随机码中加上月份唯一识别码。

这个只是随机数部分,完整的验证码在随机数前还有运动类型码,每个运动类型月订单量百万级别,我觉得未来3-5年基本上达不到吧。

 

如果行业发展很快,真的到了这个量级了,那么再加上时间吧

比如2015年6月,4位数字用1506,运动类型3位,随机码11位,一共18位,好像有点长。

可以在日期和运动类型上下功夫,比如15年06上线开始001,表示上线的第一个月。运动类型好像也没有必须用3位数999个运动类型那么多,变成2位,然后就是16位。

 

 

分类: PHP 标签:

管理Gearman

2015年9月9日 评论已被关闭

通常,Gearman被用来分发任务,以便实现非堵塞。下面捋捋如何管理Gearman。

说明:请自行安装好Gearman和PHP PECL Gearman。

准备

我们先来创建一个Worker,实现一个简单的显示功能:

[pcsh lang=”php” tab_size=”4″ message=”” hl_lines=”” provider=”manual”]

$worker= new GearmanWorker();

$worker->addServer('127.0.0.1', '4730');

$worker->addFunction('echo', 'my_echo_function');

while ($worker->work());

function my_echo_function($job) {
    return $job->workload();
}

[/pcsh]

然后我们运行它:

shell> php /path/to/worker/file

 

可能你已经注意到,代码里有一个死循环,是不是需要Sleep一下?让我们监测看看:

shell> strace -r php /path/to/worker/file
0.000099 poll([{fd=3, events=POLLIN}], 1, 10000) = 0 (Timeout)
10.006522 write(3, "\0REQ\0\0\0\t\0\0\0\0", 12) = 12

 

可见PHP PECL Gearman内部已经做了休息十秒的设置,我们就不用杞人忧天了。

接下来我们以Shell为Client来调用一下:

shell> gearman -f echo "hello, world."

 

到这里,准备工作基本就齐活儿了,相信大家已经对Gearman有了一个初步的认识。

管理

出于效率的考虑,我们往往会启动很多个Worker,但具体应该启动多少个呢?十个还是一百个?少了不够,多了浪费,到底应该如何度量呢?

其实Gearman本身已经提供了相应的命令供我们查看状态:

shell> (echo status; sleep 0.1) | nc 127.0.0.1 4730

 

命令的结果会分为四列,它们的含义从左到右依次是:

  1. Function name: A string denoting the name of the function of the job
  2. Number in queue: A positive integer indicating the total number of jobs for this function in the queue. This includes currently running ones as well (next column)
  3. Number of jobs running: A positive integer showing how many jobs of this function are currently running
  4. Number of capable workers: A positive integer denoting the maximum possible count of workers that could be doing this job. Though they may not all be working on it due to other tasks holding them busy.

 

从这些信息可以推断出:如果系统比较繁忙的话,Number of jobs running的数值会接近Number of capable workers;Number in queue可能会大于Number of capable workers。此时我们应该增加Worker的数量,反之则应该考虑减少Worker的数量。

另外,推荐大家结合使用watch命令来监控Gearman的状态,这样更直观一些:

shell> watch -n 1 "(echo status; sleep 0.1) | nc 127.0.0.1 4730"

 

实际应用中,还有很多特殊情况需要考虑,比如说:程序代码更新后,如何避免手动重启Worker?还需要注意的是Worker长时间运行,一旦意外中断或者内存泄漏怎么办?通常这类进程控制问题用Supervisor都可以轻松搞定,有兴趣的读者自己看看吧。此外网络上还有一些不错的工具可以玩玩,比如:GearmanManagerGearman-Monitor

来源:火丁笔记

 

分类: Linux, PHP 标签:

php多线程程序

2015年8月25日 评论已被关闭

参考:http://zyan.cc/pthreads/

[pcsh lang=”php” tab_size=”4″ message=”” hl_lines=”” provider=”manual”]

include_once('./XMemcache.php');
class pthreadTest extends Thread {
//循环次数
public $times = 0;

//执行的时间
public $timeCast = 0;

//是否碰撞
public $collision = false;

//第几次循环发生碰撞
public $collisionNo = 0;

//被碰撞的数字
public $beTouchedNum = 0;

//
public $data = array();

public function __construct($times) {
$this->times = $times;
}

public function run() {
$this->data = runTask($this->times);
}
}
function threadGet($pool) {
foreach ($pool as $key => $value) {
$threadArray[$key] = new pthreadTest($value);
$threadArray[$key]->start();
}

foreach ($threadArray as $key => $value) {
while ($threadArray[$key]->isRunning()) {
usleep(100);
}
if ($threadArray[$key]->join()) {
$returnData[$key] = $threadArray[$key]->data;
}
}
return $returnData;
}
function runTask($total=0) {
$total = $total==0 ? rand(100,999) : $total;
$mem = XMemcache::getInstance()->getMem();

$start = getTime();
for($i=0; $i<$total; $i++) {
$k = rand(100000000, 999999999);
if( ! $mem->get($k) ) {
$mem->set($k, $i, 3600);
}else{
echo '检查到碰撞: $i='.$i.',碰撞key='.$mem->get($k)."\n";
break;
}
}
$end = getTime();
return array('total'=>$total, 'timeCast'=>$end-$start);
}
function getTime() {
$t1 = microtime();
$t1 = explode(' ', $t1);
return $t1[1].substr($t1[0],1);
}

//task
$pool[] = 500;
$pool[] = 200;
$pool[] = 700;
$pool[] = 300;
$pool[] = 400;
$t1 = getTime();
$result = threadGet($pool);
$t2 = getTime();
print_r($result);
echo '多线程执行时间:'.($t2-$t1)."\n\n\n";
$t1 = getTime();
$r = array();
foreach ($pool as $key => $value) {
$r[$key] = runTask($value);
}
$t2 = getTime();
print_r($r);
echo '串行执行时间:'.($t2-$t1)."\n\n\n";

[/pcsh]

分类: PHP 标签: