竹磬网-邵珠庆の日记 生命只有一次,你可以用它来做些更多伟大的事情–Make the world a little better and easier


1211月/130

PHP中Push(推送)技术的探讨

发布在 邵珠庆

随着人们对Web即时应用需求的不断上升,Server Push(推送)技术在聊天、消息提醒尤其是社交网络等方面开始兴起,成为实时应用的数据流核心。这篇日志试图探讨的便是各种适合于PHP的Push的实现方式以及其优劣。

1. 什么是Server Push

想象在聊天应用中,如果使用传统的ajax来承担消息的传入,那么一般是通过每隔一定时间拉取一次信息的方式实现,但是其实这种方式有大量查询是浪费的。聊天等Web应用更需要服务器在特定时间来主动告知前端有新的消息(Push),而不是前端每时每刻问服务器:“来消息了吗?”(Pull)。这也正是为什么这个技术常被叫做反向ajax。

其他别名:Comet,反向Ajax

 

2. 如何实现Push

其实所谓的推送技术也没有多么复杂,目前从大类上有3种,一种仍然建立在ajax基础上,还有一种建立在框架基础上,最后一种抛弃了传统的HTTP协议,使用Flash或者HTML5的WebSockets技术。接下来将对这三种类别产生的不同的方式进行探讨。

 

1) Ajax 长轮询

Ajax长轮询从本质上来说仍然是一种pull,但是实时性较高,无用请求减少很多,是一种不错的Push实现方案。不过它只减少了网络上的无谓消耗。

核心: 客户端发起一个ajax请求,服务端将请求搁置(pending)或者说挂起,直到到了超时时间(timeout)或需要推送时返回;客户端则等待ajax返回后处理数据,再发起下一个ajax请求。

优点: 兼容性较高,实现简单

缺点: 对于php这种语言来说,如果要做到实时,那么服务端就要承受大得多的压力,因为搁置到什么时候往往是不确定的,这就要php脚本每次搁置都进行一个while循环。
当然,如果服务器刷新每秒级,那尚可接受,只是实时性上退化了。

注意: 浏览器有连接数限制。我得出的结论是如果当前页面上有一个ajax请求处于等待返回状态,那么其他ajax请求都会被搁置(Chrome, Firefox已测)。似乎跟页面标记有关,一个规范的HTML可以同时有多个请求。如果页面有一般ajax需求怎么办?解决方法是开个框架,框架中使在另一个域名下进行Comet长轮询,需要注意跨域问题。

PHP实现: Jquery+php实现comet

相关: Ajax跨域和js跨域解决方案

 

2) Frame 长连接

受到ajax启发,出现了框架下的长连接。

核心: Frame中发起一个普通请求,服务器将其搁置;需要推送时输出直接执行
脚本,然后继续保持连接。如果担心超时问题可以改成框架论询。

优点: 与1一样具有高兼容特性

缺点: 最大的问题是如果框架在载入,那么浏览器就好一直显示“载入中”,这就弱爆了(解决方法参见文末的相关阅读资源)。同样服务器也要能hold住大量循环……另外,是否有同域连接限制没测试。

 

3) Flash/HTML5 WebSockets

用flash来发起WebSockets,秒杀前面一切问题。

优点: 标准化, RealTime, Push

缺点: 服务器需要能应对WebSockets;还有如果既没有Flash又不支持HTML5的怎么办?

PHP实现: Start Using HTML5 WebSockets Today

 

6) 使用兼容封装层(socket.io)

以上每种方法都有优劣,那么终极解决方案便是合在一起!能WebSockets时候就WebSockets,不支持HTML5特性就退化到Flash,没有Flash则退化到Ajax长轮询。这也是我的Rainbowfish所采用的方式。

优点: 高度封装,编写非常容易,几乎不需要关心如何去实现的。实时,超低负载,高并发。

缺点: 其实算不上缺点,socket.io的服务器端要求是node.js,而不是php。

个人看法: 如果你是独立主机,能运行程序,那么socket.io配合node.js是个非常高效的选择。为什么呢?因为它还可以避免php的服务端高负载。

Rainbowfish的消息系统通过这种方式实现: 所有客户端都通过socket.io挂在nodejs服务器上(注意: 只是挂着,不需要任何循环,因为它是事件驱动的);需要推送消息了,服务器就与nodejs通信(比如访问某个地址来实现),告诉它推送什么消息到哪里;nodejs收到推送信号后,则通过socket.io实时传输数据给浏览器。这个其实也是一条单向的路,因为nodejs服务器不具备与php通信的能力,实际上也不需要,网页上直接连php就可以了。

 

3. 结束语

事实上,第一个方法(Ajax Long Pull)是一个不错的方法,只是如果使用php完成的话服务器负载上有点大,但这其实是通病;而最后列举的socket.io方案完全避免了这个问题,因为它属于另一种架构,并且这种组合也可以配合几乎所有的脚本语言实现push。

对于实时性要求非常高的应用,或许使用php实现实时部分并不是一个好的选择,将会面临非常大的服务器负载(可以通过编写支持等待事件的扩展来解决这个问题);如果只是消息提示等,则可以调整服务器上刷新的间隔降低到秒的级别,负载尚可接受。不过无论哪种用途,配合那些非阻塞语言或许才是最好的选择。

 

4. 相关阅读

How to implement COMET with PHP

Start Using HTML5 WebSockets Today

Comet(Wikipedia)

Ajax跨域和js跨域解决方案

Jquery+php实现comet

239月/130

PHP CodeIgniter框架源码解析

发布在 邵珠庆

1.index.php :入口文件
|-->define('ENVIRONMENT')  |主要用于设置errors日志输出级别
|-->$system_path |设置系统路径
|-->设置BASEPATH、FCPATH、SYSDIR、APPPATH等    |设置路径信息变量,为加载相应文件信息准备
|-->require_once BASEPATH.core/CodeIgniter.php | 最后加载CodeIgniter.php作为总控制器

2.CodeIgniter.php加载过程,主要用于加载core核心目录下相应文件

|-->require(BASEPATH.'core/Common.php');  |加载core目录下的Common文件,见2.1解析
|-->require(APPPATH.'config/'.ENVIRONMENT.'/constants.php'); |加载constants目录,与开发环境无关时直接使用config目录下的constants目录
|-->get_config(array('subclass_prefix' => $assign_to_config['subclass_prefix']));   |设置子文件,扩展类的前缀
|-->$BM =& load_class('Benchmark', 'core');  |加载benchmark类,mark记录当前的时间
|-->$EXT =& load_class('Hooks', 'core');     |加载core目录下的Hooks钩子类
|-->$EXT->_call_hook('pre_system');  |调用_call_hook(pre_system),根据pre_system内部调用_run_hook执行钩子,在系统开始正式工作前作预处理
|-->$CFG =& load_class('Config', 'core');    |继续执行core下的Config配置文件,
|-->$CFG->_assign_to_config($assign_to_config); 
|-->|$this->set_item($key, $val);      |解析指定给config的配置文件,实质为对config[]赋值
|-->$UNI =& load_class('Utf8', 'core');      |加载了UTF-8编码类,CI_Utf8
|-->$URI =& load_class('URI', 'core');       |加载core目录的URI类,CI_URI
|-->$RTR =& load_class('Router', 'core');    |设置route路由及覆盖信息,见2.2解析
|-->_set_routing()
|-->_set_overrides()
|-->$OUT =& load_class('Output', 'core');    |实例化输出类,加载core目录下的output文件
|-->$OUT->_display_cache($CFG, $URI)         |判断是否存在页面缓存,是则输出文件
|-->$SEC =& load_class('Security', 'core');  |加载core目录下的安全处理文件
|-->$IN =& load_class('Input', 'core');      |实例化输入类,加载core目录下的input文件
|-->$LANG =& load_class('Lang', 'core');     |加载语言类
|-->require BASEPATH.'core/Controller.php';  |加载基本控制器类,见2.3解析
|-->require APPPATH.'core/'.$CFG->config['subclass_prefix'].'Controller.php';  |尝试加载扩展的自定义子类控制器
|-->include(APPPATH.'controllers/'.$RTR->fetch_directory().$RTR->fetch_class().'.php');  |加载自定义控制器下的控制器类
|-->$BM->mark('loading_time:_base_classes_end'); |设定一个benchmark测试点
|-->$class  = $RTR->fetch_class();     |分别获取uri地址的控制器类名和方法名
|-->$method = $RTR->fetch_method();
|-->if ( ! class_exists($class)              |判断方法及类是否合理
OR strncmp($method, '_', 1) == 0
OR in_array(strtolower($method), array_map('strtolower', get_class_methods('CI_Controller')))
)
|-->$EXT->_call_hook('pre_controller');      |处理器执行前进行预处理,并做benchmark设置
|-->$CI = new $class();                      |获取执行的控制器实例,实例化构造器
|-->$EXT->_call_hook('post_controller_constructor');  |实例化控制器类后的钩子处理
|-->if (method_exists($CI, '_remap'))
|-->$CI->_remap($method, array_slice($URI->rsegments, 2))  |如果控制器存在_remap()方法,则执行, 判断条件$CI为控制器类 
|-->else |判断方法在类当中的存在似,如果不存在,则设置
|-->call_user_func_array(array(&$CI, $method), array_slice($URI->rsegments, 2)); |最终传递参数供调用控制类方法
|-->$BM->mark('controller_execution_time_( '.$class.' / '.$method.' )_end'); |benchmark标记时间结束点
|-->$EXT->_call_hook('post_controller');     |控制器生存周期,在控制器执行完成后执行后续操作
|-->$OUT->_display();  |输出页面进行展示
|-->$EXT->_call_hook('post_system');         |请求生存周期完成后的终结操作
|-->$CI->db->close();                        |自动关闭数据库资源

2.1 Core/Common.php加载
|-->function is_php($version)                |用于比较版本号的函数
|-->function is_really_writable($file)       |用于判断是否可以写文件,在不同的系统中可靠程度不同,
      W中通过判断is_readonly,U中如果safe_mode为开则不确定性
