2014年5月

关于php的包Pear

什么是PEAR

PEAR是PHP扩展与应用库(the PHP Extension and Application Repository)的缩写。它是一个PHP扩展及应用的一个代码仓库,简单地说,PEAR就是PHP的CPAN。

为什么要使用PEAR?

PHP是一个非常优秀的脚本语言,简洁、高效,随着4.0的发布,越来越多的人使用它来进行动态网站的开发,可以说,PHP已经成为最优秀的INTERNET开发语言之一,尤其对于那些需要能够快速、高效地开发中小规模的商业应用的网站开发人员,PHP是其首选的语言。但是随着PHP的应用的不断增多,对于这些应用缺乏统一的标准和有效的管理,因此,PHP社区很难象PERL社区的人们那样方便的共享彼此的代码和应用,因为PHP缺乏象CPAN那样的统一的代码库来分类管理应用的代码模块(熟悉PERL的人都知道,CPAN是一个巨大的PERL的扩展模块仓库,编写的应用模块可以放在CPAN下面的适当的分类目录下面,其他的人可以很方便地复用,当然,你编写应用模块时候也需要遵守其中的准则。)

为此,PEAR就应运而生了,并且从4.04开始,随着PHP核心一起被分发。

PEAR能给我带来什么好处?

1.如前所述,PEAR按照一定的分类来管理PEAR应用代码库,你的PEAR代码可以组织到其中适当的目录中,其他的人可以方便地检索并分享到你的成果。

2.PEAR不仅仅是一个代码仓库,它同时也是一个标准,使用这个标准来书写你的PHP代码,将会增强你的程序的可读性,复用性,减少出错的几率。

3.PEAR通过提供2个类为你搭建了一个框架,实现了诸如析构函数,错误捕获功能,你通过继承就可以使用这些功能。

php多线程

伪)多线程:借助外力利用WEB服务器本身的多线程来处理,从WEB服务器多次调用我们需要实现多线程的程序。
QUOTE:我们知道PHP本身是不支持多线程的, 但是我们的WEB服务器是支持多线程的.
也就是说可以同时让多人一起访问. 这也是我在PHP中实现多线程的基础.
假设我们现在运行的是a.php这个文件. 但是我在程序中又请求WEB服务器运行另一个b.php
那么这两个文件将是同时执行的.
(PS: 一个链接请求发送之后, WEB服务器就会执行它, 而不管客户端是否已经退出)
有些时候, 我们想运行的不是另一个文件, 而是本文件中的一部分代码.该怎么办呢?
其实可是通过参数来控制a.php来运行哪一段程序.
下面看一个例子:

复制代码代码如下:
<?php
function runThread(){
$fp = fsockopen('localhost', 80, $errno, $errmsg);
fputs($fp, "GET /a.php?act=brnrn");//这里的第二个参数是HTTP协议中规定的请求头,不明白的请看RFC中的定义
fclose($fp);
}
function a(){
$fp = fopen('result_a.log', 'w');
fputs($fp, 'Set in ' . Date('h:i:s', time()) . (double)microtime() . "rn");
fclose($fp);
}
function b(){
$fp = fopen('result_b.log', 'w');
fputs($fp, 'Set in ' . Date('h:i:s', time()) . (double)microtime() . "rn");
fclose($fp);
}
if(!isset($_GET['act'])){ $_GET['act'] = 'a';};
if($_GET['act'] == 'a'){
runThread();
a();
}else if($_GET['act'] == 'b'){
b();
};
?>

打开result_a.log 和 result_b.log 比较一下两个文件的中访问的时间. 大家会发现, 这两个的确是在不同线程中运行的.有些时间完全一样.
上面只是一个简单的例子, 大家可以改进成其它形式.
既然PHP中也能多线程了, 那么问题也来了, 那就是同步的问题. 我们知道 PHP本身是不支持多线程的. 所以更不会有什么像Java 中synchronize的方法了. 那我们该如何做呢.

 

1. 尽量不访问同一个资源. 以避免冲突. 但是可以同时像数据库操作. 因为数据库是支持并发操作的. 所以在多线程的PHP中不要向同一个文件中写入数据. 如果必须要写的话, 用别的方法进行同步.. 如调用 flock对文件进行加锁等. 或建立临时文件并在另外的线程中等待这个文件的消失 while(file_exits('xxx')); 这样就等于这个临时文件存在时, 表示其实线程正在操作,如果没有了这个文件, 说明其它线程已经释放了这个.

2. 尽量不要从runThread在执行fputs后取这个socket中读取数据. 因为要实现多线程, 需要的用非阻塞模式. 即在像fgets这样的函数时立即返回.. 所以读写数据就会出问题. 如果使用阻塞模式的话, 程序就不算是多线程了. 他要等上面的返回才执行下面的程序. 所以如果需要交换数据最后利用外面文件或数据中完成. 实在想要的话就用socket_set_nonblock($fp) 来实现.

说了这么多, 倒底这个有没有实际的意义呢? 在什么时候需要这种用这种方法呢 ?
答案是肯定的. 大家知道. 在一个不断读取网络资源的应用中, 网络的速度是瓶颈. 如果采多这种形式就可以同时以多个线程对不同的页面进行读取.

本人做的一个能从8848、soaso这些商城网站搜索信息的程序。还有一个从阿里巴巴网站上读取商业信息和公司目录的程序也用到了此技术。 因为这两个程序都是要不断的链接它们的服务器读取信息并保存到数据库。 利用此技术正好消除了在等待响应时的瓶颈。

多进程:使用PHP的Process Control Functions(PCNTL/线程控制函数)只能用在Unix Like OS,Windows不可用。
编译php的时候,需要加上--enable-pcntl,且推荐仅仅在CLI模式运行,不要在WEB服务器环境运行。
以下为简短的测试代码:

代码如下:
declare(ticks=1);
$bWaitFlag = FALSE; /// 是否等待进程结束
$intNum = 10;           /// 进程总数
$pids = array();        ///  进程PID数组
echo ("Start\n");
for($i = 0; $i < $intNum; $i++) {
$pids[$i] = pcntl_fork();/// 产生子进程,而且从当前行之下开试运行代码,而且不继承父进程的数据信息
if(!$pids[$i]) {
// 子进程进程代码段_Start
$str="";
sleep(5+$i);
for ($j=0;$j<$i;$j++) {$str.="*";}
echo "$i -> " . time() . " $str \n";
exit();
// 子进程进程代码段_End
}
}
if ($bWaitFlag)
{
for($i = 0; $i < $intNum; $i++) {
pcntl_waitpid($pids[$i], $status, WUNTRACED);
echo "wait $i -> " . time() . "\n";
}
}
echo ("End\n");

运行结果如下:CODE:[Copy toclipboard][qiao@oicq qiao]$ phptest.php
Start
End
[qiao@oicq qiao]$ ps -aux | grep "php"
qiao     32275  0.0  0.5 49668 6148pts/1    S    14:03   0:00/usr/local/php4/b
qiao     32276  0.0  0.5 49668 6152pts/1    S    14:03   0:00/usr/local/php4/b
qiao     32277  0.0  0.5 49668 6152pts/1    S    14:03   0:00/usr/local/php4/b
qiao     32278  0.0  0.5 49668 6152pts/1    S    14:03   0:00/usr/local/php4/b
qiao     32279  0.0  0.5 49668 6152pts/1    S    14:03   0:00/usr/local/php4/b
qiao     32280  0.0  0.5 49668 6152pts/1    S    14:03   0:00 /usr/local/php4/b
qiao     32281  0.0  0.5 49668 6152pts/1    S    14:03   0:00/usr/local/php4/b
qiao     32282  0.0  0.5 49668 6152pts/1    S    14:03   0:00/usr/local/php4/b
qiao     32283  0.0  0.5 49668 6152pts/1    S    14:03   0:00/usr/local/php4/b
qiao     32284  0.0  0.5 49668 6152pts/1    S    14:03   0:00/usr/local/php4/b
qiao     32286  0.0  0.0  1620  600pts/1    S    14:03   0:00 grep php
[qiao@oicq qiao]$ 0 -> 1133503401
1 -> 1133503402 *
2 -> 1133503403 **
3 -> 1133503404 ***
4 -> 1133503405 ****
5 -> 1133503406 *****
6 -> 1133503407 ******
7 -> 1133503408 *******
8 -> 1133503409 ********
9 -> 1133503410 *********
[qiao@oicq qiao]$
如果$bWaitFlag=TURE,则结果如下:CODE:[Copy toclipboard][qiao@oicq qiao]$ phptest.php
Start
0 -> 1133503602
wait 0 -> 1133503602
1 -> 1133503603 *
wait 1 -> 1133503603
2 -> 1133503604 **
wait 2 -> 1133503604
3 -> 1133503605 ***
wait 3 -> 1133503605
4 -> 1133503606 ****
wait 4 -> 1133503606
5 -> 1133503607 *****
wait 5 -> 1133503607
6 -> 1133503608 ******
wait 6 -> 1133503608
7 -> 1133503609 *******
wait 7 -> 1133503609
8 -> 1133503610 ********
wait 8 -> 1133503610
9 -> 1133503611 *********
wait 9 -> 1133503611
End
[qiao@oicq qiao]$
从 多进程的例子可以看出,使用pcntl_fork()之后,将生成一个子进程,而且子进程运行的代码,从pcntl_fork()之后的代码开始,而子进 程不继承父进程的数据信息(实际上是把父进程的数据做了一个全新的拷贝),因而使用if(!$pids[$i]) 来控制子进程实际运行的代码段。
更详细的研究出于时间关系,暂时没有进行,你可以参考我给出的手册的链接。

 