|-->function load_class($class, $directory = 'libraries', $prefix = 'CI_')   |用于加载目录下的PHP文件的class类
|-->foreach (array(APPPATH, BASEPATH) as $path)    |分别在application和system目录下轮循
|-->file_exists($path.$directory.'/'.$class.'.php' |找到对应的PHP文件
|-->require($path.$directory.'/'.$class.'.php');   |require加载对应的PHP文件内的类,加了前缀,此处可扩展
|-->break;    |如正确加载则退出,否则继续尝试加载文件
|-->file_exists(APPPATH.$directory.'/'.config_item('subclass_prefix').$class.'.php')  |自扩展的class类,如My_Test
|-->if ($name === FALSE)   |如果$name不存在,则exit()退出 ,(在自定义类加载时,此处可作为扩展点,增加边际条件)
|-->is_loaded($class);     |确类已经加载
|-->$_classes[$class] = new $name();  |加载至静态的classes数祖中,用于缓存,调用时首先从classes中获取
|-->function is_loaded($class = '')                      
|-->设置$_is_loaded数祖,参数$class不为空,判断是否存在gf $_is_loaded,否则设置
|-->function &get_config($replace = array())|用于获取Config的实例化文件
|-->static $_config;       |定义config类型
|-->$file_path = APPPATH.'config/config.php';      |确定application目录路径下定义的config.php的路径
|-->require($file_path);   |加载application/config/config.php类
|-->count($replace) > 0    |对于config.php中定义的变量,如果有replace,则逐个替代
|-->foreach ($replace as $key => $val)
|-->$config[$key] = $val;
|-->return $_config[0] =& $config;   |最后返回定义的config的结果集
|-->function config_item($item)    |配置选项,从config的数祖对象中返还特殊的配置项
|-->$config =& get_config();
|-->$_config_item[$item] = $config[$item];
|-->function show_error            |用于错误信息输出
|-->$_error =& load_class('Exceptions', 'core');    |加载Exceptions类
|-->echo $_error->show_error($heading, $message, 'error_general', $status_code);  |直接输出错误
|-->function show_404              |用于输出404页面,输出的错误信息页面可配置
|-->function log_message           |用于写日志信息
|-->$_log =& load_class('Log');
|-->$_log->write_log($level, $message, $php_error);

|-->function set_status_header     |用于输出状态的heade信息
|-->function _exception_handler
|-->function remove_invisible_characters
|-->function html_escape           |过滤HTML变量
|-->return htmlspecialchars($var, ENT_QUOTES, config_item('charset'));

2.2Router路由信息设置
|-->_set_routing() 
|-->$segments = array()    |根据目录,控制器,函数的触发器设定segment[]的uri段值,分别fetch()方法去取对象值
|-->include(APPPATH.'config/routes.php');       |加载config下的routes文件
|-->$this->routes          |设置routes数祖值,从config的route中获取
|-->$this->default_controller       |设置routes的控制器值,从config的route中获取
|-->return $this->_validate_request($segments); |验证uri的segment合法性
|-->$this->uri->_remove_url_suffix();$this->uri->_reindex_segments();  |进一步清理解析uri,使segment从1开始x
|-->_set_overrides()  |根据$routing的值,重新设定directory、controller、function参数
|-->$this->set_directory($routing['directory']);
|-->$this->set_class($routing['controller']);
|-->$this->set_method($routing['function']);

2.3 core/Controller.php加载
|-->__construct()                                         |构造函数
|-->self::$instance =& $this;  
|-->foreach (is_loaded() as $var => $class)       |根据is_loaded()的信息加载相应的类
|-->$this->$var =& load_class($class);   
|-->$this->load =& load_class('Loader', 'core');  |加载core/Loader的php文件
|-->$this->load->initialize();                    |主要用于autoload加载信息,如libraries、database等等
|-->function &get_instance                                |返回当前实例
|-->return self::$instance

扩展点:PHP自动加载机制在CodeIgniter中的应用
1.PHP自动加载机制:PHP5后,提供了类的自动加载机制,即类在加载时才被使用,即Lazy loading,共有二种方式
1.1: __autoload()通过扩展可实现,实质为设定规则加载相应路径的PHP文件(require、include方式)
1.2: 将autoload_func指向php文件,这个一般用c语言扩展实现 
  详见:http://blog.csdn.net/flyingpig4/article/details/7286438

2.在CodeIgniter中的应用
根据上述源码分析可知:CodeIgniter中所有的操作都是以Controller为起始,只需在Cotroller加载的过程中,
使__autoload()函数自动加载即可,目前的加载方式为在application/config/config.php中设置__autoload()
函数

86月/130

【原创】PHP超时处理全面总结

发布在 邵珠庆

【 概述 】

 在PHP开发中工作里非常多使用到超时处理到超时的场合,我说几个场景:

1. 异步获取数据如果某个后端数据源获取不成功则跳过,不影响整个页面展现

2. 为了保证Web服务器不会因为当个页面处理性能差而导致无法访问其他页面,则会对某些页面操作设置

3. 对于某些上传或者不确定处理时间的场合,则需要对整个流程中所有超时设置为无限,否则任何一个环节设置不当,都会导致莫名执行中断

4. 多个后端模块(MySQL、Memcached、HTTP接口),为了防止单个接口性能太差,导致整个前面获取数据太缓慢,影响页面打开速度,引起雪崩

5. 。。。很多需要超时的场合

 

这些地方都需要考虑超时的设定,但是PHP中的超时都是分门别类,各个处理方式和策略都不同,为了系统的描述,我总结了PHP中常用的超时处理的总结。

 

 

 

【Web服务器超时处理】

 

[ Apache ]

 

一般在性能很高的情况下,缺省所有超时配置都是30秒,但是在上传文件,或者网络速度很慢的情况下,那么可能触发超时操作。

 

目前 apache fastcgi php-fpm 模式 下有三个超时设置:

 

fastcgi 超时设置:

修改 httpd.conf 的fastcgi连接配置,类似如下:

 

<IfModule mod_fastcgi.c>    FastCgiExternalServer /home/forum/apache/apache_php/cgi-bin/php-cgi -socket /home/forum/php5/etc/php-fpm.sock

    ScriptAlias /fcgi-bin/ "/home/forum/apache/apache_php/cgi-bin/"

    AddHandler php-fastcgi .php

    Action php-fastcgi /fcgi-bin/php-cgi

    AddType application/x-httpd-php .php

</IfModule>

 

缺省配置是 30s,如果需要定制自己的配置,需要修改配置,比如修改为100秒:(修改后重启 apache):

<IfModule mod_fastcgi.c>

    FastCgiExternalServer /home/forum/apache/apache_php/cgi-bin/php-cgi -socket /home/forum/php5/etc/php-fpm.sock  -idle-timeout 100

    ScriptAlias /fcgi-bin/ "/home/forum/apache/apache_php/cgi-bin/"

    AddHandler php-fastcgi .php

    Action php-fastcgi /fcgi-bin/php-cgi

    AddType application/x-httpd-php .php

</IfModule>

 

 

如果超时会返回500错误,断开跟后端php服务的连接,同时记录一条apache错误日志:

 

[Thu Jan 27 18:30:15 2011] [error] [client 10.81.41.110] FastCGI: comm with server "/home/forum/apache/apache_php/cgi-bin/php-cgi" aborted: idle timeout (30 sec)

[Thu Jan 27 18:30:15 2011] [error] [client 10.81.41.110] FastCGI: incomplete headers (0 bytes) received from server "/home/forum/apache/apache_php/cgi-bin/php-cgi"

 

其他 fastcgi 配置参数说明:

 

IdleTimeout 发呆时限ProcessLifeTime 一个进程的最长生命周期,过期之后无条件kill

MaxProcessCount 最大进程个数

DefaultMinClassProcessCount 每个程序启动的最小进程个数

DefaultMaxClassProcessCount 每个程序启动的最大进程个数

IPCConnectTimeout 程序响应超时时间

IPCCommTimeout 与程序通讯的最长时间,上面的错误有可能就是这个值设置过小造成的

MaxRequestsPerProcess 每个进程最多完成处理个数,达成后自杀

 

 

 

[ Lighttpd ]

配置:lighttpd.conf

 

Lighttpd配置中,关于超时的参数有如下几个(篇幅考虑,只写读超时,写超时参数同理):

 

主要涉及选项:

server.max-keep-alive-idle = 5

server.max-read-idle = 60

server.read-timeout = 0

server.max-connection-idle = 360

 

--------------------------------------------------

# 每次keep-alive 的最大请求数, 默认值是16

server.max-keep-alive-requests = 100

 

# keep-alive的最长等待时间, 单位是秒,默认值是5

server.max-keep-alive-idle = 1200

 

# lighttpd的work子进程数,默认值是0,单进程运行

server.max-worker = 2

 

# 限制用户在发送请求的过程中,最大的中间停顿时间(单位是秒),

# 如果用户在发送请求的过程中(没发完请求),中间停顿的时间太长,lighttpd会主动断开连接

# 默认值是60(秒)

server.max-read-idle = 1200

 

# 限制用户在接收应答的过程中,最大的中间停顿时间(单位是秒),

# 如果用户在接收应答的过程中(没接完),中间停顿的时间太长,lighttpd会主动断开连接

# 默认值是360(秒)

server.max-write-idle = 12000

 

# 读客户端请求的超时限制,单位是秒, 配为0表示不作限制

# 设置小于max-read-idle时,read-timeout生效

server.read-timeout = 0

 

# 写应答页面给客户端的超时限制,单位是秒,配为0表示不作限制

# 设置小于max-write-idle时,write-timeout生效

server.write-timeout = 0

 

# 请求的处理时间上限,如果用了mod_proxy_core,那就是和后端的交互时间限制, 单位是秒

server.max-connection-idle = 1200

--------------------------------------------------

  

说明:

对于一个keep-alive连接上的连续请求,发送第一个请求内容的最大间隔由参数max-read-idle决定,从第二个请求起,发送请求内容的最大间隔由参数max-keep-alive-idle决定。请求间的间隔超时也由max-keep-alive-idle决定。发送请求内容的总时间超时由参数read-timeout决定。Lighttpd与后端交互数据的超时由max-connection-idle决定。

 

延伸阅读:

http://www.snooda.com/read/244

 

 

[ Nginx ]

配置:nginx.conf

 

http { 

    #Fastcgi: (针对后端的fastcgi 生效, fastcgi 不属于proxy模式)

    fastcgi_connect_timeout 5;    #连接超时

    fastcgi_send_timeout 10;       #写超时

    fastcgi_read_timeout 10;        #读取超时

 

    #Proxy: (针对proxy/upstreams的生效)

    proxy_connect_timeout 15s;    #连接超时

    proxy_read_timeout 24s;          #读超时

    proxy_send_timeout 10s;         #写超时

}

 

说明:

Nginx 的超时设置倒是非常清晰容易理解,上面超时针对不同工作模式,但是因为超时带来的问题是非常多的。

 

延伸阅读:

http://hi.baidu.com/pibuchou/blog/item/a1e330dd71fb8a5995ee3753.html

http://hi.baidu.com/pibuchou/blog/item/7cbccff0a3b77dc60b46e024.html

http://hi.baidu.com/pibuchou/blog/item/10a549818f7e4c9df703a626.html

网站导航设计模式指南

 

 

【PHP本身超时处理】

 

[ PHP-fpm ] 

 

配置:php-fpm.conf

 

<?xml version="1.0" ?>

<configuration>

//...

  Sets the limit on the number of simultaneous requests that will be served.

  Equivalent to Apache MaxClients directive.

  Equivalent to PHP_FCGI_CHILDREN environment in original php.fcgi

  Used with any pm_style.

  #php-cgi的进程数量

  <value name="max_children">128</value>

 

 

  The timeout (in seconds) for serving a single request after which the worker process will be terminated

  Should be used when 'max_execution_time' ini option does not stop script execution for some reason

  '0s' means 'off'

 #php-fpm 请求执行超时时间,0s为永不超时,否则设置一个 Ns 为超时的秒数

  <value name="request_terminate_timeout">0s</value>

 

  The timeout (in seconds) for serving of single request after which a php backtrace will be dumped to slow.log file

  '0s' means 'off'

  <value name="request_slowlog_timeout">0s</value>

 

</configuration>

 

 

 

说明:

在 php.ini 中,有一个参数 max_execution_time 可以设置 PHP 脚本的最大执行时间,但是,在 php-cgi(php-fpm) 中,该参数不会起效。真正能够控制 PHP 脚本最大执行时:

 

<value name="request_terminate_timeout">0s</value>  

 

就是说如果是使用 mod_php5.so 的模式运行 max_execution_time 是会生效的,但是如果是php-fpm模式中运行时不生效的。

  

延伸阅读:

http://blog.s135.com/file_get_contents/

 

 

[ PHP ]

 

配置:php.ini

 

选项:

max_execution_time = 30

 

或者在代码里设置:

ini_set("max_execution_time", 30);

set_time_limit(30);

 

说明:

对当前会话生效,比如设置0一直不超时,但是如果php的 safe_mode 打开了,这些设置都会不生效。

效果一样,但是具体内容需要参考php-fpm部分内容,如果php-fpm中设置了 request_terminate_timeout 的话,那么 max_execution_time 就不生效。

 

 

【后端&接口访问超时】

 

【HTTP访问】

 

一般我们访问HTTP方式很多,主要是:curl, socket, file_get_contents() 等方法。

如果碰到对方服务器一直没有响应的时候,我们就悲剧了,很容易把整个服务器搞死,所以在访问http的时候也需要考虑超时的问题。

 

[ CURL 访问HTTP]

CURL 是我们常用的一种比较靠谱的访问HTTP协议接口的lib库,性能高,还有一些并发支持的功能等。

CURL:

 

curl_setopt($ch, opt) 可以设置一些超时的设置,主要包括:

 

*(重要) CURLOPT_TIMEOUT 设置cURL允许执行的最长秒数。   

*(重要) CURLOPT_TIMEOUT_MS 设置cURL允许执行的最长毫秒数。 (在cURL 7.16.2中被加入。从PHP 5.2.3起可使用。 )

 

CURLOPT_CONNECTTIMEOUT 在发起连接前等待的时间,如果设置为0,则无限等待。  

CURLOPT_CONNECTTIMEOUT_MS 尝试连接等待的时间,以毫秒为单位。如果设置为0,则无限等待。  在cURL 7.16.2中被加入。从PHP 5.2.3开始可用。  

CURLOPT_DNS_CACHE_TIMEOUT 设置在内存中保存DNS信息的时间,默认为120秒。  

 

curl普通秒级超时:

        $ch = curl_init(); 

        curl_setopt($ch, CURLOPT_URL,$url); 

        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 

        curl_setopt($ch, CURLOPT_TIMEOUT, 60);   //只需要设置一个秒的数量就可以

        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); 

        curl_setopt($ch, CURLOPT_USERAGENT, $defined_vars['HTTP_USER_AGENT']); 

 

curl普通秒级超时使用:

        curl_setopt($ch, CURLOPT_TIMEOUT, 60);

 

curl如果需要进行毫秒超时,需要增加:

        curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1L); 

        或者是:

        curl_setopt ( $ch,  CURLOPT_NOSIGNAL, true); 是可以支持毫秒级别超时设置的

  

 

curl一个毫秒级超时的例子:

<?php

if (!isset($_GET['foo'])) {

        // Client

        $ch = curl_init('http://example.com/');

        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

        curl_setopt($ch, CURLOPT_NOSIGNAL, 1);    //注意,毫秒超时一定要设置这个

        curl_setopt($ch, CURLOPT_TIMEOUT_MS, 200);  //超时毫秒,cURL 7.16.2中被加入。从PHP 5.2.3起可使用

        $data = curl_exec($ch);

        $curl_errno = curl_errno($ch);

        $curl_error = curl_error($ch);

        curl_close($ch);

 

        if ($curl_errno > 0) {

                echo "cURL Error ($curl_errno): $curl_error\n";

        } else {

                echo "Data received: $data\n";

        }

} else {

        // Server

        sleep(10);

        echo "Done.";

}

?> 

 

其他一些技巧:

1. 按照经验总结是:cURL 版本 >= libcurl/7.21.0 版本,毫秒级超时是一定生效的,切记。

2. curl_multi的毫秒级超时也有问题。。单次访问是支持ms级超时的,curl_multi并行调多个会不准

 

 

[流处理方式访问HTTP] 

除了curl,我们还经常自己使用fsockopen、或者是file操作函数来进行HTTP协议的处理,所以,我们对这块的超时处理也是必须的。

 

一般连接超时可以直接设置,但是流读取超时需要单独处理。

自己写代码处理:

$tmCurrent = gettimeofday();

            $intUSGone = ($tmCurrent['sec'] - $tmStart['sec']) * 1000000

                    + ($tmCurrent['usec'] - $tmStart['usec']);

            if ($intUSGone > $this->_intReadTimeoutUS) {

                return false;

            }

 

或者使用内置流处理函数 stream_set_timeout() 和 stream_get_meta_data() 处理:

 

<?php // Timeout in seconds 

$timeout = 5; 

$fp = fsockopen("example.com", 80, $errno, $errstr, $timeout); 