[文章二] 尝试php命令行脚本多进程并发执行除了fork, cli下的并发方式还有一种,看我的例子:
php不支持多线程,但是我们可以把问题转换成“多进程”来解决。由于php中的pcntl_fork只有unix平台才可以使用,所以本文尝试使用popen来替代。
下面是一个例子:被并行调用的子程序代码:

复制代码代码如下:
<?php
if($argc==1){
echo("argv\n");
}
$arg = $argv[1];
for($i=0; $i<10; $i++)
{
echo($i.".1.".time()." exec $arg \n");
if($arg=='php2'){
sleep(1);
echo($i.".2.".time()." exec $arg \n");
sleep(1);
}else{
sleep(1);
}
}
?>

主调用者程序,由他调用子进程,同时并发的收集子程序的输出

代码如下:
error_reporting(E_ALL);
$handle1 = popen('php sub.php php1', 'r');
$handle2 = popen('php sub.php php2', 'r');
$handle3 = popen('php sub.php php3', 'r');
echo "'$handle1'; " . gettype($handle1) . "\n";
echo "'$handle2'; " . gettype($handle2) . "\n";
echo "'$handle3'; " . gettype($handle3) . "\n";
//sleep(20);
while(!feof($handle1) || !feof($handle2) || !feof($handle3) )
{
$read = fgets($handle1);
echo $read;
$read = fgets($handle2);
echo $read;
$read = fgets($handle3);
echo $read;
}
pclose($handle1);
pclose($handle2);
pclose($handle3);

下面是我机器上的输出:
C:\my_hunter>php exec.php
'Resource id #4'; resource
'Resource id #5'; resource
'Resource id #6'; resource
0.1.1147935331 exec php1
0.1.1147935331 exec php2
0.1.1147935331 exec php3
1.1.1147935332 exec php1
0.2.1147935332 exec php2
1.1.1147935332 exec php3
2.1.1147935333 exec php1
1.1.1147935333 exec php2
2.1.1147935333 exec php3
3.1.1147935334 exec php1
1.2.1147935334 exec php2
3.1.1147935334 exec php3
4.1.1147935335 exec php1
2.1.1147935335 exec php2
4.1.1147935335 exec php3
5.1.1147935336 exec php1
2.2.1147935336 exec php2
5.1.1147935336 exec php3
6.1.1147935337 exec php1
3.1.1147935337 exec php2
6.1.1147935337 exec php3
7.1.1147935338 exec php1
3.2.1147935338 exec php2
7.1.1147935338 exec php3
8.1.1147935339 exec php1
4.1.1147935339 exec php2
8.1.1147935339 exec php3
9.1.1147935340 exec php1
4.2.1147935340 exec php2
9.1.1147935340 exec php3
5.1.1147935341 exec php2
5.2.1147935342 exec php2
6.1.1147935343 exec php2
6.2.1147935344 exec php2
7.1.1147935345 exec php2
7.2.1147935346 exec php2
8.1.1147935347 exec php2
8.2.1147935348 exec php2
9.1.1147935349 exec php2
9.2.1147935350 exec php2
总结:主程序循环等待子进程, 通过fgets或fread 把子进程的输出获取出来 , 从时间戳上看,的确实现了并发执行。

以后的改进:*  popen打开的句柄是单向的,如果需要向子进程交互,可以使用proc_open
*  使用数组和子函数代替while(!feof($handle1)|| !feof($handle2) || !feof($handle3) )这种龌龊的写法
*  用fread一次把子进程已经产生的输出取完,而不是每次一行。
一个并发执行shell任务的调度者,本程序读取一个任务文件,把里面的每行命令并发执行, 可以设置同时存在的子进程数目:

代码如下:
/*
主任务管理器
并发的执行子任务列表
*/
include("../common/conf.php");
include("../common/function.php");
//开启的进程数
$exec_number = 40 ;
/***** main ********/
if($argc==1){
echo("argv\n");
}
$taskfile = $argv[1];
//tasklist
$tasklist = file($taskfile);
$tasklist_len = count($tasklist);
$tasklist_pos = 0;
$handle_list = array();
while(1)
{
//子进程列表有空闲,则填充补齐子进程列表
if($exec_number > count($handle_list) &&
$tasklist_pos < $tasklist_len)
{
for($i=$tasklist_pos; $i<$tasklist_len; )
{
$command = $tasklist[$i] ;
$handle_list[] = popen($command , "r" );
tolog("begin task \t ".$tasklist[$i]);
$i++;
if($exec_number == count($handle_list)) break;
}
$tasklist_pos = $i;
}
//如果子进程列表空,退出
if(0 == count($handle_list))
{
break;
}
//检查子进程列表的输出,把停掉的子进程关闭并记录下来
$end_handle_keys = array();
foreach($handle_list as $key => $handle)
{
//$str = fgets($handle, 65536);
$str = fread($handle, 65536);
echo($str);
if(feof($handle))
{
$end_handle_keys[] = $key;
pclose($handle);
}
}
//踢出停掉的子进程
foreach($end_handle_keys as $key)
{
unset($handle_list[$key]);
//var_dump($handle_list);
//exit;
}
}
tolog("\n\n*end*\n\n", "" ,  true);

附加一段Socket多进程接收的代码:

代码如下:
do {
if (($msgsock = socket_accept($sock)) < 0) {
echo "socket_accept() failed: reason: " .
       socket_strerror($msgsock) . "\n";
break;
}
$pid = pcntl_fork();
if ($pid == -1) {
die('could not fork');
} else if (!$pid) {
.....
socket_write($msgsock, $msg, strlen($msg));
do {
......
} while (true);
socket_close($msgsock);
}
} while (true);

LAMP还是WAMP?

LAMP--Linux+Apache+Mysql+Perl/PHP/Python,一组常用来搭建动态网站或者服务器的开源软件,本身都是各自独立的程序,但是因为常被放在一起使用,拥有了越来越高的兼容度,共同组成了一个强大的Web应用程序平台。

随着开源潮流的蓬勃发展,开放源代码的LAMP已经与J2EE和.Net商业软件形成三足鼎立之势,并且该软件开发的项目在软件方面的投资成本较低,因此受到整个IT界的关注。从网站的流量上来说,70%以上的访问流量是LAMP来提供的,LAMP是最强大的网站解决方案.

LAMP是基于Linux,Apache,MySQL和PHP的开放资源网络开发平台,PHP是一种有时候用Perl或Python可代替的编程语言。这个术语来自欧洲,在那里这些程序常用来作为一种标准开发环境。名字来源于每个程序的第一个字母。每个程序在所有权里都符合开放源代码标准:Linux是开放系统;Apache是最通用的网络服务器;mySQL是带有基于网络管理附加工具的关系数据库;PHP是流行的对象脚本语言,它包含了多数其它语言的优秀特征来使得它的网络开发更加有效。开发者在Windows操作系统下使用这些Linux环境里的工具称为使用WAMP。

虽然这些开放源代码程序本身并不是专门设计成同另外几个程序一起工作的,但由于它们都是影响较大的开源软件,拥有很多共同特点,这就导致了这些组件经常在一起使用。在过去的几年里,这些组件的兼容性不断完善,在一起的应用情形变得更加普遍。并且它们为了改善不同组件之间的协作,已经创建了某些扩展功能。目前,几乎在所有的Linux发布版中都默认包含了这些产品。Linux操作系统、Apache服务器、MySQL数据库和Perl、PHP或者 Python语言,这些产品共同组成了一个强大的Web应用程序平台。

随着开源潮流的蓬勃发展,开放源代码的LAMP已经与J2EE和.Net商业软件形成三足鼎立之势,受到整个IT界的关注。越来越多的供应商、用户和企业投资者日益认识到,经过LAMP单个组件的开源软件组成的平台用来构建以及运行各种商业应用和协作构建各种网络应用程序变为一种可能和实践,变得更加具有竞争力,更加吸引客户。LAMP无论是性能、质量还是价格都将成为企业、政府信息化所必须考虑的平台。