if ($fp) { 

        fwrite($fp, "GET / HTTP/1.0\r\n"); 

        fwrite($fp, "Host: example.com\r\n"); 

        fwrite($fp, "Connection: Close\r\n\r\n"); 

        stream_set_blocking($fp, true);   //重要,设置为非阻塞模式

        stream_set_timeout($fp,$timeout);   //设置超时

        $info = stream_get_meta_data($fp); 

        while ((!feof($fp)) && (!$info['timed_out'])) { 

                $data .= fgets($fp, 4096); 

                $info = stream_get_meta_data($fp); 

                ob_flush; 

                flush(); 

        } 

        if ($info['timed_out']) { 

                echo "Connection Timed Out!"; 

        } else { 

                echo $data; 

        } 

 

 

file_get_contents 超时:

 

<?php$timeout = array(

    'http' => array(

        'timeout' => 5 //设置一个超时时间,单位为秒

    )

);

$ctx = stream_context_create($timeout);

$text = file_get_contents("http://example.com/", 0, $ctx);

?>

 

 

fopen 超时:

<?php$timeout = array(

    'http' => array(

        'timeout' => 5 //设置一个超时时间,单位为秒

    )

);

$ctx = stream_context_create($timeout);

if ($fp = fopen("http://example.com/", "r", false, $ctx)) {

  while( $c = fread($fp, 8192)) {

    echo $c;

  }

  fclose($fp);

}

?>

 

 

 

 

【MySQL】
php中的mysql客户端都没有设置超时的选项,mysqli和mysql都没有,但是libmysql是提供超时选项的,只是我们在php中隐藏了而已。

 

那么如何在PHP中使用这个操作捏,就需要我们自己定义一些MySQL操作常量,主要涉及的常量有:

MYSQL_OPT_READ_TIMEOUT=11;

MYSQL_OPT_WRITE_TIMEOUT=12;

 

这两个,定义以后,可以使用 options 设置相应的值。

 

不过有个注意点,mysql内部实现:

1. 超时设置单位为秒,最少配置1秒

2. 但mysql底层的read会重试两次,所以实际会是 3 秒

 

重试两次 + 自身一次 = 3倍超时时间,那么就是说最少超时时间是3秒,不会低于这个值,对于大部分应用来说可以接受,但是对于小部分应用需要优化。

 

 

查看一个设置访问mysql超时的php实例:

 

<?php//自己定义读写超时常量

if (!defined('MYSQL_OPT_READ_TIMEOUT')) {

        define('MYSQL_OPT_READ_TIMEOUT',  11);

}

if (!defined('MYSQL_OPT_WRITE_TIMEOUT')) {

        define('MYSQL_OPT_WRITE_TIMEOUT', 12);

}

//设置超时

$mysqli = mysqli_init();

$mysqli->options(MYSQL_OPT_READ_TIMEOUT, 3);

$mysqli->options(MYSQL_OPT_WRITE_TIMEOUT, 1);

 

//连接数据库

$mysqli->real_connect("localhost", "root", "root", "test");

if (mysqli_connect_errno()) {

   printf("Connect failed: %s/n", mysqli_connect_error());

   exit();

}

//执行查询 sleep 1秒不超时

printf("Host information: %s/n", $mysqli->host_info);

if (!($res=$mysqli->query('select sleep(1)'))) {

    echo "query1 error: ". $mysqli->error ."/n";

} else {

    echo "Query1: query success/n";

}

//执行查询 sleep 9秒会超时

if (!($res=$mysqli->query('select sleep(9)'))) {

    echo "query2 error: ". $mysqli->error ."/n";

} else {

    echo "Query2: query success/n";

}

$mysqli->close();

echo "close mysql connection/n";

?>

 

  

延伸阅读:

http://blog.csdn.net/heiyeshuwu/article/details/5869813

 

 

 

 

【Memcached】

 

[PHP扩展]

php_memcache 客户端:

连接超时:bool Memcache::connect ( string $host [, int $port [, int $timeout ]] )

 

在get和set的时候,都没有明确的超时设置参数。

 

libmemcached 客户端:在php接口没有明显的超时参数。

 

说明:所以说,在PHP中访问Memcached是存在很多问题的,需要自己hack部分操作,或者是参考网上补丁。

 

[C&C++访问Memcached]

客户端:libmemcached 客户端

说明:memcache超时配置可以配置小点,比如5,10个毫秒已经够用了,超过这个时间还不如从数据库查询。

 

下面是一个连接和读取set数据的超时的C++示例:

 

//创建连接超时(连接到Memcached)

memcached_st* MemCacheProxy::_create_handle()

{

        memcached_st * mmc = NULL;

        memcached_return_t prc;

        if (_mpool != NULL) {  // get from pool

          mmc = memcached_pool_pop(_mpool, false, &prc);

          if (mmc == NULL) {

            __LOG_WARNING__("MemCacheProxy", "get handle from pool error [%d]", (int)prc);

          }

          return mmc;

        }

 

        memcached_st* handle = memcached_create(NULL);

        if (handle == NULL){

          __LOG_WARNING__("MemCacheProxy", "create_handle error");

          return NULL;

        }

 

        // 设置连接/读取超时

        memcached_behavior_set(handle, MEMCACHED_BEHAVIOR_HASH, MEMCACHED_HASH_DEFAULT);

        memcached_behavior_set(handle, MEMCACHED_BEHAVIOR_NO_BLOCK, _noblock);  //参数MEMCACHED_BEHAVIOR_NO_BLOCK为1使超时配置生效,不设置超时会不生效,关键时候会悲剧的,容易引起雪崩

        memcached_behavior_set(handle, MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT, _connect_timeout);  //连接超时

        memcached_behavior_set(handle, MEMCACHED_BEHAVIOR_RCV_TIMEOUT, _read_timeout);    //读超时

        memcached_behavior_set(handle, MEMCACHED_BEHAVIOR_SND_TIMEOUT, _send_timeout);    //写超时

        memcached_behavior_set(handle, MEMCACHED_BEHAVIOR_POLL_TIMEOUT, _poll_timeout);

 

        // 设置一致hash

        //      memcached_behavior_set_distribution(handle, MEMCACHED_DISTRIBUTION_CONSISTENT);

        memcached_behavior_set(handle, MEMCACHED_BEHAVIOR_DISTRIBUTION, MEMCACHED_DISTRIBUTION_CONSISTENT);

 

        memcached_return rc;

        for (uint i = 0; i < _server_count; i++){

          rc = memcached_server_add(handle, _ips[i], _ports[i]);

          if (MEMCACHED_SUCCESS != rc) {

            __LOG_WARNING__("MemCacheProxy", "add server [%s:%d] failed.", _ips[i], _ports[i]);

          }

        }

 

        _mpool = memcached_pool_create(handle, _min_connect, _max_connect);

        if (_mpool == NULL){

          __LOG_WARNING__("MemCacheProxy", "create_pool error");

          return NULL;

        }

 

        mmc = memcached_pool_pop(_mpool, false, &prc);

        if (mmc == NULL) {

          __LOG_WARNING__("MyMemCacheProxy", "get handle from pool error [%d]", (int)prc);

        }

        //__LOG_DEBUG__("MemCacheProxy", "get handle [%p]", handle);

        return mmc;

}

 

//设置一个key超时(set一个数据到memcached)

bool MemCacheProxy::_add(memcached_st* handle, unsigned int* key, const char* value, int len, unsigned int timeout)

{

        memcached_return rc;

 

        char tmp[1024];

        snprintf(tmp, sizeof (tmp), "%u#%u", key[0], key[1]);

        //有个timeout值

        rc = memcached_set(handle, tmp, strlen(tmp), (char*)value, len, timeout, 0);

        if (MEMCACHED_SUCCESS != rc){

          return false;

        } 

        return true;

}

 

//Memcache读取数据超时 (没有设置)

libmemcahed 源码中接口定义:

LIBMEMCACHED_API char *memcached_get(memcached_st *ptr,const char *key, size_t key_length,size_t *value_length,uint32_t *flags,memcached_return_t *error);

LIBMEMCACHED_API memcached_return_t memcached_mget(memcached_st *ptr,const char * const *keys,const size_t *key_length,size_t number_of_keys);

 

从接口中可以看出在读取数据的时候,是没有超时设置的。

 

  

延伸阅读:

http://hi.baidu.com/chinauser/item/b30af90b23335dde73e67608

http://libmemcached.org/libMemcached.html

 

 

 

【如何实现超时】

 

程序中需要有超时这种功能,比如你单独访问一个后端Socket模块,Socket模块不属于我们上面描述的任何一种的时候,它的协议也是私有的,那么这个时候可能需要自己去实现一些超时处理策略,这个时候就需要一些处理代码了。

 

[PHP中超时实现] 

 

一、初级:最简单的超时实现 (秒级超时)

 

思路很简单:链接一个后端,然后设置为非阻塞模式,如果没有连接上就一直循环,判断当前时间和超时时间之间的差异。

 

php socket 中实现原始的超时:(每次循环都当前时间去减,性能会很差,cpu占用会较高)

<?    $host = "127.0.0.1";

    $port = "80";

    $timeout = 15;  //timeout in seconds

 

    $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)

      or die("Unable to create socket\n");

 

    socket_set_nonblock($socket)     //务必设置为阻塞模式

      or die("Unable to set nonblock on socket\n");

 

    $time = time();

    //循环的时候每次都减去相应值

    while (!@socket_connect($socket, $host, $port))    //如果没有连接上就一直死循环

    {

      $err = socket_last_error($socket);

      if ($err == 115 || $err == 114)

      {

        if ((time() - $time) >= $timeout)    //每次都需要去判断一下是否超时了

        {

          socket_close($socket);

          die("Connection timed out.\n");

        }

        sleep(1);

        continue;

      }

      die(socket_strerror($err) . "\n");

    }

    socket_set_block($this->socket)    //还原阻塞模式

      or die("Unable to set block on socket\n");

?> 

 

二、升级:使用PHP自带异步IO去实现(毫秒级超时)

 

说明:
异步IO:异步IO的概念和同步IO相对。当一个异步过程调用发出后,调用者不能立刻得到结果。实际处理这个调用的部件在完成后,通过状态、通知和回调来通知调用者。异步IO将比特分成小组进行传送,小组可以是8位的1个字符或更长。发送方可以在任何时刻发送这些比特组,而接收方从不知道它们会在什么时候到达。

多路复用:复用模型是对多个IO操作进行检测,返回可操作集合,这样就可以对其进行操作了。这样就避免了阻塞IO不能随时处理各个IO和非阻塞占用系统资源的确定。

 

使用 socket_select() 实现超时

socket_select(..., floor($timeout), ceil($timeout*1000000));
select的特点:能够设置到微秒级别的超时!

  

使用socket_select() 的超时代码(需要了解一些异步IO编程的知识去理解)

### 调用类 ####

<?php 

$server = new Server; 

$client = new Client; 

 

for (;;) { 

  foreach ($select->can_read(0) as $socket) { 

 

    if ($socket == $client->socket) { 

      // New Client Socket 

      $select->add(socket_accept($client->socket)); 

    } 

    else { 

      //there's something to read on $socket 

    } 

  } 

?> 

 

### 异步多路复用IO & 超时连接处理类 ###

<?php 

class select { 

  var $sockets; 

 

  function select($sockets) { 

 

    $this->sockets = array(); 

 

    foreach ($sockets as $socket) { 

      $this->add($socket); 

    } 

  } 

 

  function add($add_socket) { 

    array_push($this->sockets,$add_socket); 

  } 

 

  function remove($remove_socket) { 

    $sockets = array(); 

 

    foreach ($this->sockets as $socket) { 

      if($remove_socket != $socket) 

        $sockets[] = $socket; 

    } 

 

    $this->sockets = $sockets; 

  } 

 

  function can_read($timeout) { 

    $read = $this->sockets; 

    socket_select($read,$write = NULL,$except = NULL,$timeout); 

    return $read; 

  } 

 

  function can_write($timeout) { 

    $write = $this->sockets; 

    socket_select($read = NULL,$write,$except = NULL,$timeout); 

    return $write; 

  } 

?> 

 

 

[C&C++中超时实现] 

 

一般在Linux C/C++中,可以使用:alarm() 设置定时器的方式实现秒级超时,或者:select()、poll()、epoll() 之类的异步复用IO实现毫秒级超时。也可以使用二次封装的异步io库(libevent, libev)也能实现。

 

一、使用alarm中用信号实现超时 (秒级超时)

 

说明:Linux内核connect超时通常为75秒,我们可以设置更小的时间如10秒来提前从connect中返回。这里用使用信号处理机制,调用alarm,超时后产生SIGALRM信号 (也可使用select实现) 

 

用 alarym 秒级实现 connect 设置超时代码示例:

 

//信号处理函数static void connect_alarm(int signo)

{

     debug_printf("SignalHandler");

     return;

}

 

//alarm超时连接实现

static void conn_alarm()

Sigfunc * sigfunc ; //现有信号处理函数

sigfunc=signal(SIGALRM, connect_alarm); //建立信号处理函数connect_alarm,(如果有)保存现有的信号处理函数 

    int timeout = 5;

 

    //设置闹钟

if( alarm(timeout)!=0 ){ 

  //... 闹钟已经设置处理

 

    //进行连接操作

    if (connect(m_Socket, (struct sockaddr *)&addr, sizeof(addr)) < 0 ) {

        if ( errno == EINTR ) { //如果错误号设置为EINTR,说明超时中断了

            debug_printf("Timeout");

            m_connectionStatus = STATUS_CLOSED;

            errno = ETIMEDOUT; //防止三次握手继续进行 

            return ERR_TIMEOUT;

        }

        else {

            debug_printf("Other Err");

            m_connectionStatus = STATUS_CLOSED;

            return ERR_NET_SOCKET;

        }

    }

alarm(0);//关闭时钟 

signal(SIGALRM, sigfunc); //(如果有)恢复原来的信号处理函数 

return; 

}

 

//读取数据的超时设置

同样可以为 recv 设置超时,5秒内收不到任何应答就中断 

signal( ... ); 

alarm(5); 

recv( ... ); 

alarm(0); 

static void sig_alarm(int signo){return;} 

  

当客户端阻塞于读(readline,...)时,如果此时服务器崩了,客户TCP试图从服务器接收一个ACK,持续重传 数据分节,大约要等9分钟才放弃重传,并返回一个错误。因此,在客户读阻塞时,调用超时。

 

 

二、使用异步复用IO使用 (毫秒级超时)

 

异步IO执行流程:

1.首先将标志位设为Non-blocking模式,准备在非阻塞模式下调用connect函数

2.调用connect,正常情况下,因为TCP三次握手需要一些时间;而非阻塞调用只要不能立即完成就会返回错误,所以这里会返回EINPROGRESS,表示在建立连接但还没有完成。

3.在读套接口描述符集(fd_set rset)和写套接口描述符集(fd_set wset)中将当前套接口置位(用FD_ZERO()、FD_SET()宏),并设置好超时时间(struct timeval *timeout)

4.调用select( socket, &rset, &wset, NULL, timeout )

返回0表示connect超时,如果你设置的超时时间大于75秒就没有必要这样做了,因为内核中对connect有超时限制就是75秒。

  

 

//select 实现毫秒级超时示例:
 

static void conn_select() {

    // Open TCP Socket

    m_Socket = socket(PF_INET,SOCK_STREAM,0);

    if( m_Socket < 0 )

    {

        m_connectionStatus = STATUS_CLOSED;

        return ERR_NET_SOCKET;

    }

 

    struct sockaddr_in addr;

    inet_aton(m_Host.c_str(), &addr.sin_addr);

    addr.sin_port = htons(m_Port);

    addr.sin_family = PF_INET;

 

    // Set timeout values for socket

    struct timeval timeouts;

    timeouts.tv_sec = SOCKET_TIMEOUT_SEC ;   // const -> 5

    timeouts.tv_usec = SOCKET_TIMEOUT_USEC ; // const -> 0

    uint8_t optlen = sizeof(timeouts);

 

    if( setsockopt( m_Socket, SOL_SOCKET, SO_RCVTIMEO,&timeouts,(socklen_t)optlen) < 0 )

    {

        m_connectionStatus = STATUS_CLOSED;

        return ERR_NET_SOCKET;

    }

 

    // Set the Socket to TCP Nodelay ( Send immediatly after a send / write command )

    int flag_TCP_nodelay = 1;

    if ( (setsockopt( m_Socket, IPPROTO_TCP, TCP_NODELAY,

            (char *)&flag_TCP_nodelay, sizeof(flag_TCP_nodelay))) < 0)

    {

        m_connectionStatus = STATUS_CLOSED;

        return ERR_NET_SOCKET;

    }

    // Save Socket Flags

    int opts_blocking = fcntl(m_Socket, F_GETFL);

    if ( opts_blocking < 0 )

    {

        return ERR_NET_SOCKET;

    }

    //设置为非阻塞模式

    int opts_noblocking = (opts_blocking | O_NONBLOCK);

    // Set Socket to Non-Blocking

    if (fcntl(m_Socket, F_SETFL, opts_noblocking)<0)

    {

        return ERR_NET_SOCKET;

    }

    // Connect

    if ( connect(m_Socket, (struct sockaddr *)&addr, sizeof(addr)) < 0)

    {

        // EINPROGRESS always appears on Non Blocking connect

        if ( errno != EINPROGRESS )

        {

            m_connectionStatus = STATUS_CLOSED;

            return ERR_NET_SOCKET;

        }

        // Create a set of sockets for select

        fd_set socks;

        FD_ZERO(&socks);

        FD_SET(m_Socket,&socks);

        // Wait for connection or timeout

        int fdcnt = select(m_Socket+1,NULL,&socks,NULL,&timeouts);

        if ( fdcnt < 0 )

        {

            return ERR_NET_SOCKET;

        }

        else if ( fdcnt == 0 )

        {

            return ERR_TIMEOUT;

        }

    }

    //Set Socket to Blocking again

    if(fcntl(m_Socket,F_SETFL,opts_blocking)<0)

    {

        return ERR_NET_SOCKET;

    }

 

    m_connectionStatus = STATUS_OPEN;

    return 0;

}

  

 

说明:在超时实现方面,不论是什么脚本语言:PHP、Python、Perl 基本底层都是C&C++的这些实现方式,需要理解这些超时处理,需要一些Linux 编程和网络编程的知识。

 

延伸阅读:

http://blog.sina.com.cn/s/blog_4462f8560100tvgo.html

http://blog.csdn.net/thimin/article/details/1530839

http://hi.baidu.com/xjtdy888/item/93d9daefcc1d31d1ea34c992

http://blog.csdn.net/byxdaz/article/details/5461142

http://blog.163.com/xychenbaihu@yeah/blog/static/13222965520112163171778/

http://hi.baidu.com/suyupin/item/df10004decb620e91f19bcf5

http://stackoverflow.com/questions/7092633/connect-timeout-with-alarm

http://stackoverflow.com/questions/7089128/linux-tcp-connect-with-select-fails-at-testserver?lq=1

http://cppentry.com/bencandy.php?fid=54&id=1129

 

 

 

【 总结 】

 

1. PHP应用层如何设置超时?

PHP在处理超时层次有很多,不同层次,需要前端包容后端超时:

浏览器(客户端) -> 接入层 -> Web服务器  -> PHP  -> 后端 (MySQL、Memcached)

 

就是说,接入层(Web服务器层)的超时时间必须大于PHP(PHP-FPM)中设置的超时时间,不然后面没处理完,你前面就超时关闭了,这个会很杯具。还有就是PHP的超时时间要大于PHP本身访问后端(MySQL、HTTP、Memcached)的超时时间,不然结局同前面。

 

2. 超时设置原则是什么?

如果是希望永久不超时的代码(比如上传,或者定期跑的程序),我仍然建议设置一个超时时间,比如12个小时这样的,主要是为了保证不会永久夯住一个php进程或者后端,导致无法给其他页面提供服务,最终引起所有机器雪崩。

如果是要要求快速响应的程序,建议后端超时设置短一些,比如连接500ms,读1s,写1s,这样的速度,这样能够大幅度减少应用雪崩的问题,不会让服务器负载太高。

 

3. 自己开发超时访问合适吗?

一般如果不是万不得已,建议用现有很多网络编程框架也好、基础库也好,里面一般都带有超时的实现,比如一些网络IO的lib库,尽量使用它们内置的,自己重复造轮子容易有bug,也不方便维护(不过如是是基于学习的目的就当别论了)。

 

4. 其他建议

超时在所有应用里都是大问题,在开发应用的时候都要考虑到。我见过一些应用超时设置上百秒的,这种性能就委实差了,我举个例子:

比如你php-fpm开了128个php-cgi进程,然后你的超时设置的是32s,那么我们如果后端服务比较差,极端情况下,那么最多每秒能响应的请求是:

128 / 32 = 4个 

你没看错,1秒只能处理4个请求,那服务也太差了!虽然我们可以把php-cgi进程开大,但是内存占用,还有进程之间切换成本也会增加,cpu呀,内存呀都会增加,服务也会不稳定。所以,尽量设置一个合理的超时值,或者督促后端提高性能。

305月/130

PHP 正则表达式简单笔记

发布在 邵珠庆

1.简单介绍

在编写处理字符串的程序或网页时,经常会有查找符合某些复杂规则的字符串的需要。正则表达式就是用于描述这些规则的语法。

例:在判断用户邮件地址格式、手机号码格式或者采集别人网页内容时

主要的作用是:分割、匹配、查找、替换

注:正则表达式对于一个程序员来讲是至关重要的一个知识点,所以学好正则是每一个程序员必须具备的。不仅可以帮助我们完成一些通过函数无法实现的工作,还可以帮助我们减轻很多工作量。

2、PHP中两个常用的正则函数

preg_match 正则函数,以perl语言为基础

preg_match ( mode, string subject , array matches )

ereg 正则函数,以POSIX基础 (Unix 、 Script)

ereg ( mode, string subject , array regs )

3、正则表达式中包括的元素

(1)、原子(普通字符:a-z A-Z 0-9 、原子表、 转义字符)

(2)、元字符 (有特殊功能的字符)

(3)、模式修正符 (系统内置部分字符 i 、m、S、U…)

4、正则表达式中的“原子”

①a-z A-Z _ 0-9 //最常见的字符

②(abc) (skd) //用圆括号包含起来的单元符合

③[abcs] [^abd] //用方括号包含的原子表,原子表中的^代表排除或相反内容

④转义字符

\d 包含所有数字[0-9]

\D 除所有数字外[^0-9]

\w 包含所有英文字符[a-zA-Z_0-9]

\W 除所有英文字符外[^a-zA-Z_0-9] \s 包含空白区域如回车、换行、分页等 [\f\n\r]

5、正则表达式元字符

* 匹配前一个内容的0次1次或多次

. 匹配内容的0次1次或多次,但不包含回车换行

+ 匹配前一个内容的1次或多次

?匹配前一个内容的0次或1次

| 选择匹配类似PHP中的| (因为这个运算符合是弱类型导致前面最为整体匹配)

^ 匹配字符串首部内容

$ 匹配字符串尾部内容

\b 匹配单词边界,边界可以是空格或者特殊符合

\B 匹配除带单词边界意外内容

{m} 匹配前一个内容的重复次数为M次

{m,} 匹配前一个内容的重复次数大于等于M次

{m,n} 匹配前一个内容的重复次数M次到N次

( ) 合并整体匹配,并放入内存,可使用\1 \2…依次获取

6、运算顺序

依然遵循从左到→右的运算规则

优先级

①( ) 圆括号因为是内存处理所以最高

②* ? + { } 重复匹配内容其次

③^ $ \b 边界处理第三

④| 条件处理第四

最后按照运算顺序计算匹配

7、模式修正符,是为正则表达式增强和补充的一个功能。

常用修正符

i 正则内容在匹配时候不区分大小写(默认是区分的)

m 在匹配首内容或者尾内容时候采用多行识别匹配

S 将转义回车取消是为单行匹配如. 匹配的时候

x 忽略正则中的空白

A 强制从头开始匹配

D 强制$匹配尾部无任何内容 \n

U 禁止贪婪匹配 只跟踪到最近的一个匹配符并结束

 

匹配指定的标签对,标签对间可以有内容:/<\s*h4[^>]*>(.*?)<\s*/\s*h4>/g
匹配所有的标签和标签属性:/<(.|\n)*?>/g
匹配所有的开始标签,标签里可以有属性:/<\s*\w.*?>/g
匹配所有的结束标签:/<\s*\/\s*\w\s*.*?>|<\s*br\s*>/g
匹配指定的开始标签,标签里可以有属性:/<\s*div.*?>/g
匹配标签对间有内容的结束标签:/<\s*\/\s*div\s*.*?>/g
匹配所有指定的标签(不管开始或结束标签),标签里有可以有属性:/<\s*\/?\s*span\s*.*?>/g
匹配有指定属性的开始标签:/<\s*\w*\s*style.*?>/g
匹配有指定属性和指定的属性值的开始标签:/<\s*\w*\s*href\s*=\s*”?\s*([\w\s%#\/\.;:_-]*)\s*”?.*?>/g

 

 

274月/130

PHP中设置Session过期方法

发布在 邵珠庆

Session的有效期是随浏览器进程的,浏览器关掉后就没了,那么怎么像Cookies那样设置过期时间呢?下面这段代码就可以实现。

 
1
2
3
4
5
<?php
$cookies_life_time = 24 * 3600;   //过期时间,单位为秒,这里的设置即为一天
session_start();
setcookie(session_name() ,session_id(), time() + $cookies_life_time, "/");
?>
244月/130

PHP读取文件的常见方法

发布在 邵珠庆

整理了一下PHP中读取文件的几个方法,方便以后查阅。

1.fread

string fread ( int $handle , int $length )

fread() 从 handle 指向的文件中读取最多 length 个字节。该函数在读取完最多 length 个字节数,或到达 EOF 的时候,或(对于网络流)当一个包可用时,或(在打开用户空间流之后)已读取了 8192 个字节时就会停止读取文件,视乎先碰到哪种情况。

fread() 返回所读取的字符串,如果出错返回 FALSE。

复制代码
<?php
    $filename = "/usr/local/something.txt";
    $handle = fopen($filename, "r");//读取二进制文件时,需要将第二个参数设置成'rb'
    
    //通过filesize获得文件大小,将整个文件一下子读到一个字符串中
    $contents = fread($handle, filesize ($filename));
    fclose($handle);
?>
复制代码

如果所要读取的文件不是本地普通文件,而是远程文件或者流文件,就不能用这种方法,因为,filesize不能获得这些文件的大小。此时,你需要通过feof()或者fread()的返回值判断是否已经读取到了文件的末尾。

例如:

复制代码
<?php
    $handle = fopen('http://www.baidu.com', 'r');
    $content = '';
    while(!feof($handle)){
        $content .= fread($handle, 8080);
    }
    echo $content;
    fclose($handle);
?>
复制代码

或者:

复制代码
<?php
    $handle = fopen('http://www.baidu.com', 'r');
    $content = '';
    while(false != ($a = fread($handle, 8080))){//返回false表示已经读取到文件末尾
        $content .= $a;
    }
    echo $content;
    fclose($handle);
?>
复制代码

 

2.fgets

 string fgets ( int $handle [, int $length ] )

  fgets()从 handle 指向的文件中读取一行并返回长度最多为 length - 1 字节的字符串。碰到换行符(包括在返回值中)、EOF 或者已经读取了 length - 1 字节后停止(看先碰到那一种情况)。如果没有指定 length,则默认为 1K,或者说 1024 字节。

复制代码
<?php
    $handle = fopen('./file.txt', 'r');
    while(!feof($handle)){
        echo fgets($handle, 1024);
    }
    fclose($handle);
?>
复制代码

Note: length 参数从 PHP 4.2.0 起成为可选项,如果忽略,则行的长度被假定为 1024。从 PHP 4.3 开始,忽略掉 length 将继续从流中读取数据直到行结束。如果文件中的大多数行都大于 8KB,则在脚本中指定最大行的长度在利用资源上更为有效。从 PHP 4.3 开始本函数可以安全用于二进制文件。早期的版本则不行。

3.fgetss

string fgetss ( resource $handle [, int $length [, string $allowable_tags ]] )

跟fgets功能一样,但是fgetss会尝试从读取的文本中去掉任何 HTML 和 PHP 标记,可以用可选的第三个参数指定哪些标记不被去掉。

复制代码
<?php
    $handle = fopen('./file.txt', 'r');
    while(!feof($handle)){
        echo fgetss($handle, 1024, '<br>');
    }
    fclose($handle);
?>
复制代码

 

4.file

array file ( string $filename [, int $use_include_path [, resource $context ]] )
将文件内容读入一个数组中,数组的每一项对应文件中的一行,包括换行符在内。不需要行结束符时可以使用 rtrim() 函数过滤换行符。

复制代码
<?php
    $a = file('./file.txt');
    foreach($a as $line => $content){
        echo 'line '.($line + 1).':'.$content;
    }
?>
复制代码

 5.readfile

int readfile ( string $filename [, bool $use_include_path [, resource $context ]] )

读入一个文件并写入到输出缓冲。返回从文件中读入的字节数。如果出错返回 FALSE 并且除非是以 @readfile() 形式调用,否则会显示错误信息。

<?php
    $size = readfile('./file.txt');
    echo $size;
?>

 

6.file_get_contents

string file_get_contents ( string $filename [, bool $use_include_path [, resource $context [, int $offset [, int $maxlen ]]]] )

将文件读入一个字符串。第三个参数$context可以用来设置一些参数,比如访问远程文件时,设置超时等等。

另外,file_get_contents相对于以上几个函数,性能要好得多,所以应该优先考虑使用file_get_contents。但是readfile貌似比file_get_contents性能好一点(?),因为它不需要调用fopen。

复制代码
<?php 
    $ctx = stream_context_create(array( 
        'http' => array( 
            'timeout' => 1    //设置超时
            ) 
        ) 
    ); 
    echo file_get_contents("http://www.baidu.com/", 0, $ctx); 
?>
复制代码

7.fpassthru

   int fpassthru ( resource $handle )

将给定的文件指针从当前的位置读取到 EOF 并把结果写到输出缓冲区。

复制代码
<?php 
    header("Content-Type:text/html;charset=utf-8"); 
    $handle = fopen('./test2.php', 'r');
    fseek($handle, 1024);//将指针定位到1024字节处
    fpassthru($handle);
?>
复制代码

 

8.parse_ini_file

array parse_ini_file ( string $filename [, bool $process_sections ] )

parse_ini_file() 载入一个由 filename 指定的 ini 文件,并将其中的设置作为一个联合数组返回。如果将最后的 process_sections 参数设为 TRUE,将得到一个多维数组,包括了配置文件中每一节的名称和设置。process_sections 的默认值是 FALSE。

注意:

1. 如果 ini 文件中的值包含任何非字母数字的字符,需要将其括在双引号中(")。
2. 有些保留字不能作为 ini 文件中的键名,包括:null,yes,no,true 和 false。值为 null,no 和 false 等效于 "",值为 yes 和 true 等效于 "1"。字符 {}|&~![()" 也不能用在键名的任何地方,而且这些字符在选项值中有着特殊的意义。

test.ini文件内容:

复制代码
; This is a sample configuration file
; Comments start with ';', as in php.ini

[first_section]
one = 1
five = 5
animal = BIRD

[second_section]
path = "/usr/local/bin"
URL = "http://www.example.com/~username
复制代码

test.php内容:

<?php 
    $config = parse_ini_file('./test.ini', ture);
    print_r($config);
?>

输出内容:

复制代码
Array
(
    [first_section] => Array
        (
            [one] => 1
            [five] => 5
            [animal] => BIRD
        )

    [second_section] => Array
        (
            [path] => /usr/local/bin
            [URL] => http://www.example.com/~username
        )

)
复制代码

 

 

 

几个注意事项:

1. 鼓励在处理二进制文件时使用 b 标志,即使系统并不需要,这样可以使脚本的移植性更好。 

2. allow_url_fopen选项激活了 URL 形式的 fopen 封装协议使得可以访问 URL 对象例如文件。默认的封装协议提供用 ftp 和 http 协议来访问远程文件,一些扩展库例如 zlib 可能会注册更多的封装协议。出于安全性考虑,此选项只能在 php.ini 中设置。

3. 如果要打开有特殊字符的 URL (比如说有空格),就需要使用 urlencode() 进行 URL 编码。

52月/130

PHP的简单正则判断字符串类型

发布在 邵珠庆

前两天写PHP代码的时候遇到要判断一个变量是否为数字,所以就把相关的文章简单的摘抄了过来:

php 正则验证字符串是否为数字
方法一:
php中利用正则表达式验证字符串是否为数字一件非常容易的事情,最主要的是如何写好正则表达式以及掌握正则表达式的写法,在此利用正则表达式的方式来列举一下判断数字的方法。

<?

if($str){
  if(eregi("^[0-9]+$",$str)){
    $str=(int)$str;
  }else{
    echo "获取到的数据不是有效的数字类型,操作将停止!";
    exit();
  }
}else{
  echo "需要验证的数据为空,操作停止!";
  exit();
}

?>

方法二:
建议大家对关键的参数必须做过滤。

如数字正则过滤
if(preg_match("/^\d*$/",$fgid)) {echo('是数字');}else{echo('不是数字');}

或者用函数
if(is_numeric($fgid)) {echo('是数字');}else{ echo('不是数字');}

这两种方法的区别是  is_numeric小数也会认为是数字,而前面正则会把小数点当作字符。

附一些常用的正则运算:

验证数字:^[0-9]*$
验证n位的数字:^\d{n}$
验证至少n位数字:^\d{n,}$
验证m-n位的数字:^\d{m,n}$
验证零和非零开头的数字:^(0|[1-9][0-9]*)$
验证有两位小数的正实数:^[0-9]+(.[0-9]{2})?$
验证有1-3位小数的正实数:^[0-9]+(.[0-9]{1,3})?$
验证非零的正整数:^\+?[1-9][0-9]*$
验证非零的负整数:^\-[1-9][0-9]*$
验证非负整数(正整数 + 0)  ^\d+$
验证非正整数(负整数 + 0)  ^((-\d+)|(0+))$
验证长度为3的字符:^.{3}$
验证由26个英文字母组成的字符串:^[A-Za-z]+$
验证由26个大写英文字母组成的字符串:^[A-Z]+$
验证由26个小写英文字母组成的字符串:^[a-z]+$
验证由数字和26个英文字母组成的字符串:^[A-Za-z0-9]+$
验证由数字、26个英文字母或者下划线组成的字符串:^\w+$
验证用户密码:^[a-zA-Z]\w{5,17}$ 正确格式为:以字母开头,长度在6-18之间,只能包含字符、数字和下划线。
验证是否含有 ^%&‘,;=?$\” 等字符:[^%&‘,;=?$\x22]+
验证汉字:^[\u4e00-\u9fa5],{0,}$
验证Email地址:^\w+[-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$
验证InternetURL:^http://([\w-]+\.)+[\w-]+(/[\w-./?%&=]*)?$ ;^[a-zA-z]+://(w+(-w+)*)(.(w+(-w+)*))*(?S*)?$
验证电话号码:^(\(\d{3,4}\)|\d{3,4}-)?\d{7,8}$:–正确格式为:XXXX-XXXXXXX,XXXX-XXXXXXXX,XXX-XXXXXXX,XXX-XXXXXXXX,XXXXXXX,XXXXXXXX。
验证身份证号(15位或18位数字):^\d{15}|\d{}18$
验证一年的12个月:^(0?[1-9]|1[0-2])$ 正确格式为:“01”-“09”和“1”“12”
验证一个月的31天:^((0?[1-9])|((1|2)[0-9])|30|31)$    正确格式为:01、09和1、31。
整数:^-?\d+$
非负浮点数(正浮点数 + 0):^\d+(\.\d+)?$
正浮点数   ^(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*))$
非正浮点数(负浮点数 + 0) ^((-\d+(\.\d+)?)|(0+(\.0+)?))$
负浮点数  ^(-(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*)))$
浮点数  ^(-?\d+)(\.\d+)?

 

 

 

271月/130

《Head First 设计模式》代码之PHP版

发布在 邵珠庆

《Head First 设计模式》是本不错的讲解设计模式的书,不像F4写的那么枯燥,应该算是比较容易理解的好书。书中的例子都比较浅显易懂,不过由于是外国佬写的,所以例子的习惯不是很附合中国特色,可能偶尔看起来有些别扭,还有语言习惯也不是中国风。当然看过这本书之后,你才能深刻理解设计模式到底能为你解决哪些题,不能为你解决哪些问题(比如不能代替你的编码)。

策略模式

 

[php] view plaincopy

 
  1. <?php  
  2. /** 
  3.  * 策略模式 
  4.  * 定义了算法族,分别封装起来,让它们之间可以互相替换, 
  5.  * 此模式让算法的变化独立于使用算法的客户。 
  6.  */  
  7. //飞行行为接口  
  8. interface FlyBehavior {  
  9.     public function fly();  
  10. }  
  11. //呱呱叫行为接口  
  12. interface QuackBehavior {  
  13.     public function quack();  
  14. }  
  15. //翅膀飞行  
  16. class FlyWithWings implements FlyBehavior {  
  17.     public function fly() {  
  18.         echo "I'm flying!!/n";  
  19.     }  
  20. }  
  21. //不会飞  
  22. class FlyNoWay implements FlyBehavior {  
  23.     public function fly() {  
  24.         echo "I can't fly!/n";  
  25.     }  
  26. }  
  27. class FlyRocketPowered implements FlyBehavior {  
  28.     public function fly() {  
  29.         echo "I'm flying with a rocket!/n";  
  30.     }  
  31. }  
  32. class Qquack implements QuackBehavior {  
  33.     public function quack() {  
  34.         echo "Quack/n";  
  35.     }  
  36. }  
  37. class Squeak implements QuackBehavior {  
  38.     public function quack() {  
  39.         echo "Squeak/n";  
  40.     }  
  41. }  
  42. class MuteQuack implements QuackBehavior {  
  43.     public function quack() {  
  44.         echo "<< Silence >>/n";  
  45.     }  
  46. }  
  47. abstract class Duck {  
  48.     protected $quack_obj;  
  49.     protected $fly_obj;  
  50.     public abstract function display();  
  51.     public function performQuack() {  
  52.         $this->quack_obj->quack();  
  53.     }  
  54.     public function performFly() {  
  55.         $this->fly_obj->fly();  
  56.     }  
  57.     public function swim() {  
  58.         echo "All ducks float, even decoys!/n";  
  59.     }  
  60.     public function setFlyBehavior(FlyBehavior $fb) {  
  61.         $this->fly_obj = $fb;  
  62.     }  
  63.     public function setQuackBehavior(QuackBehavior $qb) {  
  64.         $this->quack_obj = $qb;  
  65.     }  
  66. }  
  67. class ModelDuck extends Duck {  
  68.     public function __construct() {  
  69.         $this->fly_obj = new FlyNoWay();  
  70.         $this->quack_obj = new MuteQuack();  
  71.     }  
  72.     public function display() {  
  73.         echo "I'm a model duck!/n";  
  74.     }  
  75. }  
  76. $model = new ModelDuck();  
  77. $model->performFly();  
  78. $model->performQuack();  
  79. //提供新的能力  
  80. $model->setFlyBehavior(new FlyRocketPowered());  
  81. $model->setQuackBehavior(new Squeak());  
  82. $model->performFly();  
  83. $model->performQuack();  
  84. ?>  

 

单件模式

 

[php] view plaincopy

 
  1. <?php  
  2. /** 
  3.  * 单件模式 
  4.  * 确保一个类只有一个实例,并提供一个全局访问点。 
  5.  */  
  6. class MyClass {  
  7.     private static $uniqueInstance;  
  8.     private function __construct() {  
  9.     }  
  10.     public static function getInstance() {  
  11.         if (self::$uniqueInstance == null) {  
  12.             self::$uniqueInstance = new MyClass();  
  13.         }  
  14.         return self::$uniqueInstance;  
  15.     }  
  16. }  
  17. $myClass = MyClass::getInstance();  
  18. var_dump($myClass);  
  19. $myClass = MyClass::getInstance();  
  20. var_dump($myClass);  
  21. ?>  

 

工厂方法模式

 

[php] view plaincopy

 
  1. <?php  
  2. abstract class PizzaStore {  
  3.     public function orderPizza($type) {  
  4.         $pizza = $this->createPizza($type);  
  5.         $pizza->prepare();  
  6.         $pizza->bake();  
  7.         $pizza->cut();  
  8.         $pizza->box();  
  9.         return $pizza;  
  10.     }  
  11.     public abstract function createPizza($type);  
  12. }  
  13. class NYPizzaStore extends PizzaStore {  
  14.     public function createPizza($type) {  
  15.         if ($type == "cheese") {  
  16.             return new NYStyleCheesePizza();  
  17.         } elseif ($type == "veggie") {  
  18.             return new NYStyleVeggiePizza();  
  19.         } elseif ($type == "clam") {  
  20.             return new NYStyleClamPizza();  
  21.         } elseif ($type == "papperoni") {  
  22.             return new NYStylePapperoniPizza();  
  23.         } else {  
  24.             return null;  
  25.         }  
  26.     }  
  27. }  
  28. class ChicagoPizzaStore extends PizzaStore {  
  29.     public function createPizza($type) {  
  30.         if ($type == "cheese") {  
  31.             return new ChicagoStyleCheesePizza();  
  32.         } elseif ($type == "veggie") {  
  33.             return new ChicagoStyleVeggiePizza();  
  34.         } elseif ($type == "clam") {  
  35.             return new ChicagoStyleClamPizza();  
  36.         } elseif ($type == "papperoni") {  
  37.             return new ChicagoStylePapperoniPizza();  
  38.         } else {  
  39.             return null;  
  40.         }  
  41.     }  
  42. }  
  43. abstract class Pizza {  
  44.     public $name;  
  45.     public $dough;  
  46.     public $sauce;  
  47.     public $toppings = array();  
  48.     public function prepare() {  
  49.         echo "Preparing " . $this->name . "/n";  
  50.         echo "Yossing dough.../n";  
  51.         echo "Adding sauce.../n";  
  52.         echo "Adding toppings: /n";  
  53.         for ($i = 0; $i < count($this->toppings); $i++) {  
  54.             echo "    " . $this->toppings[$i] . "/n";  
  55.         }  
  56.     }  
  57.     public function bake() {  
  58.         echo "Bake for 25 minutes at 350/n";  
  59.     }  
  60.     public function cut() {  
  61.         echo "Cutting the pizza into diagonal slices/n";  
  62.     }  
  63.     public function box() {  
  64.         echo "Place pizza in official PizzaStore box/n";  
  65.     }  
  66.     public function getName() {  
  67.         return $this->name;  
  68.     }  
  69. }  
  70. class NYStyleCheesePizza extends Pizza {  
  71.     public function __construct() {  
  72.         $this->name = "NY Style Sauce and cheese Pizza";  
  73.         $this->dough = "Thin Crust Dough";  
  74.         $this->sauce = "Marinara Sauce";  
  75.         $this->toppings[] = "Grated Reggiano Cheese";  
  76.     }  
  77. }  
  78. class NYStyleVeggiePizza extends Pizza {  
  79.     public function __construct() {  
  80.         $this->name = "NY Style Sauce and veggie Pizza";  
  81.         $this->dough = "Thin Crust Dough";  
  82.         $this->sauce = "Marinara Sauce";  
  83.         $this->toppings[] = "Grated Reggiano veggie";  
  84.     }  
  85. }  
  86. class NYStyleClamPizza extends Pizza {  
  87.     public function __construct() {  
  88.         $this->name = "NY Style Sauce and clam Pizza";  
  89.         $this->dough = "Thin Crust Dough";  
  90.         $this->sauce = "Marinara Sauce";  
  91.         $this->toppings[] = "Grated Reggiano clam";  
  92.     }  
  93. }  
  94. class NYStylePapperoniPizza extends Pizza {  
  95.     public function __construct() {  
  96.         $this->name = "NY Style Sauce and papperoni Pizza";  
  97.         $this->dough = "Thin Crust Dough";  
  98.         $this->sauce = "Marinara Sauce";  
  99.         $this->toppings[] = "Grated Reggiano papperoni";  
  100.     }  
  101. }  
  102. class ChicagoStyleCheesePizza extends Pizza {  
  103.     public function __construct() {  
  104.         $this->name = "Chicago Style Deep Dish Cheese Pizza";  
  105.         $this->dough = "Extra Thick Crust Dough";  
  106.         $this->sauce = "Plum Tomato Sauce";  
  107.         $this->toppings[] = "Shredded Mozzarella Cheese";  
  108.     }  
  109.     public function cut() {  
  110.         echo "Cutting the pizza into square slices/n";  
  111.     }  
  112. }  
  113. $myStore = new NYPizzaStore();  
  114. $chicagoStore = new ChicagoPizzaStore();  
  115. $pizza = $myStore->orderPizza("cheese");  
  116. echo "Ethan ordered a " . $pizza->getName() . "/n";  
  117. $pizza = $chicagoStore->orderPizza("cheese");  
  118. echo "Ethan ordered a " . $pizza->getName() . "/n";  
  119. ?>  

 

工厂模式

 

[php] view plaincopy

 
  1. <?php  
  2. abstract class PizzaStore {  
  3.     public function orderPizza($type) {  
  4.         $pizza = $this->createPizza($type);  
  5.         $pizza->prepare();  
  6.         $pizza->bake();  
  7.         $pizza->cut();  
  8.         $pizza->box();  
  9.         return $pizza;  
  10.     }  
  11.     public abstract function createPizza($type);  
  12. }  
  13. class NYPizzaStore extends PizzaStore {  
  14.     public function createPizza($type) {  
  15.         $pizza = null;  
  16.         $ingredientFactory = new NYPizzaIngredientFactory();  
  17.         if ($type == "cheese") {  
  18.             $pizza = new CheesePizza($ingredientFactory);  
  19.             $pizza->setName('New York Style Cheese Pizza');  
  20.         } elseif ($type == "veggie") {  
  21.             $pizza = new VeggiePizza($ingredientFactory);  
  22.             $pizza->setName('New York Style Veggie Pizza');  
  23.         } elseif ($type == "clam") {  
  24.             $pizza = new ClamPizza($ingredientFactory);  
  25.             $pizza->setName('New York Style Clam Pizza');  
  26.         } elseif ($type == "papperoni") {  
  27.             $pizza = new PapperoniPizza($ingredientFactory);  
  28.             $pizza->setName('New York Style Papperoni Pizza');  
  29.         }  
  30.         return $pizza;  
  31.     }  
  32. }  
  33. class ChicagoPizzaStore extends PizzaStore {  
  34.     public function createPizza($type) {  
  35.         if ($type == "cheese") {  
  36.             return new ChicagoStyleCheesePizza();  
  37.         } elseif ($type == "veggie") {  
  38.             return new ChicagoStyleVeggiePizza();  
  39.         } elseif ($type == "clam") {  
  40.             return new ChicagoStyleClamPizza();  
  41.         } elseif ($type == "papperoni") {  
  42.             return new ChicagoStylePapperoniPizza();  
  43.         } else {  
  44.             return null;  
  45.         }  
  46.     }  
  47. }  
  48. interface PizzaIngredientFactory {  
  49.     public function createDough();  
  50.     public function createSauce();  
  51.     public function createCheese();  
  52.     public function createVeggies();  
  53.     public function createPepperoni();  
  54.     public function createClam();  
  55. }  
  56. class NYPizzaIngredientFactory implements PizzaIngredientFactory {  
  57.     public function createDough() {  
  58.         return new ThinCrustDough();  
  59.     }  
  60.     public function createSauce() {  
  61.         return new MarinaraSauce();  
  62.     }  
  63.     public function createCheese() {  
  64.         return new ReggianoCheese();  
  65.     }  
  66.     public function createVeggies() {  
  67.         $veggies = array(  
  68.         new Garlic(),  
  69.         new Onion(),  
  70.         new Mushroom(),  
  71.         new RedPepper(),  
  72.         );  
  73.         return $veggies;  
  74.     }  
  75.     public function createPepperoni() {  
  76.         return new SlicedPepperoni();  
  77.     }  
  78.     public function createClam() {  
  79.         return new FreshClams();  
  80.     }  
  81. }  
  82. class ChicagoPizzaIngredientFactory implements PizzaIngredientFactory {  
  83.     public function createDough() {  
  84.         return new ThickCrustDough();  
  85.     }  
  86.     public function createSauce() {  
  87.         return new PlumTomatoSauce();  
  88.     }  
  89.     public function createCheese() {  
  90.         return new Mozzarella();  
  91.     }  
  92.     public function createVeggies() {  
  93.         $veggies = array(  
  94.         new BlackOlives(),  
  95.         new Spinach(),  
  96.         new EggPlant(),  
  97.         );  
  98.         return $veggies;  
  99.     }  
  100.     public function createPepperoni() {  
  101.         return new SlicedPepperoni();  
  102.     }  
  103.     public function createClam() {  
  104.         return new FrozenClams();  
  105.     }  
  106. }  
  107. abstract class Pizza {  
  108.     public $name;  
  109.     public $dough;  
  110.     public $sauce;  
  111.     public $veggies = array();  
  112.     public $cheese;  
  113.     public $pepperoni;  
  114.     public $clam;  
  115.     public abstract function prepare();  
  116.     public function bake() {  
  117.         echo "Bake for 25 minutes at 350/n";  
  118.     }  
  119.     public function cut() {  
  120.         echo "Cutting the pizza into diagonal slices/n";  
  121.     }  
  122.     public function box() {  
  123.         echo "Place pizza in official PizzaStore box/n";  
  124.     }  
  125.     public function getName() {  
  126.         return $this->name;  
  127.     }  
  128.     public function setName($name) {  
  129.         $this->name = $name;  
  130.     }  
  131.     public function __toString() {  
  132.     }  
  133. }  
  134. class CheesePizza extends Pizza {  
  135.     public $ingredientFactory;  
  136.     public function __construct(PizzaIngredientFactory $ingredientFactory) {  
  137.         $this->ingredientFactory = $ingredientFactory;  
  138.     }  
  139.     public function prepare() {  
  140.         echo "Preparing " . $this->name . "/n";  
  141.         $this->dough = $this->ingredientFactory->createDough();  
  142.         $this->sauce = $this->ingredientFactory->createSauce();  
  143.         $this->cheese = $this->ingredientFactory->createCheese();  
  144.     }  
  145. }  
  146. class ClamPizza extends Pizza {  
  147.     public $ingredientFactory;  
  148.     public function __construct(PizzaIngredientFactory $ingredientFactory) {  
  149.         $this->ingredientFactory = $ingredientFactory;  
  150.     }  
  151.     public function prepare() {  
  152.         echo "Preparing " . $this->name . "/n";  
  153.         $this->dough = $this->ingredientFactory->createDough();  
  154.         $this->sauce = $this->ingredientFactory->createSauce();  
  155.         $this->cheese = $this->ingredientFactory->createCheese();  
  156.         $clam = $this->ingredientFactory->createClam();  
  157.     }  
  158. }  
  159. $nyPizzaStore = new NYPizzaStore();  
  160. $nyPizzaStore->orderPizza('cheese');  
  161. ?>  

 

观察者模式

 

[php] view plaincopy

 
  1. <?php  
  2. /** 
  3.  * 观察者模式 
  4.  * 定义了对象之间的一对多依赖,当一个对象改变状态时, 
  5.  * 它的所有依赖者都会收到通知并自动更新。 
  6.  */  
  7. interface Subject {  
  8.     public function registerObserver(Observer $o);  
  9.     public function removeObserver(Observer $o);  
  10.     public function notifyObservers();  
  11. }  
  12. interface Observer {  
  13.     public function update($temperature, $humidity, $pressure);  
  14. }  
  15. interface DisplayElement {  
  16.     public function display();  
  17. }  
  18. class WeatherData implements Subject {  
  19.     private $observers = array();  
  20.     private $temperature;  
  21.     private $humidity;  
  22.     private $pressure;  
  23.     public function __construct() {  
  24.         $this->observers = array();  
  25.     }  
  26.     public function registerObserver(Observer $o) {  
  27.         $this->observers[] = $o;  
  28.     }  
  29.     public function removeObserver(Observer $o) {  
  30.         if (($key = array_search($o, $this->observers)) !== false) {  
  31.             unset($this->observers[$key]);  
  32.         }  
  33.     }  
  34.     public function notifyObservers() {  
  35.         foreach ($this->observers as $observer) {  
  36.             $observer->update($this->temperature, $this->humidity, $this->pressure);  
  37.         }  
  38.     }  
  39.     public function measurementsChanged() {  
  40.         $this->notifyObservers();  
  41.     }  
  42.     public function setMeasurements($temperature, $humidity, $pressure) {  
  43.         $this->temperature = $temperature;  
  44.         $this->humidity = $humidity;  
  45.         $this->pressure = $pressure;  
  46.         $this->measurementsChanged();  
  47.     }  
  48. }  
  49. class CurrentConditionsDisplay implements Observer, DisplayElement {  
  50.     private $temperature;  
  51.     private $humidity;  
  52.     private $weatherData;  
  53.     public function __construct(Subject $weatherData) {  
  54.         $this->weatherData = $weatherData;  
  55.         $weatherData->registerObserver($this);  
  56.     }  
  57.     public function update($temperature, $humidity, $pressure) {  
  58.         $this->temperature = $temperature;  
  59.         $this->humidity = $humidity;  
  60.         $this->display();  
  61.     }  
  62.     public function display() {  
  63.         echo "温度:" . $this->temperature . "; 湿度:" . $this->humidity . "%/n";  
  64.     }  
  65. }  
  66. class StatistionsDisplay implements Observer, DisplayElement {  
  67.     private $temperature;  
  68.     private $humidity;  
  69.     private $pressure;  
  70.     private $weatherData;  
  71.     public function __construct(Subject $weatherData) {  
  72.         $this->weatherData = $weatherData;  
  73.         $weatherData->registerObserver($this);  
  74.     }  
  75.     public function update($temperature, $humidity, $pressure) {  
  76.         $this->temperature = $temperature;  
  77.         $this->humidity = $humidity;  
  78.         $this->pressure = $pressure;  
  79.         $this->display();  
  80.     }  
  81.     public function display() {  
  82.         echo "温度:" . $this->temperature . "; 湿度:" . $this->humidity . "%; 气压:" . $this->pressure . "/n";  
  83.     }  
  84. }  
  85. $weatherData = new WeatherData();  
  86. $currentDisplay = new CurrentConditionsDisplay($weatherData);  
  87. $statistionDisplay = new StatistionsDisplay($weatherData);  
  88. $weatherData->setMeasurements(10, 20, 30);  
  89. $weatherData->removeObserver($currentDisplay);  
  90. $weatherData->setMeasurements(30, 40, 50);  
  91. ?>  

 

命令模式

 

[php] view plaincopy

 
  1. <?php  
  2. class Light {  
  3.     public function __construct() {  
  4.     }  
  5.     public function on() {  
  6.         echo "Light On/n";  
  7.     }  
  8.     public function off() {  
  9.         echo "Light Off/n";  
  10.     }  
  11. }  
  12. interface Command {  
  13.     public function execute();  
  14. }  
  15. class LightOnCommand implements Command {  
  16.     public $light;  
  17.     public function __construct(Light $light) {  
  18.         $this->light = $light;  
  19.     }  
  20.     public function execute() {  
  21.         $this->light->on();  
  22.     }  
  23. }  
  24. class SimpleRemoteControl {  
  25.     public $slot;  
  26.     public function __construct() {  
  27.     }  
  28.     public function setCommand(Command $command) {  
  29.         $this->slot = $command;  
  30.     }  
  31.     public function buttonWasPressed() {  
  32.         $this->slot->execute();  
  33.     }  
  34. }  
  35. class RemoteControlTest {  
  36.     public static function main() {  
  37.         $remote = new SimpleRemoteControl();  
  38.         $light = new Light();  
  39.         $lightOn = new LightOnCommand($light);  
  40.         $remote->setCommand($lightOn);  
  41.         $remote->buttonWasPressed();  
  42.     }  
  43. }  
  44. RemoteControlTest::main();  
  45. ?>  

 

 

装饰者模式

 

[php] view plaincopy

 
  1. <?php  
  2. /** 
  3.  * 装饰着模式 
  4.  * 动态地将责任附加到对象上,若要扩展功能,装饰者提供了比继承更有弹性的替代方案。 
  5.  */  
  6. abstract class Beverage {  
  7.     public $description = "Unknown Beverage";  
  8.     public function getDescription() {  
  9.         return $this->description;  
  10.     }  
  11.     public abstract function cost();  
  12. }  
  13. abstract class CondimentDecorator extends Beverage {  
  14.     //JAVA代码里这里是个抽象类,PHP不允许这么做  
  15.     public function getDescription() {  
  16.         return $this->description;  
  17.     }  
  18. }  
  19. class Espresso extends Beverage {  
  20.     public function __construct() {  
  21.         $this->description = "Espresso";  
  22.     }  
  23.     public function cost() {  
  24.         return 1.99;  
  25.     }  
  26. }  
  27. class HouseBlend extends Beverage {  
  28.     public function __construct() {  
  29.         $this->description = "HouseBlend";  
  30.     }  
  31.     public function cost() {  
  32.         return .89;  
  33.     }  
  34. }  
  35. class DarkRoast extends Beverage {  
  36.     public function __construct() {  
  37.         $this->description = "DarkRoast";  
  38.     }  
  39.     public function cost() {  
  40.         return .99;  
  41.     }  
  42. }  
  43. class Mocha extends CondimentDecorator {  
  44.     public $beverage;  
  45.     public function __construct(Beverage $beverage) {  
  46.         $this->beverage = $beverage;  
  47.     }  
  48.     public function getDescription() {  
  49.         return $this->beverage->getDescription() . ", Mocha";  
  50.     }  
  51.     public function cost() {  
  52.         return .20 + $this->beverage->cost();  
  53.     }  
  54. }  
  55. class Whip extends CondimentDecorator {  
  56.     public $beverage;  
  57.     public function __construct(Beverage $beverage) {  
  58.         $this->beverage = $beverage;  
  59.     }  
  60.     public function getDescription() {  
  61.         return $this->beverage->getDescription() . ", Whip";  
  62.     }  
  63.     public function cost() {  
  64.         return .10 + $this->beverage->cost();  
  65.     }  
  66. }  
  67. class Soy extends CondimentDecorator {  
  68.     public $beverage;  
  69.     public function __construct(Beverage $beverage) {  
  70.         $this->beverage = $beverage;  
  71.     }  
  72.     public function getDescription() {  
  73.         return $this->beverage->getDescription() . ", Soy";  
  74.     }  
  75.     public function cost() {  
  76.         return .15 + $this->beverage->cost();  
  77.     }  
  78. }  
  79. $beverage = new Espresso();  
  80. echo $beverage->getDescription() . "/n";  
  81. $beverage2 = new DarkRoast();  
  82. $beverage2 = new Mocha($beverage2);  
  83. $beverage2 = new Mocha($beverage2);  
  84. $beverage2 = new Whip($beverage2);  
  85. echo $beverage2->getDescription() . " $" . $beverage2->cost() . "/n";  
  86. $beverage3 = new HouseBlend();  
  87. $beverage3 = new Soy($beverage3);  
  88. $beverage3 = new Mocha($beverage3);  
  89. $beverage3 = new Whip($beverage3);  
  90. echo $beverage3->getDescription() . " $" . $beverage3->cost() . "/n";  
  91. ?>  

 

状态模式

 

[php] view plaincopy

 
  1. <?php  
  2. class GumballMachine {  
  3.     const SOLD_OUT = 0;  
  4.     const NO_QUARTER = 1;  
  5.     const HAS_QUARTER = 2;  
  6.     const SOLD = 3;  
  7.     public $state = self::SOLD_OUT;  
  8.     public $count = 0;  
  9.     public function __construct($count) {  
  10.         $this->count = $count;  
  11.         if ($count > 0) {  
  12.             $this->state = self::NO_QUARTER;  
  13.         }  
  14.     }  
  15.     public function insertQuarter() {  
  16.         if ($this->state == self::HAS_QUARTER) {  
  17.             echo "You can't insert another quarter!/n";  
  18.         } else if ($this->state == self::NO_QUARTER) {  
  19.             $this->state = self::HAS_QUARTER;  
  20.             echo "You inserted a quarter!/n";  
  21.         } else if ($this->state == self::SOLD_OUT) {  
  22.             echo "You can't insert a quarter, the machine is sold out!/n";  
  23.         } else if ($this->state == self::SOLD) {  
  24.             echo "Please wait, we're already giving you a gumball!/n";  
  25.         }  
  26.     }  
  27. }  
  28. $obj = new GumballMachine(0);  
  29. print_r($obj)  
  30. ?>  

 

86月/120

PHP CURL详解

发布在 邵珠庆



目前为目最全的CURL中文说明了,学PHP的要好好掌握.有很多的参数.大部份都很有用.真正掌握了它和正则,一定就是个采集高手了.

PHP中的CURL函数库(Client URL Library Function)

curl_close — 关闭一个curl会话

curl_copy_handle — 拷贝一个curl连接资源的所有内容和参数

curl_errno — 返回一个包含当前会话错误信息的数字编号

curl_error — 返回一个包含当前会话错误信息的字符串

curl_exec — 执行一个curl会话

curl_getinfo — 获取一个curl连接资源句柄的信息

curl_init — 初始化一个curl会话

curl_multi_add_handle — 向curl批处理会话中添加单独的curl句柄资源

curl_multi_close — 关闭一个批处理句柄资源

curl_multi_exec — 解析一个curl批处理句柄

curl_multi_getcontent — 返回获取的输出的文本流

curl_multi_info_read — 获取当前解析的curl的相关传输信息

curl_multi_init — 初始化一个curl批处理句柄资源

curl_multi_remove_handle — 移除curl批处理句柄资源中的某个句柄资源

curl_multi_select — Get all the sockets associated with the cURL extension, which can then be "selected"

curl_setopt_array — 以数组的形式为一个curl设置会话参数

curl_setopt — 为一个curl设置会话参数

curl_version — 获取curl相关的版本信息

curl_init()函数的作用初始化一个curl会话,curl_init()函数唯一的一个参数是可选的,表示一个url地址。

curl_exec()函数的作用是执行一个curl会话,唯一的参数是curl_init()函数返回的句柄。

curl_close()函数的作用是关闭一个curl会话,唯一的参数是curl_init()函数返回的句柄。

<?php

$ch = curl_init("http://www.baidu.com/");

curl_exec($ch);

curl_close($ch);

?>

curl_version()函数的作用是获取curl相关的版本信息,curl_version()函数有一个参数,不清楚是做什么的

<?php

print_r(curl_version())

?>

curl_getinfo()函数的作用是获取一个curl连接资源句柄的信息,curl_getinfo()函数有两个参数,第一个参数是curl的资源句柄,第二个参数是下面一些常量:

<?php

$ch = curl_init("http://www.baidu.com/");

print_r(curl_getinfo($ch));

?>

可选的常量包括:

CURLINFO_EFFECTIVE_URL

最后一个有效的url地址

CURLINFO_HTTP_CODE

最后一个收到的HTTP代码

CURLINFO_FILETIME

远程获取文档的时间,如果无法获取,则返回值为“-1”

CURLINFO_TOTAL_TIME

最后一次传输所消耗的时间

CURLINFO_NAMELOOKUP_TIME

名称解析所消耗的时间

CURLINFO_CONNECT_TIME

建立连接所消耗的时间

CURLINFO_PRETRANSFER_TIME

从建立连接到准备传输所使用的时间

CURLINFO_STARTTRANSFER_TIME

从建立连接到传输开始所使用的时间

CURLINFO_REDIRECT_TIME

在事务传输开始前重定向所使用的时间

CURLINFO_SIZE_UPLOAD

上传数据量的总值

CURLINFO_SIZE_DOWNLOAD

下载数据量的总值

CURLINFO_SPEED_DOWNLOAD

平均下载速度

CURLINFO_SPEED_UPLOAD

平均上传速度

CURLINFO_HEADER_SIZE

header部分的大小

CURLINFO_HEADER_OUT

发送请求的字符串

CURLINFO_REQUEST_SIZE

在HTTP请求中有问题的请求的大小

CURLINFO_SSL_VERIFYRESULT

Result of SSL certification verification requested by setting CURLOPT_SSL_VERIFYPEER

CURLINFO_CONTENT_LENGTH_DOWNLOAD

从Content-Length: field中读取的下载内容长度

CURLINFO_CONTENT_LENGTH_UPLOAD

上传内容大小的说明

CURLINFO_CONTENT_TYPE

下载内容的“Content-type”值,NULL表示服务器没有发送有效的“Content-Type: header”

curl_setopt()函数的作用是为一个curl设置会话参数。curl_setopt_array()函数的作用是以数组的形式为一个curl设置会话参数。

<?php

$ch = curl_init();

$fp = fopen("example_homepage.txt", "w");

curl_setopt($ch, CURLOPT_FILE, $fp);

$options = array(

 
CURLOPT_URL => 'http://www.baidu.com/',

 
CURLOPT_HEADER => false

 
);

curl_setopt_array($ch, $options);

curl_exec($ch);

curl_close($ch);

fclose($fp);

?>

可设置的参数有:

CURLOPT_AUTOREFERER

自动设置header中的referer信息

CURLOPT_BINARYTRANSFER

在启用CURLOPT_RETURNTRANSFER时候将获取数据返回

CURLOPT_COOKIESESSION

启用时curl会仅仅传递一个session cookie,忽略其他的cookie,默认状况下curl会将所有的cookie返回给服务端。session cookie是指那些用来判断服务器端的session是否有效而存在的cookie。

CURLOPT_CRLF

启用时将Unix的换行符转换成回车换行符。

CURLOPT_DNS_USE_GLOBAL_CACHE

启用时会启用一个全局的DNS缓存,此项为线程安全的,并且默认为true。

CURLOPT_FAILONERROR

显示HTTP状态码,默认行为是忽略编号小于等于400的HTTP信息

CURLOPT_FILETIME

启用时会尝试修改远程文档中的信息。结果信息会通过curl_getinfo()函数的CURLINFO_FILETIME选项返回。

CURLOPT_FOLLOWLOCATION

启用时会将服务器服务器返回的“Location:”放在header中递归的返回给服务器,使用CURLOPT_MAXREDIRS可以限定递归返回的数量。

CURLOPT_FORBID_REUSE

在完成交互以后强迫断开连接,不能重用。

CURLOPT_FRESH_CONNECT

强制获取一个新的连接,替代缓存中的连接。

CURLOPT_FTP_USE_EPRT

TRUE to use EPRT (and LPRT) when doing active FTP downloads. Use FALSE to disable EPRT and LPRT and use PORT only.

Added in PHP 5.0.0.

CURLOPT_FTP_USE_EPSV

TRUE to first try an EPSV command for FTP transfers before reverting back to PASV. Set to FALSE to disable EPSV.

CURLOPT_FTPAPPEND

TRUE to append to the remote file instead of overwriting it.

CURLOPT_FTPASCII

An alias of CURLOPT_TRANSFERTEXT. Use that instead.

CURLOPT_FTPLISTONLY

TRUE to only list the names of an FTP directory.

CURLOPT_HEADER

启用时会将头文件的信息作为数据流输出。

CURLOPT_HTTPGET

启用时会设置HTTP的method为GET,因为GET是默认是,所以只在被修改的情况下使用。

CURLOPT_HTTPPROXYTUNNEL

启用时会通过HTTP代理来传输。

CURLOPT_MUTE

讲curl函数中所有修改过的参数恢复默认值。

CURLOPT_NETRC

在连接建立以后,访问~/.netrc文件获取用户名和密码信息连接远程站点。

CURLOPT_NOBODY

启用时将不对HTML中的body部分进行输出。

CURLOPT_NOPROGRESS

启用时关闭curl传输的进度条,此项的默认设置为true

CURLOPT_NOSIGNAL

启用时忽略所有的curl传递给php进行的信号。在SAPI多线程传输时此项被默认打开。

CURLOPT_POST

启用时会发送一个常规的POST请求,类型为:application/x-www-form-urlencoded,就像表单提交的一样。

CURLOPT_PUT

启用时允许HTTP发送文件,必须同时设置CURLOPT_INFILE和CURLOPT_INFILESIZE

CURLOPT_RETURNTRANSFER

讲curl_exec()获取的信息以文件流的形式返回,而不是直接输出。

CURLOPT_SSL_VERIFYPEER

FALSE to stop cURL from verifying the peer's certificate. Alternate certificates to verify against can be specified with the CURLOPT_CAINFO option or a certificate directory can be specified with the CURLOPT_CAPATH option. CURLOPT_SSL_VERIFYHOST may also need to be TRUE or FALSE if CURLOPT_SSL_VERIFYPEER is disabled (it defaults to 2). TRUE by default as of cURL 7.10. Default bundle installed as of cURL 7.10.

CURLOPT_TRANSFERTEXT

TRUE to use ASCII mode for FTP transfers. For LDAP, it retrieves data in plain text instead of HTML. On Windows systems, it will not set STDOUT to binary mode.

CURLOPT_UNRESTRICTED_AUTH

在使用CURLOPT_FOLLOWLOCATION产生的header中的多个locations中持续追加用户名和密码信息,即使域名已发生改变。

CURLOPT_UPLOAD

启用时允许文件传输

CURLOPT_VERBOSE

启用时会汇报所有的信息,存放在STDERR或指定的CURLOPT_STDERR中

CURLOPT_BUFFERSIZE

每次获取的数据中读入缓存的大小,这个值每次都会被填满。

CURLOPT_CLOSEPOLICY

不是CURLCLOSEPOLICY_LEAST_RECENTLY_USED就是CURLCLOSEPOLICY_OLDEST,还存在另外三个,但是curl暂时还不支持。.

CURLOPT_CONNECTTIMEOUT

在发起连接前等待的时间,如果设置为0,则不等待。

CURLOPT_DNS_CACHE_TIMEOUT

设置在内存中保存DNS信息的时间,默认为120秒。

CURLOPT_FTPSSLAUTH

The FTP authentication method (when is activated): CURLFTPAUTH_SSL (try SSL first), CURLFTPAUTH_TLS (try TLS first), or CURLFTPAUTH_DEFAULT (let cURL decide).

CURLOPT_HTTP_VERSION

设置curl使用的HTTP协议,CURL_HTTP_VERSION_NONE(让curl自己判断),CURL_HTTP_VERSION_1_0(HTTP/1.0),CURL_HTTP_VERSION_1_1(HTTP/1.1)

CURLOPT_HTTPAUTH

使用的HTTP验证方法,可选的值有:CURLAUTH_BASIC,CURLAUTH_DIGEST,CURLAUTH_GSSNEGOTIATE,CURLAUTH_NTLM,CURLAUTH_ANY,CURLAUTH_ANYSAFE,可以使用“|”操作符分隔多个值,curl让服务器选择一个支持最好的值,CURLAUTH_ANY等价于CURLAUTH_BASIC | CURLAUTH_DIGEST | CURLAUTH_GSSNEGOTIATE | CURLAUTH_NTLM,CURLAUTH_ANYSAFE等价于CURLAUTH_DIGEST | CURLAUTH_GSSNEGOTIATE | CURLAUTH_NTLM

CURLOPT_INFILESIZE

设定上传文件的大小

CURLOPT_LOW_SPEED_LIMIT

当传输速度小于CURLOPT_LOW_SPEED_LIMIT时,PHP会根据CURLOPT_LOW_SPEED_TIME来判断是否因太慢而取消传输。

CURLOPT_LOW_SPEED_TIME

The number of seconds the transfer should be below CURLOPT_LOW_SPEED_LIMIT for PHP to consider the transfer too slow and abort.

当传输速度小于CURLOPT_LOW_SPEED_LIMIT时,PHP会根据CURLOPT_LOW_SPEED_TIME来判断是否因太慢而取消传输。

CURLOPT_MAXCONNECTS

允许的最大连接数量,超过是会通过CURLOPT_CLOSEPOLICY决定应该停止哪些连接

CURLOPT_MAXREDIRS

指定最多的HTTP重定向的数量,这个选项是和CURLOPT_FOLLOWLOCATION一起使用的。

CURLOPT_PORT

一个可选的用来指定连接端口的量

CURLOPT_PROXYAUTH

The HTTP authentication method(s) to use for the proxy connection. Use the same bitmasks as described in CURLOPT_HTTPAUTH. For proxy authentication, only CURLAUTH_BASIC and CURLAUTH_NTLM are currently supported.

CURLOPT_PROXYPORT

The port number of the proxy to connect to. This port number can also be set in CURLOPT_PROXY.

CURLOPT_PROXYTYPE

Either CURLPROXY_HTTP (default) or CURLPROXY_SOCKS5.

CURLOPT_RESUME_FROM

在恢复传输时传递一个字节偏移量(用来断点续传)

CURLOPT_SSL_VERIFYHOST

1 to check the existence of a common name in the SSL peer certificate.

2 to check the existence of a common name and also verify that it matches the hostname provided.

CURLOPT_SSLVERSION

The SSL version (2 or 3) to use. By default PHP will try to determine this itself, although in some cases this must be set manually.

CURLOPT_TIMECONDITION

如果在CURLOPT_TIMEVALUE指定的某个时间以后被编辑过,则使用CURL_TIMECOND_IFMODSINCE返回页面,如果没有被修改过,并且CURLOPT_HEADER为true,则返回一个"304 Not Modified"的header,CURLOPT_HEADER为false,则使用CURL_TIMECOND_ISUNMODSINCE,默认值为CURL_TIMECOND_IFMODSINCE

CURLOPT_TIMEOUT

设置curl允许执行的最长秒数

CURLOPT_TIMEVALUE

设置一个CURLOPT_TIMECONDITION使用的时间戳,在默认状态下使用的是CURL_TIMECOND_IFMODSINCE

CURLOPT_CAINFO

The name of a file holding one or more certificates to verify the peer with. This only makes sense when used in combination with CURLOPT_SSL_VERIFYPEER.

CURLOPT_CAPATH

A directory that holds multiple CA certificates. Use this option alongside CURLOPT_SSL_VERIFYPEER.

CURLOPT_COOKIE

设定HTTP请求中“Set-Cookie:”部分的内容。

CURLOPT_COOKIEFILE

包含cookie信息的文件名称,这个cookie文件可以是Netscape格式或者HTTP风格的header信息。

CURLOPT_COOKIEJAR

连接关闭以后,存放cookie信息的文件名称

CURLOPT_CUSTOMREQUEST

A custom request method to use instead of "GET" or "HEAD" when doing a HTTP request. This is useful for doing "DELETE" or other, more obscure HTTP requests. Valid values are things like "GET", "POST", "CONNECT" and so on; i.e. Do not enter a whole HTTP request line here. For instance, entering "GET /index.html HTTP/1.0rnrn" would be incorrect.

Note: Don't do this without making sure the server supports the custom request method first.

CURLOPT_EGBSOCKET

Like CURLOPT_RANDOM_FILE, except a filename to an Entropy Gathering Daemon socket.

CURLOPT_ENCODING

header中“Accept-Encoding: ”部分的内容,支持的编码格式为:"identity","deflate","gzip"。如果设置为空字符串,则表示支持所有的编码格式

CURLOPT_FTPPORT

The value which will be used to get the IP address to use for the FTP "POST" instruction. The "POST" instruction tells the remote server to connect to our specified IP address. The string may be a plain IP address, a hostname, a network interface name (under Unix), or just a plain '-' to use the systems default IP address.

CURLOPT_INTERFACE

在外部网络接口中使用的名称,可以是一个接口名,IP或者主机名。

CURLOPT_KRB4LEVEL

KRB4(Kerberos 4)安全级别的设置,可以是一下几个值之一:"clear","safe","confidential","private"。默认的值为"private",设置为null的时候表示禁用KRB4,现在KRB4安全仅能在FTP传输中使用。

CURLOPT_POSTFIELDS

在HTTP中的“POST”操作。如果要传送一个文件,需要一个@开头的文件名

CURLOPT_PROXY

设置通过的HTTP代理服务器

CURLOPT_PROXYUSERPWD

连接到代理服务器的,格式为“[username]:[password]”的用户名和密码。

CURLOPT_RANDOM_FILE

设定存放SSL用到的随机数种子的文件名称

CURLOPT_RANGE

设置HTTP传输范围,可以用“X-Y”的形式设置一个传输区间,如果有多个HTTP传输,则使用逗号分隔多个值,形如:"X-Y,N-M"。

CURLOPT_REFERER

设置header中"Referer: " 部分的值。

CURLOPT_SSL_CIPHER_LIST

A list of ciphers to use for SSL. For example, RC4-SHA and TLSv1 are valid cipher lists.

CURLOPT_SSLCERT

传递一个包含PEM格式证书的字符串。

CURLOPT_SSLCERTPASSWD

传递一个包含使用CURLOPT_SSLCERT证书必需的密码。

CURLOPT_SSLCERTTYPE

The format of the certificate. Supported formats are "PEM" (default), "DER", and "ENG".

CURLOPT_SSLENGINE

The identifier for the crypto engine of the private SSL key specified in CURLOPT_SSLKEY.

CURLOPT_SSLENGINE_DEFAULT

The identifier for the crypto engine used for asymmetric crypto operations.

CURLOPT_SSLKEY

The name of a file containing a private SSL key.

CURLOPT_SSLKEYPASSWD

The secret password needed to use the private SSL key specified in CURLOPT_SSLKEY.

Note: Since this option contains a sensitive password, remember to keep the PHP script it is contained within safe.

CURLOPT_SSLKEYTYPE

The key type of the private SSL key specified in CURLOPT_SSLKEY. Supported key types are "PEM" (default), "DER", and "ENG".

CURLOPT_URL

需要获取的URL地址,也可以在PHP的curl_init()函数中设置。

CURLOPT_USERAGENT

在HTTP请求中包含一个”user-agent”头的字符串。

CURLOPT_USERPWD

传递一个连接中需要的用户名和密码,格式为:“[username]:[password]”。

CURLOPT_HTTP200ALIASES

设置不再以error的形式来处理HTTP 200的响应,格式为一个数组。

CURLOPT_HTTPHEADER

设置一个header中传输内容的数组。

CURLOPT_POSTQUOTE

An array of FTP commands to execute on the server after the FTP request has been performed.

CURLOPT_QUOTE

An array of FTP commands to execute on the server prior to the FTP request.

CURLOPT_FILE

设置输出文件的位置,值是一个资源类型,默认为STDOUT (浏览器)。

CURLOPT_INFILE

在上传文件的时候需要读取的文件地址,值是一个资源类型。

CURLOPT_STDERR

设置一个错误输出地址,值是一个资源类型,取代默认的STDERR。

CURLOPT_WRITEHEADER

设置header部分内容的写入的文件地址,值是一个资源类型。

CURLOPT_HEADERFUNCTION

设置一个回调函数,这个函数有两个参数,第一个是curl的资源句柄,第二个是输出的header数据。header数据的输出必须依赖这个函数,返回已写入的数据大小。

CURLOPT_PASSWDFUNCTION

设置一个回调函数,有三个参数,第一个是curl的资源句柄,第二个是一个密码提示符,第三个参数是密码长度允许的最大值。返回密码的值。

CURLOPT_READFUNCTION

设置一个回调函数,有两个参数,第一个是curl的资源句柄,第二个是读取到的数据。数据读取必须依赖这个函数。返回读取数据的大小,比如0或者EOF。

CURLOPT_WRITEFUNCTION

设置一个回调函数,有两个参数,第一个是curl的资源句柄,第二个是写入的数据。数据写入必须依赖这个函数。返回精确的已写入数据的大小

curl_copy_handle()函数的作用是拷贝一个curl连接资源的所有内容和参数

<?php

$ch = curl_init("http://www.baidu.com/");

$another = curl_copy_handle($ch);

curl_exec($another);

curl_close($another);

?>

curl_error()函数的作用是返回一个包含当前会话错误信息的字符串。

curl_errno()函数的作用是返回一个包含当前会话错误信息的数字编号。

curl_multi_init()函数的作用是初始化一个curl批处理句柄资源。

curl_multi_add_handle()函数的作用是向curl批处理会话中添加单独的curl句柄资源。curl_multi_add_handle()函数有两个参数,第一个参数表示一个curl批处理句柄资源,第二个参数表示一个单独的curl句柄资源。

curl_multi_exec()函数的作用是解析一个curl批处理句柄,curl_multi_exec()函数有两个参数,第一个参数表示一个批处理句柄资源,第二个参数是一个引用值的参数,表示剩余需要处理的单个的curl句柄资源数量。

curl_multi_remove_handle()函数表示移除curl批处理句柄资源中的某个句柄资源,curl_multi_remove_handle()函数有两个参数,第一个参数表示一个curl批处理句柄资源,第二个参数表示一个单独的curl句柄资源。

curl_multi_close()函数的作用是关闭一个批处理句柄资源。

<?php

$ch1 = curl_init();

$ch2 = curl_init();

curl_setopt($ch1, CURLOPT_URL, "http://www.baidu.com/");

curl_setopt($ch1, CURLOPT_HEADER, 0);

curl_setopt($ch2, CURLOPT_URL, "http://www.google.com/");

curl_setopt($ch2, CURLOPT_HEADER, 0);

$mh = curl_multi_init();

curl_multi_add_handle($mh,$ch1);

curl_multi_add_handle($mh,$ch2);

do {

 
curl_multi_exec($mh,$flag);

} while ($flag > 0);

curl_multi_remove_handle($mh,$ch1);

curl_multi_remove_handle($mh,$ch2);

curl_multi_close($mh);

?>

curl_multi_getcontent()函数的作用是在设置了CURLOPT_RETURNTRANSFER的情况下,返回获取的输出的文本流。

curl_multi_info_read()函数的作用是获取当前解析的curl的相关传输信息。

curl_multi_select()

Get all the sockets associated with the cURL extension, which can then be "selected"

143月/120

PHP特性小结

发布在 邵珠庆