LAMP这个特定名词最早出现在1998年。当时,Michael Kunze为德国计算机杂志c't写作的一篇关于自由软件如何成为商业软件替代品的文章时,创建了LAMP这个名词,用来指代Linux 操作系统、Apache网络服务器、MySQL 数据库和PHP (Perl或Python)脚本语言的组合(由四种技术的开头字母组成)。由于IT世界众所周知的对缩写的爱好,Kunze提出的LAMP这一术语很快就被市场接受。O'Reilly和MySQL AB更是在英语人群中推广普及了这个术语。随之LAMP技术成为了开源软件业的一盏真正的明灯。事实上,LAMP,正像一盏开源明灯指引着我们前进的方向!

 

WAMP是指在Windows服务器上使用Apache、MySQL和PHP的集成安装环境,可以快速安装配置Web服务器,一般说来,大家都习惯于将Apache、MySQL、PHP架设在Linux系统下,但是,不可否认的是Windows也有其优点,就是易用,界面友好,软件丰富,操作起来非常方面,因此对新手来说在Windows平台下使用Apache、MySQL、PHP也确实是一个不错的选择。下面我将介绍几款在Windows下可以使用的WAMP集成环境。

XAMPP - XAMPP是一款具有中文说明的功能全面的集成环境,XAMPP并不仅仅针对Windows,而是一个适用于Linux、Windows、Mac OS X 和Solaris 的易于安装的Apache 发行版。软件包中包含Apache 服务器、MySQL、SQLite、PHP、Perl、FileZilla FTP Server、Tomcat等等。默认安装开放了所有功能,安全性有问题,需要进行额外的安全设定。

WampServer - WampServe集成了Apache、MySQL、PHP、phpmyadmin,支持Apache的mod_rewrite,PHP扩展、Apache模块只需要在菜单“开启/关闭”上点点就搞定,省去了修改配置文件的麻烦。

AppServ - 集成了Apache、PHP、MySQL、phpMyAdmin,较为轻量。

总的来说,无论从安全性和性能上来讲,LAMP(Linux + Apache + MySQL + PHP)都优于WAMP(Windows + Apache + MySQL + PHP),不过由于Windows具有易用的特点,WAMP也未尝不是初学者的一个不错的选择。

关于模板引擎smarty

框架

框架就像一个大楼的地基, 无论大楼怎么盖, 打造地基的方法永远都是类似的.在我们进行程序开发的过程中, 你会发现每个程序之间都要有很多类似的东西和可以重用的东西, 如果你每个项目过后都把这些类似的东西积累起来, 那么这些代码可以称为库, 当库越来越强大, 甚至连程序结构都可以重用的时候, 你就可以叫他框架了.

模板引擎

模板引擎你可以理解成施工队里刷油漆的, 他们是专业刷油漆的, 盖楼的不用管油漆怎么刷, 刷油漆的也不关注楼是怎么盖的.

其实模板引擎的主要作用还是将逻辑和显示进行分离, 最初可能是为了让程序员和美工更好的进行配合, 既然初学者, 我想你经常会把php代码和html写到一起, 你自己是可以看懂的, 但是美工不一定看得懂, 他们可能只能看懂html和css, 再者说如果美工在混合代码里加了复杂的css或者js你也一样会看不懂, 这样就给程序开发带来了很大的困难. 所以才有了模板引擎, 它将逻辑和显示完全分离, 程序员只需要关注逻辑, 在程序的最后将数据准备好然后传递给模板, 而美工只要修改模板而不需要考虑程序逻辑, 模板技术在团队开发中是经常使用的

smarty 仅是一个模版引擎,做的事情,就是把数据结合模板文件,渲染出来。
个人觉得smarty 语法古怪,硬是把很简单的事搞得很复杂。网上大把的模版类可以拿着用。当然做为一整套的体系的东西而言smarty 是做的不错的,可惜就是不好用。

框架,即framework。其实就是某种应用的半成品,就是一组组件,供你选用完成你自己的系统。简单说就是使用别人搭好的舞台,你来做表演。而且,框架一般是成熟的,不断升级的软件。 

为什么要用框架?

因为软件系统发展到今天已经很复杂了,特别是服务器端软件,设计到的知识,内容,问题太多。在某些方面使用别人成熟的框架,就相当于让别人帮你完成一些基础工作,你只需要集中精力完成系统的业务逻辑设计。而且框架一般是成熟,稳健的,他可以处理系统很多细节问题,比如,事物处理,安全性,数据流控制等问题。还有框架一般都经过很多人使用,所以结构很好,所以扩展性也很好,而且它是不断升级的,你可以直接享受别人升级代码带来的好处。
框架一般处在低层应用平台(如J2EE)和高层业务逻辑之间的中间层。