[数据为王]日请求过亿:QQ会员活动平台PHP7升级实践
Php/Js/Shell/Go jackxiang 2016-6-1 12:15
背景:我都之前说php7对wordpress提升不大,没有一个兄弟支持我,都说提升大,你看这文章,qq会员那边的一个实践更多证实了我的观点。
......
在benchmark(测试程序)中得到非常好的结果,实现JIT后性能比PHP5.5提升了8倍。然而,当他们把这个优化放入到实际的项目WordPress(一个开源博客项目)中,却几乎看不见性能的提升。原因在于测试项目的代码量比较少,通过JIT产生的机器码也不大,而真实的WordPress项目生成的机器码太大,引起CPU缓存命中率下降(CPU Cache Miss)。
......
对apache的工作模式分析很透彻:
Prefork、Worker、Event三者粗略介绍:
(1)prefork,多进程模式,1个进程服务于1个用户请求,成本比较高。但是,稳定性最高,不需要支持线程安全。
(2)worker,多进程多线程模式,1个进程含有多个worker线程,1个worker线程服务于1个用户请求,因为线程更轻量,成本比较低。但是,在KeepAlive场景下,worker资源会被client占据,无法响应其他请求(空等待)。
(3)event,多进程多线程模式,1个进程也含有多个worker线程,1个worker线程服务于1个用户请求。但是,它解决了KeepAlive场景下的worker线程被占据问题,它通过专门的线程来管理这些KeepAlive连接,然后再分配“工作”给具体处理的worker,工作worker不会因为KeepAlive而导致空等待。
博文摘自 : http://geek.csdn.net/news/detail/77849
......
在benchmark(测试程序)中得到非常好的结果,实现JIT后性能比PHP5.5提升了8倍。然而,当他们把这个优化放入到实际的项目WordPress(一个开源博客项目)中,却几乎看不见性能的提升。原因在于测试项目的代码量比较少,通过JIT产生的机器码也不大,而真实的WordPress项目生成的机器码太大,引起CPU缓存命中率下降(CPU Cache Miss)。
......
对apache的工作模式分析很透彻:
Prefork、Worker、Event三者粗略介绍:
(1)prefork,多进程模式,1个进程服务于1个用户请求,成本比较高。但是,稳定性最高,不需要支持线程安全。
(2)worker,多进程多线程模式,1个进程含有多个worker线程,1个worker线程服务于1个用户请求,因为线程更轻量,成本比较低。但是,在KeepAlive场景下,worker资源会被client占据,无法响应其他请求(空等待)。
(3)event,多进程多线程模式,1个进程也含有多个worker线程,1个worker线程服务于1个用户请求。但是,它解决了KeepAlive场景下的worker线程被占据问题,它通过专门的线程来管理这些KeepAlive连接,然后再分配“工作”给具体处理的worker,工作worker不会因为KeepAlive而导致空等待。
博文摘自 : http://geek.csdn.net/news/detail/77849
ERR_CACHE_MISS 搜尋回上一頁空白或錯誤
Php/Js/Shell/Go jackxiang 2016-5-5 11:20
问题:
确认重新提交表单
此网页需要使用您之前输入的数据才能正常显示。您可以重新发送这些数据,不过,这么做会重复执行此网页之前执行过的所有操作。
按“重新加载”按钮,重新提交加载该网页所需的数据。
ERR_CACHE_MISS
————————————————————————————————————————————————————————————————
瀏覽很多網站後都會發生一個小問題,那就是瀏覽搜尋結果,當我點近物件後,再使用瀏覽器的回上一頁功能,就會出現空白頁面,並出現錯誤,以chrome為例,如下:
這個網頁需要使用您先前輸入的資料才能正確顯示。您可以重新傳送這些資料,不過這麼做會重複執行這個網頁先前執行過的任何動作。
重新載入這個網頁。
按下重新載入按鈕,重新提交載入網頁所需的資料。
錯誤代碼:ERR_CACHE_MISS
這通常是搜尋頁面為a.php把搜尋的結果置入b.php,當我們把搜尋結果點進去看物件的時候,就是c.php畫面,所以一般來說瀏覽器回上一頁就是進入b.php,但是問題是b.php並沒有任何值的載入,所以就會發生空白頁面與錯誤代碼:ERR_CACHE_MISS的問題,解決的方式很簡單,就是在a.php放入下一段
如此,輕鬆解決問題,當然還有人會把傳輸的值把它存成cookie/session,這也都是解決辦法喔!
来自:http://blog.csdn.net/a9925/article/details/42027229
确认重新提交表单
此网页需要使用您之前输入的数据才能正常显示。您可以重新发送这些数据,不过,这么做会重复执行此网页之前执行过的所有操作。
按“重新加载”按钮,重新提交加载该网页所需的数据。
ERR_CACHE_MISS
————————————————————————————————————————————————————————————————
瀏覽很多網站後都會發生一個小問題,那就是瀏覽搜尋結果,當我點近物件後,再使用瀏覽器的回上一頁功能,就會出現空白頁面,並出現錯誤,以chrome為例,如下:
這個網頁需要使用您先前輸入的資料才能正確顯示。您可以重新傳送這些資料,不過這麼做會重複執行這個網頁先前執行過的任何動作。
重新載入這個網頁。
按下重新載入按鈕,重新提交載入網頁所需的資料。
錯誤代碼:ERR_CACHE_MISS
這通常是搜尋頁面為a.php把搜尋的結果置入b.php,當我們把搜尋結果點進去看物件的時候,就是c.php畫面,所以一般來說瀏覽器回上一頁就是進入b.php,但是問題是b.php並沒有任何值的載入,所以就會發生空白頁面與錯誤代碼:ERR_CACHE_MISS的問題,解決的方式很簡單,就是在a.php放入下一段
如此,輕鬆解決問題,當然還有人會把傳輸的值把它存成cookie/session,這也都是解決辦法喔!
来自:http://blog.csdn.net/a9925/article/details/42027229
务实至上:“PHP之父”Rasmus Lerdorf访谈录
Php/Js/Shell/Go jackxiang 2016-5-5 11:17
“PHP之父”Rasmus Lerdorf性格直接坦荡,措辞简练精辟,字里行间透着一股“务实至上”的精神气。在参加“PHP全球开发者大会”前夕,这位“实干家”接受了《程序员》采访,分享了自己的编程感悟。
工作重心
我参与的项目总与用户直接相关。我曾多年担任雅虎工程师,负责连接数亿终端用户的基础设施,这些基础设置仍在服役。而如今,我在Etsy也是负责连接百万用户的后端基础设施。技术其实只是解决问题的工具,是抽象的锤头、锯子,并没什么了不起,而真正振奋人心的是用技术提升了百万人的生活品质。
“问题”为指引
比起“计算机科学家”,“工程师”的称谓更得我心。论这两者的区别,我认为后者更专注于解决眼前的问题。之所以开发PHP,并非因为我喜爱编程或语言设计,反倒是因为不喜欢。1993年的那套编程把式,让我没法轻松迅捷地解决Web问题。于我而言,只有当遇到困难,才会翻翻书,查查资料来充实自己,技能不是为了提高而提高,我的每一个决定都是以解决问题为中心的。
经验与教训
我犯了很多错,有些事后才意识到;但也取得过好于预期的成果。最重要的经验是:解决Web问题的确应该从一开始就专注相关的整个生态系统。20年来,针对Web问题的解决方案层出不穷,而质量却参差不齐,没几个能构建起完整的生态圈,并为普通人所用。
PHP 7何处费思量?
开发PHP 7那最后10%最费时,也最无趣。不过强大的新功能和性能突飞猛进,还是让积极心态占了上风,也激励了整个团队,帮我们很快熬了过去。不过,每次更新都有做不完的测试、解决不完的平台问题,调查不完的诡异边缘情况,看不完的漏洞报告,没个尽头。
吸纳新人
我知道前不久Emacs的版本控制系统从BZR换成了Git,不过对于吸纳新贡献者,我觉得它们其实平分秋色。Git近来更受欢迎,方便蜻蜓点水式的添砖加瓦。不过对于长期的忠实贡献者,版本控制系统无关紧要。良好的文档和方便新贡献的流程才重要呢。
假如能重新设计PHP
假如时光能倒流,肯定有我希望能改进的地方,比如区分Keyword大小写。刚开始PHP不过是种HTML模板语言。九十年代初,人们争论HTML标签是该大写、小写还是大小写混合。我不想争来争去的,就把PHP的模版标签做成不区分大小写的,这个做法至今还在沿用。
JavaScript在吞噬其他语言吗?
PHP和JavaScript的演进几乎同步。我与Brendan Eich(JavaScript设计者)是同一时期开始的,他的重心显而易见是客户端,而我则是服务器。如果你写客户端应用,除了JavaScript,别无选择——浏览器支持哪种语言就得用哪种;但如果重心是服务器就很不一样了。
写客户端代码者众,所以会JavaScript的人多,而如今它在服务器这厢也开花结果了。但JavaScript跟PHP一样只是解决方案之一,而非唯一,这样挺好。就像我刚说的,语言只是解决问题的工具,不是受人膜拜的宗教。如果眼前有问题,而你更倾向于JavaScript,那么它就是最佳选择。
编程原则
只要有效、安全、够快,就发布,然后解决下个问题。三者缺一不可,否则就要回头检查代码,好抓紧时间解决下一个问题。
未来展望
关于编程语言,我还真没想过这些工具未来会经历什么,我更关心的是它们能否解决当下的问题。拿Etsy举例,作为手工工艺品网站,它能在富有的买家和穷苦艺术家之间牵线搭桥,让他们摆脱贫穷的窘境吗?我们的基础设施能帮助其他公司去应对同等重大的问题吗?我们的解决方案是否强大到一转眼客户的问题就去无踪了呢?这些才是我关心的。
过去,我不喜欢编程,现在还是不咋喜欢。我只喜欢以解决问题为中心,这点永远不变。
工作重心
我参与的项目总与用户直接相关。我曾多年担任雅虎工程师,负责连接数亿终端用户的基础设施,这些基础设置仍在服役。而如今,我在Etsy也是负责连接百万用户的后端基础设施。技术其实只是解决问题的工具,是抽象的锤头、锯子,并没什么了不起,而真正振奋人心的是用技术提升了百万人的生活品质。
“问题”为指引
比起“计算机科学家”,“工程师”的称谓更得我心。论这两者的区别,我认为后者更专注于解决眼前的问题。之所以开发PHP,并非因为我喜爱编程或语言设计,反倒是因为不喜欢。1993年的那套编程把式,让我没法轻松迅捷地解决Web问题。于我而言,只有当遇到困难,才会翻翻书,查查资料来充实自己,技能不是为了提高而提高,我的每一个决定都是以解决问题为中心的。
经验与教训
我犯了很多错,有些事后才意识到;但也取得过好于预期的成果。最重要的经验是:解决Web问题的确应该从一开始就专注相关的整个生态系统。20年来,针对Web问题的解决方案层出不穷,而质量却参差不齐,没几个能构建起完整的生态圈,并为普通人所用。
PHP 7何处费思量?
开发PHP 7那最后10%最费时,也最无趣。不过强大的新功能和性能突飞猛进,还是让积极心态占了上风,也激励了整个团队,帮我们很快熬了过去。不过,每次更新都有做不完的测试、解决不完的平台问题,调查不完的诡异边缘情况,看不完的漏洞报告,没个尽头。
吸纳新人
我知道前不久Emacs的版本控制系统从BZR换成了Git,不过对于吸纳新贡献者,我觉得它们其实平分秋色。Git近来更受欢迎,方便蜻蜓点水式的添砖加瓦。不过对于长期的忠实贡献者,版本控制系统无关紧要。良好的文档和方便新贡献的流程才重要呢。
假如能重新设计PHP
假如时光能倒流,肯定有我希望能改进的地方,比如区分Keyword大小写。刚开始PHP不过是种HTML模板语言。九十年代初,人们争论HTML标签是该大写、小写还是大小写混合。我不想争来争去的,就把PHP的模版标签做成不区分大小写的,这个做法至今还在沿用。
JavaScript在吞噬其他语言吗?
PHP和JavaScript的演进几乎同步。我与Brendan Eich(JavaScript设计者)是同一时期开始的,他的重心显而易见是客户端,而我则是服务器。如果你写客户端应用,除了JavaScript,别无选择——浏览器支持哪种语言就得用哪种;但如果重心是服务器就很不一样了。
写客户端代码者众,所以会JavaScript的人多,而如今它在服务器这厢也开花结果了。但JavaScript跟PHP一样只是解决方案之一,而非唯一,这样挺好。就像我刚说的,语言只是解决问题的工具,不是受人膜拜的宗教。如果眼前有问题,而你更倾向于JavaScript,那么它就是最佳选择。
编程原则
只要有效、安全、够快,就发布,然后解决下个问题。三者缺一不可,否则就要回头检查代码,好抓紧时间解决下一个问题。
未来展望
关于编程语言,我还真没想过这些工具未来会经历什么,我更关心的是它们能否解决当下的问题。拿Etsy举例,作为手工工艺品网站,它能在富有的买家和穷苦艺术家之间牵线搭桥,让他们摆脱贫穷的窘境吗?我们的基础设施能帮助其他公司去应对同等重大的问题吗?我们的解决方案是否强大到一转眼客户的问题就去无踪了呢?这些才是我关心的。
过去,我不喜欢编程,现在还是不咋喜欢。我只喜欢以解决问题为中心,这点永远不变。
关于异步任务队列之PHP使用swoole来实现实时异步任务队列。
Php/Js/Shell/Go jackxiang 2016-4-27 09:50
背景:关于PHP的异步回调啥的,其实PHP这种语言的运行机制想优雅实现是不可能的,有一个叫swoole的扩展实现这个队列的处理是很不错的,之前有张宴兄弟写过一个叫https的队列处理(基于libevent),后面有韩天峰兄弟写的swoole,更注重了异步IO实现对CPU的IO的吃满(基于自己编写的epoll加队列链表内存分配一堆东西,反正我是看过没看明白有空再研究),但是,作为swoole的粉丝兼顾问,异步问题在PHP业界的一个需求量还是蛮大的,尤其是日志异步写、url访问、邮件异步发、跨机房db特殊的小同步、审核异步队列、框架底层对接口访问排查错误的db和cache接口查询及返回,这些目前对于大并发网站都是需要异步来解决的,但是异步归异步,回调这块也实现异步回调(真大并发想知道结果可能阻塞了PHP进程产生进程等待异步返回而新来的连接没法及时处理的php-fpm进程性雪崩),在实际运用中常规处理办法是开一个新的端口,下面的swoole也是开了新的端口来处理,于httpsqs不同在于swoole可以把简单的curl啥的逻辑也可封装里面,在httpsqs里只是纯队列,一个投递进来,再起一个php的daemon进行读取队列,因为如果真是繁忙,导致异步处理返回慢,这个等待也是太漫长,我觉得看具体业务而看要不要等待,在实际中异步和队列大都用于抛数据以及解耦,swoole在这块不光有了异步还有异步回调,所以,最大限度的解决了上面这些场景,先抄一篇文章再说,有空再研究研究其实现,假如能看懂的话:-),异步回调这块如果有明白的可以留言给我,谢谢。
————————————————————————————————————————————————————————————————————————
关于异步任务队列
用户打开了我们的网站。他要做的就是勾选需要发邮件的代理商列表,然后把结算邮件发出去。
假如我们需要发1封邮件,我们写个函数执行即可。考虑到网络可能会稍微有点延迟,但是是可以接受的,用户会乖乖等你的网页发完邮件了再关闭网页。
假如我们要发布10封邮件,用一个for循环,循环10遍执行发邮件操作。这时候,也许10倍的网络延迟会让用户稍微有点不耐烦,但勉强可以等吧。
假如要发100封邮件,for循环100遍,用户直接揭竿而起,什么破网站!
但实际上,我们很可能有超过1万的邮件。怎么处理这个延迟的问题?
答案就是用异步。把“发邮件”这个操作封装,然后后台异步地执行1万遍。这样的话,用户提交网页后,他所等待的时间只是“把发邮件任务请求推送进队列里”的时间。而我们的后台服务将在用户看不见的地方跑。
在实现“异步队列”这点上,有人采用mysql表或者redis来存放待发送的邮件,然后,每分钟定时读取待发送列表,然后处理。这便是定时异步任务队列。但当前提交的任务要一分钟后才能执行,在某些实时性要求应用场景里还是不快。有些场景要求,只有一提交任务,便马上执行,但用户不需要等待返回结果。
在云平台SAE和BAE上,都有taskqueue服务来解决上面的问题。而如果是自己假设服务器,则如何解决?本文将探讨用php扩展swoole实现实时异步任务队列的方案。
安装swoole
pecl 安装:
pecl install swoole
看命令行提示,如果它提示说没有写php.ini,则自己手动在PHP.ini后面加上:
extension = "swoole.so"
服务端
在打算放置脚本的目录(你也可以自行新建)新建Server.php,代码如下:
由于服务端是异步、常驻内存的,因此必须通过命令行来启动。在命令行执行以上代码以启动服务
php Server.php
执行完毕后关闭命令行窗口即可。服务会在后台以守护进程运行
客户端
启动服务后,让我们看看如何调用服务。新建测试文件Client_test.php
代码如下:
在上面代码中,url即为任务所在地址,param为所需传递参数。
保存好代码,在命令行或者浏览器中执行Client_test.php,便实现了异步任务队列。你所填写的URL,将会在每次异步任务被提交后,以HTTP GET的方式异步执行。
查看与关闭
swoole好像没有很便捷的关闭方式。所以只能直接通过关闭进程来关闭。
查看命令:
ps -ef | grep php
结束单个进程:
kill -9 {进程号}
结束所有进程的命令:
killall -9 php
摘自第七星尘的博客:http://blog.star7th.com/2016/01/1905.html
————————————————————————————————————————————————————————————————————————
关于异步任务队列
用户打开了我们的网站。他要做的就是勾选需要发邮件的代理商列表,然后把结算邮件发出去。
假如我们需要发1封邮件,我们写个函数执行即可。考虑到网络可能会稍微有点延迟,但是是可以接受的,用户会乖乖等你的网页发完邮件了再关闭网页。
假如我们要发布10封邮件,用一个for循环,循环10遍执行发邮件操作。这时候,也许10倍的网络延迟会让用户稍微有点不耐烦,但勉强可以等吧。
假如要发100封邮件,for循环100遍,用户直接揭竿而起,什么破网站!
但实际上,我们很可能有超过1万的邮件。怎么处理这个延迟的问题?
答案就是用异步。把“发邮件”这个操作封装,然后后台异步地执行1万遍。这样的话,用户提交网页后,他所等待的时间只是“把发邮件任务请求推送进队列里”的时间。而我们的后台服务将在用户看不见的地方跑。
在实现“异步队列”这点上,有人采用mysql表或者redis来存放待发送的邮件,然后,每分钟定时读取待发送列表,然后处理。这便是定时异步任务队列。但当前提交的任务要一分钟后才能执行,在某些实时性要求应用场景里还是不快。有些场景要求,只有一提交任务,便马上执行,但用户不需要等待返回结果。
在云平台SAE和BAE上,都有taskqueue服务来解决上面的问题。而如果是自己假设服务器,则如何解决?本文将探讨用php扩展swoole实现实时异步任务队列的方案。
安装swoole
pecl 安装:
pecl install swoole
看命令行提示,如果它提示说没有写php.ini,则自己手动在PHP.ini后面加上:
extension = "swoole.so"
服务端
在打算放置脚本的目录(你也可以自行新建)新建Server.php,代码如下:
由于服务端是异步、常驻内存的,因此必须通过命令行来启动。在命令行执行以上代码以启动服务
php Server.php
执行完毕后关闭命令行窗口即可。服务会在后台以守护进程运行
客户端
启动服务后,让我们看看如何调用服务。新建测试文件Client_test.php
代码如下:
在上面代码中,url即为任务所在地址,param为所需传递参数。
保存好代码,在命令行或者浏览器中执行Client_test.php,便实现了异步任务队列。你所填写的URL,将会在每次异步任务被提交后,以HTTP GET的方式异步执行。
查看与关闭
swoole好像没有很便捷的关闭方式。所以只能直接通过关闭进程来关闭。
查看命令:
ps -ef | grep php
结束单个进程:
kill -9 {进程号}
结束所有进程的命令:
killall -9 php
摘自第七星尘的博客:http://blog.star7th.com/2016/01/1905.html
Zephir--最简单的php扩展开发工具
Php/Js/Shell/Go jackxiang 2016-4-18 14:32
背景:写PHP扩展很麻烦,有用c写也有用c++写都麻烦,且难调错,有没有没一个框架实现,从框架看也就是输入和输出,以字符串char*传入,json输出,就很简单了,这儿介绍一个:Zephir提供了一种类似php的高级语言语法的方式,来自动生成扩展的c语言代码,使编写php扩展变得非常的简单。
阅读全文
阅读全文
shell脚本执行返回的状态码,shell返回值环境变量之shell将其返回值赋值给$?环境变量,以及在Mysql备份导出mysqldump中的使用示例。
Php/Js/Shell/Go jackxiang 2016-4-11 16:25
背景:shell在执行一些程序时,其返回值影响后面用&&或||来进行判断,特别是以rpmbuild来举例说明,其在post和postun用到一些删除某些服务啥的,出现返回值不是1,导致rpm -e xxx,出现错误,卸载报错 /var/tmp/rpm-tmp.ELL6uY: line 3: /sbin/chkconfig: No such file or directory,这些都是和这个shell返回值有很大关系的。
返回值,失败示例,返回1值:
shell执行成功示例,返回0值:
二、在Mysql备份导出mysqldump中的使用示例:
=========================================================
每个命令都有一个返回值(返回状态或者退出状态)。命令执行成功的返回值总是0(零值),执行失败的命令,返回一个非0值(错误码)。错误码必须是一个1到255之间的整数。
在编写脚本时,另一个很有用的命令是exit。这个命令被用来终止当前的执行,并把返回值交给shell。当exit不带任何参数时,它会终止当前脚本的执行并返回在它之前最后一个执行的命令的返回值。
一个程序运行结束后,shell将其返回值赋值给$?环境变量。因此$?变量通常被用来检测一个脚本执行成功与否。
与使用exit来结束一个脚本的执行类似,我们可以使用return命令来结束一个函数的执行并将返回值返回给调用者。当然,也可以在函数内部用exit,这 不但 会中止函数的继续执行,而且 会终止整个程序的执行。
摘自:https://github.com/liushuaikobe/bash-handbook-zh-CN#%E4%BA%A4%E4%BA%92%E6%A8%A1%E5%BC%8F
Linux下一条命令或一个进程执行完成会返回一个一个状态码。
0 === 成功执行
非0 === 执行过程中出现异常或非正常退出
在Shell脚本中 最后执行的一条命令将决定整个shell脚本的状态. 此外 shell的内部命令exit也可以随时终止shell脚本的执行,返回Shell脚本的状态码
当shell脚本执行结束前 的最后一个命令是不带参数的exit ,那么 shell脚本的最终返回值 就是 exit 语句前一条语句的返回值,根据这个值可以判断脚本成功执行与否。
$? 可以查看 最后一条命令的返回值 该变量可以在shell 脚本中的任何地方使用.
来自:http://www.cnblogs.com/MyEyes/archive/2012/01/12/2320529.html
返回值,失败示例,返回1值:
shell执行成功示例,返回0值:
二、在Mysql备份导出mysqldump中的使用示例:
=========================================================
每个命令都有一个返回值(返回状态或者退出状态)。命令执行成功的返回值总是0(零值),执行失败的命令,返回一个非0值(错误码)。错误码必须是一个1到255之间的整数。
在编写脚本时,另一个很有用的命令是exit。这个命令被用来终止当前的执行,并把返回值交给shell。当exit不带任何参数时,它会终止当前脚本的执行并返回在它之前最后一个执行的命令的返回值。
一个程序运行结束后,shell将其返回值赋值给$?环境变量。因此$?变量通常被用来检测一个脚本执行成功与否。
与使用exit来结束一个脚本的执行类似,我们可以使用return命令来结束一个函数的执行并将返回值返回给调用者。当然,也可以在函数内部用exit,这 不但 会中止函数的继续执行,而且 会终止整个程序的执行。
摘自:https://github.com/liushuaikobe/bash-handbook-zh-CN#%E4%BA%A4%E4%BA%92%E6%A8%A1%E5%BC%8F
Linux下一条命令或一个进程执行完成会返回一个一个状态码。
0 === 成功执行
非0 === 执行过程中出现异常或非正常退出
在Shell脚本中 最后执行的一条命令将决定整个shell脚本的状态. 此外 shell的内部命令exit也可以随时终止shell脚本的执行,返回Shell脚本的状态码
当shell脚本执行结束前 的最后一个命令是不带参数的exit ,那么 shell脚本的最终返回值 就是 exit 语句前一条语句的返回值,根据这个值可以判断脚本成功执行与否。
$? 可以查看 最后一条命令的返回值 该变量可以在shell 脚本中的任何地方使用.
来自:http://www.cnblogs.com/MyEyes/archive/2012/01/12/2320529.html
一个高级PHP工程师所应该具备的
Php/Js/Shell/Go jackxiang 2016-4-2 18:26
初次接触PHP,就为他的美所折服,于是一发不可收拾。
很多面试,很多人员能力要求都有“PHP高级工程师的字眼”,如果您真心喜欢PHP,并且您刚起步,那么我简单说说一个PHP高级工程师所应该具备的,希望给初级或已经达到中级的PHP工程师一些帮助。
一、平静的心态
和所有程序员一样,要写一手好的程序,没有好的心态是不行的。
遇事不可急躁,不可轻言放弃。
在程序开发过程中,尤其是初中级程序员,写出的程序或架构会遇到很多问题,其中一些问题比较弱智,而有些问题根本没有碰到过,于是不可太过急躁,应该逐个排查问题的最初源泉,将其干掉。急躁的心态去开发系统是对项目的一种不负责。急躁会让人学会将就,让人学会逃避。而我个人北京两年的简单生活,给我其中一个最大的历练也就是:我的心态更加平静了。
相信,这样的心态也会有助于你其他方面的处事能力。
为什么将心态列入其中,我是想说明:他不同于销售的职能,需要很大激情澎湃,而是需要静静的思考。
二、一套烂熟于心的问题解决思路
曾经有位程序开发的同事在QQ签名中写到:每解决一个bug,就给自己一个提升。的确,没有真正解决过无数的bug或问题的程序员,谈不上专家,谈不上高级程序员。而一个高级程序员正是从这种解决问题的过程中不断的历练自己,形成一套烂熟于心的问题解决思路,要自己强大的。
我也简单说说PHP程序员成长过程中经常遇到的一些问题,如果你一个也没遇到或很少遇到,那么您就是两个极端的人:要么初级入门,要么高级了,哈哈。
1,编码问题
2,PHP和SQL数据库执行效率问题
3,Session和Cookie域和加密解析问题
4,程序的执行顺序问题
5,程序编写的多环境适用问题
6,分类的构建和结构设计问题
7,字符串处理问题:正则表达式处理或简单PHP字符串处理函数来处理
8,各种模板引擎的编写局限性问题
9,PHP和web端数据交互问题(如ajax,接口调用等)
三、过硬的PHP基础知识
没有过硬的PHP基础知识,哪怕心态再好,问题解决的能力再强,也只能纸上谈兵。
过硬的基础知识会让你在项目开发过程中游刃有余。
我也简单说说哪些属于PHP工程师所应具备的基础知识(其实这些在招聘需求中很常见):
1,语法规则,这个不说了,这个不会,就没入门,赶紧买本书或找个网站补补
2,MYSQL各种sql语句的写法,增删改查基本的不说了,in,union,left,left join,as,replace,alter table,where的字段排序,各种索引建立的方法要特别熟悉
3,会自己搭建LAMP环境和WAMP环境,用集成软件一键式安装的不算。开发程序,对于自己开发的环境构建结构都不清楚,怎么排查问题?所以至少要会用对立的msi文件来安装自己需要的开发环境。安装3-5遍成功,这个算还行,还得会安装各种扩展,配置apache服务,知道各种参数设置的地方以及知道怎么设置各种参数;会linux操作系统的基本命令。
4,熟悉web方面的其他程序,因为PHP不是一个完全独立的东西,他是一个和其他语言和要素配合来完成一个项目的,如果对其他语言和要素不太熟悉,在团队协作过程中会非常吃力。这些其他要素包括:html,javascript,jquery,xml,http协议,正则表达式等
四、综合的互联网应用及项目管理知识和素养
1,见识广博,擅于学习
只顾自己专研,不看看、学学人家的做法,会像井底之蛙,难以看到广阔的天空的;所以,不要只顾着天天编程,学会抽点时间去看看一些大型开源系统的架构思路,以及大型商务网站的构建方式。向他们学习,补充自己的不足。
比如至少该晓得不同类型的开源系统有哪些吧,比如Uchome,dede,phpcms,wordpress,discuz,帝国等等
看多了,你也会总结发现一些常规性的思路,比如缓存的机制,比如模板机制,比如静态页面生成等等。
2,项目解决方案选型
不同需求,用不同的机构和选型。也就是常说的“水来土掩,兵来将挡”,有些架构固然强大,但是用于小型项目也会很吃力,就是杀机不用牛刀。根据需求来选型很重要。
选型不是随口就能定的,需要一个PHP程序员用于良好的储备,个人觉得至少需要以下储备,才具备选型能力:
熟练应用至少一个PHP框架,两-三个PHP开源系统;拥有自己的一套应用系统。
3,良好的项目管理素养
项目不是一直开发过程中,项目也会进入运营期,维护期,这样,具备良好的项目管理素养会使项目更加稳定,可控。
良好的项目管理素养包括:
良好的项目开发及维护习惯,记住:千万别为了一时的省力,造成后面多次的重复劳动。时时提醒自己将工作流程化,流程规划化,规范简单化。
良好的多人合作管理意识:项目不是一个人的,是多人协作的产物,也是服务于大众的,因而,要提升协作意识,让相关人员一同来完善项目。
4,丰富的项目开发应用经验
学理论,去考试或考核是学校里面的事儿,没有项目经验,就像满肚子经文,吐也难吐出。
这就需要实际的项目将自己的知识去学会转化为需求实现。
5,良好的开发规范
代码可读性强:对象,方法,函数的注释;一套成熟的命名规范;
代码冗余度底:程序和文件的重用性大,高内聚,低耦合
执行效率高:用最简单的程序流程实现应用需求,勿扰大弯子
代码安全性好:做一名警惕的程序员,任何有用户输入和上传文件的地方都得额外谨慎,也许一个程序员一时的疏忽就会导致一个系统顷刻间崩溃。
另外,多废话几句,PHP高级工程师,其实对于一个稍微能坚持,并喜欢PHP的来说不太难;难的是学会用工具来实现想法,不管是自己的想法还是他人的需求,学会转化。
这样,不防多了解些互联网发展的趋势,项目开发管理流程等等
很多面试,很多人员能力要求都有“PHP高级工程师的字眼”,如果您真心喜欢PHP,并且您刚起步,那么我简单说说一个PHP高级工程师所应该具备的,希望给初级或已经达到中级的PHP工程师一些帮助。
一、平静的心态
和所有程序员一样,要写一手好的程序,没有好的心态是不行的。
遇事不可急躁,不可轻言放弃。
在程序开发过程中,尤其是初中级程序员,写出的程序或架构会遇到很多问题,其中一些问题比较弱智,而有些问题根本没有碰到过,于是不可太过急躁,应该逐个排查问题的最初源泉,将其干掉。急躁的心态去开发系统是对项目的一种不负责。急躁会让人学会将就,让人学会逃避。而我个人北京两年的简单生活,给我其中一个最大的历练也就是:我的心态更加平静了。
相信,这样的心态也会有助于你其他方面的处事能力。
为什么将心态列入其中,我是想说明:他不同于销售的职能,需要很大激情澎湃,而是需要静静的思考。
二、一套烂熟于心的问题解决思路
曾经有位程序开发的同事在QQ签名中写到:每解决一个bug,就给自己一个提升。的确,没有真正解决过无数的bug或问题的程序员,谈不上专家,谈不上高级程序员。而一个高级程序员正是从这种解决问题的过程中不断的历练自己,形成一套烂熟于心的问题解决思路,要自己强大的。
我也简单说说PHP程序员成长过程中经常遇到的一些问题,如果你一个也没遇到或很少遇到,那么您就是两个极端的人:要么初级入门,要么高级了,哈哈。
1,编码问题
2,PHP和SQL数据库执行效率问题
3,Session和Cookie域和加密解析问题
4,程序的执行顺序问题
5,程序编写的多环境适用问题
6,分类的构建和结构设计问题
7,字符串处理问题:正则表达式处理或简单PHP字符串处理函数来处理
8,各种模板引擎的编写局限性问题
9,PHP和web端数据交互问题(如ajax,接口调用等)
三、过硬的PHP基础知识
没有过硬的PHP基础知识,哪怕心态再好,问题解决的能力再强,也只能纸上谈兵。
过硬的基础知识会让你在项目开发过程中游刃有余。
我也简单说说哪些属于PHP工程师所应具备的基础知识(其实这些在招聘需求中很常见):
1,语法规则,这个不说了,这个不会,就没入门,赶紧买本书或找个网站补补
2,MYSQL各种sql语句的写法,增删改查基本的不说了,in,union,left,left join,as,replace,alter table,where的字段排序,各种索引建立的方法要特别熟悉
3,会自己搭建LAMP环境和WAMP环境,用集成软件一键式安装的不算。开发程序,对于自己开发的环境构建结构都不清楚,怎么排查问题?所以至少要会用对立的msi文件来安装自己需要的开发环境。安装3-5遍成功,这个算还行,还得会安装各种扩展,配置apache服务,知道各种参数设置的地方以及知道怎么设置各种参数;会linux操作系统的基本命令。
4,熟悉web方面的其他程序,因为PHP不是一个完全独立的东西,他是一个和其他语言和要素配合来完成一个项目的,如果对其他语言和要素不太熟悉,在团队协作过程中会非常吃力。这些其他要素包括:html,javascript,jquery,xml,http协议,正则表达式等
四、综合的互联网应用及项目管理知识和素养
1,见识广博,擅于学习
只顾自己专研,不看看、学学人家的做法,会像井底之蛙,难以看到广阔的天空的;所以,不要只顾着天天编程,学会抽点时间去看看一些大型开源系统的架构思路,以及大型商务网站的构建方式。向他们学习,补充自己的不足。
比如至少该晓得不同类型的开源系统有哪些吧,比如Uchome,dede,phpcms,wordpress,discuz,帝国等等
看多了,你也会总结发现一些常规性的思路,比如缓存的机制,比如模板机制,比如静态页面生成等等。
2,项目解决方案选型
不同需求,用不同的机构和选型。也就是常说的“水来土掩,兵来将挡”,有些架构固然强大,但是用于小型项目也会很吃力,就是杀机不用牛刀。根据需求来选型很重要。
选型不是随口就能定的,需要一个PHP程序员用于良好的储备,个人觉得至少需要以下储备,才具备选型能力:
熟练应用至少一个PHP框架,两-三个PHP开源系统;拥有自己的一套应用系统。
3,良好的项目管理素养
项目不是一直开发过程中,项目也会进入运营期,维护期,这样,具备良好的项目管理素养会使项目更加稳定,可控。
良好的项目管理素养包括:
良好的项目开发及维护习惯,记住:千万别为了一时的省力,造成后面多次的重复劳动。时时提醒自己将工作流程化,流程规划化,规范简单化。
良好的多人合作管理意识:项目不是一个人的,是多人协作的产物,也是服务于大众的,因而,要提升协作意识,让相关人员一同来完善项目。
4,丰富的项目开发应用经验
学理论,去考试或考核是学校里面的事儿,没有项目经验,就像满肚子经文,吐也难吐出。
这就需要实际的项目将自己的知识去学会转化为需求实现。
5,良好的开发规范
代码可读性强:对象,方法,函数的注释;一套成熟的命名规范;
代码冗余度底:程序和文件的重用性大,高内聚,低耦合
执行效率高:用最简单的程序流程实现应用需求,勿扰大弯子
代码安全性好:做一名警惕的程序员,任何有用户输入和上传文件的地方都得额外谨慎,也许一个程序员一时的疏忽就会导致一个系统顷刻间崩溃。
另外,多废话几句,PHP高级工程师,其实对于一个稍微能坚持,并喜欢PHP的来说不太难;难的是学会用工具来实现想法,不管是自己的想法还是他人的需求,学会转化。
这样,不防多了解些互联网发展的趋势,项目开发管理流程等等
php生成UUID唯一序列的代码示例
Php/Js/Shell/Go jackxiang 2016-3-30 14:50
背景:生成一个唯一性的uuid有一个好处,那就是可以用它标识一个唯一的事物,或一次接口请求只能一次,统一了格式。
用redis队列吧
每次要唯一值都从redis里面拿
uniqid() 性能狠low
你这么做可以满足自己的需求
当前 机器IP+ pid+microtime+rand
pid是当前进程号
*************************************************************************************
也可以直接用sql语句生成如:
直接在insert语句中插入UUID作主键的用法(简便):
insert into Price( Name, UUID, Price, BID) values('FEIFEI_TEST', uuid(), 32, 3);
************************************************************************************
php生成uuid 来表示唯一码
uuid是什么?guid是什么?php如何生成uuid?(google 搜索相关内容时使用uuid + mysql得到的结果较uuid+php要多些)
这里有一篇关于UUID的说明 蛮详细
http://mlxia.javaeye.com/blog/279059
以下部分内容为转载:
我唯一还算熟悉的数据库就 算是MySQL了,大概使用MySQL的人,百分之九九以上的人会使用Autoincrement ID做主键,这是可以理解的,因为MySQL的自增ID效率很高,使用也很方便。那么剩下的百分之一的人使用什么做主键呢?可能是自己做的 KeyGenerator,也可能是我们下面要说的UUID。
据说在Oracle的圈子里,如果谁用自增ID做主键是要被鄙视的,主键最自然的选择就是UUID。我不了解Oracle,这些道听途说的结论是否正确不做承诺。
那么我们先看看什么是UUID?简单的说,UUID是指在一台机器上生成的数字,它保证对在同一时空中的所有机器都是唯一的。在UUID的算法中,可能会用到诸如网卡MAC地址,IP,主机名,进程ID等信息以保证其独立性。
如果你的MySQL版本不太老的话,键入 SELECT UUID(); 输出的就是UUID,如下:
mysql> select uuid();
+--------------------------------------+
| uuid() |
+--------------------------------------+
| 54b4c01f-dce0-102a-a4e0-462c07a00c5e |
+--------------------------------------+
现在大家应该对UUID有一个比较直观的认识了,我们来看看UUID的优缺点分别是什么。
优点:
能够保证独立性,程序可以在不同的数据库间迁移,效果不受影响。
保证生成的ID不仅是表独立的,而且是库独立的,这点在你想切分数据库的时候尤为重要。
缺点:
比较占地方,和INT类型相比,存储一个UUID要花费更多的空间。
使用UUID后,URL显得冗长,不够友好。
下面针对上述UUID的缺点说说我的看法,比较占地方这个缺点我不是很在乎,现在最不值钱的就是硬盘了,略过此条缺点无妨。至于说使用UUID后,URL 显得不友好,我觉得这多少是你的INT情结造成的惯性思维,其实,和INT类型相比,UUID才是最自然的主键选择,注意,我这里用的是自然这个形容词, 仔细体会一下你能理解我的意思。另外,很多时候,URL本身就不需要友好,比如,一个电子商务网站,按照INT友好的URL说法,她的订单URL大概是下 面这个形式的:/order.php/id/123,我要说明的是,这样是很友好,但是有些太友好了,友好的甚至不安全,比如说,我早晨下一个订单,发现 URL是/order.php/id/1000,晚上再下一个订单发现URL是/order.php/id/2000,那么我就可以估计出此网站一天的订 单数大致是1000左右,甚至能大体估计出它的销售额,而这些数据往往都是重要的商业秘密。使用UUID就没有这个顾虑。
效率?
如果上面说的UUID的所谓缺点都不成立的话,那么是否使用UUID做主键,唯一的问题就是效率了。据说在PostgreSQL等数据库里,都有专门的 UUID类型,在这样的数据库里,使用UUID做主键,效率没有任何问题,可惜在MySQL里没有这样的字段,如果想在MySQL里保存UUID做主键, 一般是使用CHAR(36)来模拟,因为不是一个原生的UUID类型,所以主键的效率到底如何有待测试,另外,UUID做主键的效率和UUID本身的算法 实现也有很大关系。
我本来想在我自己的电脑上插入1000000条数据测试一下看看来着,可惜一测试,硬盘灯就一直亮,让我很担心它会挂,虽然硬盘不值钱,但是我重要的数据都在上面,一旦坏了,损失就大了,所以,测试只好作罢。
至于在MySQL上使用UUID(用char(36)存储)做主键,效率到底如何,我也不知道,抱歉 -_-!!!
如何生成UUID?下面这种方法生成的貌似不是UUID,因为MD5实际上是可能存在重复值的(参考http://www.phpx.com/happy/archiver/tid-56636.html),况且使用随机更不能避免存在重复.所以应直接使用mysql中的uuid函数生成
de> function uuid($prefix = '')
{
$chars = md5(uniqid(mt_rand(), true));
$uuid = substr($chars,0,8) . '-';
$uuid .= substr($chars,8,4) . '-';
$uuid .= substr($chars,12,4) . '-';
$uuid .= substr($chars,16,4) . '-';
$uuid .= substr($chars,20,12);
return $prefix . $uuid;
} de>
在mysql中插入uuid使用mysql的uuid()函数
INSERT INTO Table(id,..) VALUES( UUID(), ...)
当然也可以用 SELECT UUID() 先得到一个uuid值再插入进去
题外:
可能相比较使用整型做主键,效率稍差,
另外一个问题是可能导致URL太长,比如显示某个id下的分类时
通常这样category.php?cid=2 但是现在可能是category.php?uuid=a93f16c5-9634-102c-824f-3ea0651c5b77
是否能更改为整型做主键
摘自 :http://blog.csdn.net/china_skag/article/details/7297957
用redis队列吧
每次要唯一值都从redis里面拿
uniqid() 性能狠low
你这么做可以满足自己的需求
当前 机器IP+ pid+microtime+rand
pid是当前进程号
*************************************************************************************
也可以直接用sql语句生成如:
直接在insert语句中插入UUID作主键的用法(简便):
insert into Price( Name, UUID, Price, BID) values('FEIFEI_TEST', uuid(), 32, 3);
************************************************************************************
php生成uuid 来表示唯一码
uuid是什么?guid是什么?php如何生成uuid?(google 搜索相关内容时使用uuid + mysql得到的结果较uuid+php要多些)
这里有一篇关于UUID的说明 蛮详细
http://mlxia.javaeye.com/blog/279059
以下部分内容为转载:
我唯一还算熟悉的数据库就 算是MySQL了,大概使用MySQL的人,百分之九九以上的人会使用Autoincrement ID做主键,这是可以理解的,因为MySQL的自增ID效率很高,使用也很方便。那么剩下的百分之一的人使用什么做主键呢?可能是自己做的 KeyGenerator,也可能是我们下面要说的UUID。
据说在Oracle的圈子里,如果谁用自增ID做主键是要被鄙视的,主键最自然的选择就是UUID。我不了解Oracle,这些道听途说的结论是否正确不做承诺。
那么我们先看看什么是UUID?简单的说,UUID是指在一台机器上生成的数字,它保证对在同一时空中的所有机器都是唯一的。在UUID的算法中,可能会用到诸如网卡MAC地址,IP,主机名,进程ID等信息以保证其独立性。
如果你的MySQL版本不太老的话,键入 SELECT UUID(); 输出的就是UUID,如下:
mysql> select uuid();
+--------------------------------------+
| uuid() |
+--------------------------------------+
| 54b4c01f-dce0-102a-a4e0-462c07a00c5e |
+--------------------------------------+
现在大家应该对UUID有一个比较直观的认识了,我们来看看UUID的优缺点分别是什么。
优点:
能够保证独立性,程序可以在不同的数据库间迁移,效果不受影响。
保证生成的ID不仅是表独立的,而且是库独立的,这点在你想切分数据库的时候尤为重要。
缺点:
比较占地方,和INT类型相比,存储一个UUID要花费更多的空间。
使用UUID后,URL显得冗长,不够友好。
下面针对上述UUID的缺点说说我的看法,比较占地方这个缺点我不是很在乎,现在最不值钱的就是硬盘了,略过此条缺点无妨。至于说使用UUID后,URL 显得不友好,我觉得这多少是你的INT情结造成的惯性思维,其实,和INT类型相比,UUID才是最自然的主键选择,注意,我这里用的是自然这个形容词, 仔细体会一下你能理解我的意思。另外,很多时候,URL本身就不需要友好,比如,一个电子商务网站,按照INT友好的URL说法,她的订单URL大概是下 面这个形式的:/order.php/id/123,我要说明的是,这样是很友好,但是有些太友好了,友好的甚至不安全,比如说,我早晨下一个订单,发现 URL是/order.php/id/1000,晚上再下一个订单发现URL是/order.php/id/2000,那么我就可以估计出此网站一天的订 单数大致是1000左右,甚至能大体估计出它的销售额,而这些数据往往都是重要的商业秘密。使用UUID就没有这个顾虑。
效率?
如果上面说的UUID的所谓缺点都不成立的话,那么是否使用UUID做主键,唯一的问题就是效率了。据说在PostgreSQL等数据库里,都有专门的 UUID类型,在这样的数据库里,使用UUID做主键,效率没有任何问题,可惜在MySQL里没有这样的字段,如果想在MySQL里保存UUID做主键, 一般是使用CHAR(36)来模拟,因为不是一个原生的UUID类型,所以主键的效率到底如何有待测试,另外,UUID做主键的效率和UUID本身的算法 实现也有很大关系。
我本来想在我自己的电脑上插入1000000条数据测试一下看看来着,可惜一测试,硬盘灯就一直亮,让我很担心它会挂,虽然硬盘不值钱,但是我重要的数据都在上面,一旦坏了,损失就大了,所以,测试只好作罢。
至于在MySQL上使用UUID(用char(36)存储)做主键,效率到底如何,我也不知道,抱歉 -_-!!!
如何生成UUID?下面这种方法生成的貌似不是UUID,因为MD5实际上是可能存在重复值的(参考http://www.phpx.com/happy/archiver/tid-56636.html),况且使用随机更不能避免存在重复.所以应直接使用mysql中的uuid函数生成
de> function uuid($prefix = '')
{
$chars = md5(uniqid(mt_rand(), true));
$uuid = substr($chars,0,8) . '-';
$uuid .= substr($chars,8,4) . '-';
$uuid .= substr($chars,12,4) . '-';
$uuid .= substr($chars,16,4) . '-';
$uuid .= substr($chars,20,12);
return $prefix . $uuid;
} de>
在mysql中插入uuid使用mysql的uuid()函数
INSERT INTO Table(id,..) VALUES( UUID(), ...)
当然也可以用 SELECT UUID() 先得到一个uuid值再插入进去
题外:
可能相比较使用整型做主键,效率稍差,
另外一个问题是可能导致URL太长,比如显示某个id下的分类时
通常这样category.php?cid=2 但是现在可能是category.php?uuid=a93f16c5-9634-102c-824f-3ea0651c5b77
是否能更改为整型做主键
摘自 :http://blog.csdn.net/china_skag/article/details/7297957
背景:博客采用了ssl的https和http访问,自己后台登录和搜索采用https,而发现在搜索时出现https://jackxiang.com/visit.php有时从www.jackxiang.com里进去后出现,https://www.jackxiang.com:80/visit.php,查看模板里的这个变量值是:action="https://{$_SERVER["HTTP_HOST"]}/visit.php",我其实是想它走https://jackxiang.com/visit.php,一查原来是这个变量的问题,于是修改成了:action="https://{$_SERVER["SERVER_NAME"]}/visit.php" 就好了,如下:
PHP $_SERVER["SERVER_NAME"]与 $_SERVER['HTTP_HOST'] 区别对比如下:
相同点:
当满足以下三个条件时,两者会输出相同信息。
1. 服务器为80端口
2. apache的conf中ServerName设置正确
3. HTTP/1.1协议规范
不同点:
1. 通常情况:
_SERVER["HTTP_HOST"] 在HTTP/1.1协议规范下,会根据客户端的HTTP请求输出信息。
_SERVER["SERVER_NAME"] 默认情况下直接输出apache的配置文件httpd.conf中的ServerName值。
2. 当服务器为非80端口时:
_SERVER["HTTP_HOST"] 会输出端口号,例如:111cn.net:8080
_SERVER["SERVER_NAME"] 会直接输出ServerName值
因此在这种情况下,可以理解为:HTTP_HOST = SERVER_NAME : SERVER_PORT
3. 当配置文件httpd.conf中的ServerName与HTTP/1.0请求的域名不一致时:
httpd.conf配置如下:
<virtualhost *>
ServerName 111cn.net
ServerAlias www.111cn.net
</virtualhost>
客户端访问域名www.111cn.net
_SERVER["HTTP_HOST"] 输出 www.111cn.net
_SERVER["SERVER_NAME"] 输出 111cn.net
所以,在实际程序中,应尽量使用_SERVER["HTTP_HOST"] ,比较保险和可靠。
来自:http://www.111cn.net/phper/php-cy/59314.htm
PHP $_SERVER["SERVER_NAME"]与 $_SERVER['HTTP_HOST'] 区别对比如下:
相同点:
当满足以下三个条件时,两者会输出相同信息。
1. 服务器为80端口
2. apache的conf中ServerName设置正确
3. HTTP/1.1协议规范
不同点:
1. 通常情况:
_SERVER["HTTP_HOST"] 在HTTP/1.1协议规范下,会根据客户端的HTTP请求输出信息。
_SERVER["SERVER_NAME"] 默认情况下直接输出apache的配置文件httpd.conf中的ServerName值。
2. 当服务器为非80端口时:
_SERVER["HTTP_HOST"] 会输出端口号,例如:111cn.net:8080
_SERVER["SERVER_NAME"] 会直接输出ServerName值
因此在这种情况下,可以理解为:HTTP_HOST = SERVER_NAME : SERVER_PORT
3. 当配置文件httpd.conf中的ServerName与HTTP/1.0请求的域名不一致时:
httpd.conf配置如下:
<virtualhost *>
ServerName 111cn.net
ServerAlias www.111cn.net
</virtualhost>
客户端访问域名www.111cn.net
_SERVER["HTTP_HOST"] 输出 www.111cn.net
_SERVER["SERVER_NAME"] 输出 111cn.net
所以,在实际程序中,应尽量使用_SERVER["HTTP_HOST"] ,比较保险和可靠。
来自:http://www.111cn.net/phper/php-cy/59314.htm
PHP-fpm下的fpm的children参数
Php/Js/Shell/Go jackxiang 2016-3-28 17:43
PHP-fpm下的fpm的children参数:
Opt Children Number = Total CPU Resource / CPU Usage Per Request,
第一个是物理核数? 第二个是每个请求对cpu的使用率? 第二个数值怎么去得到呢?
Opt Children Number = Total CPU Resource / CPU Usage Per Request,
第一个是物理核数? 第二个是每个请求对cpu的使用率? 第二个数值怎么去得到呢?
聊聊swoole的心跳
Php/Js/Shell/Go jackxiang 2016-3-25 17:37
来自:桶哥的一篇关于swoole的心跳的文章,作为Swoole顾问(顾得上就问,是为「顾问」)得推一下这篇文章,最后只留下一配置,其实我也不是太明白原理,我在想如果是局域网里还需要心跳?
——————————————————————————————————————————————————————————————————————
swoole提供了一个心跳的功能,很多朋友感到困惑。
心跳是什么?
顾名思义,心跳是判断一个事物生还是死的一个标准,在swoole里,心跳是指用来判断一个连接是正常还是断开的。
从TCP协议说起
我们都知道一个五元组标识一个网络连接,创建一个连接有三次握手,而断开一个连接有四次挥手。不管是服务器还是客户端
发起连接的关闭,都会完整的走完四次挥手的过程,这样,一切很完美,系统回收这个fd,应用层也可以通过onClose回调处理相关的事情.
fd是什么?
fd学名是文件描述符,在unix的哲学就是一切皆文件中,这个fd就是系统层暴露给业务层的用来表示一个五元组网络连接的标识。你可以简单的理解为一个索引,通过对这个fd的操作,系统层可以找到相应的连接而且进行的一系列操作,如发送数据到网瞳,进行连接关闭等等。
为什么要心跳?
刚才提到,如果我们要关闭某个连接,我们可以在业务层对fd发起关闭连接的操作,以swoole为例:
$server->close($fd);
正常情况下,都会走完整个四次挥手,(swoole会有onClose回调),系统回收fd,以待分配给其他的连接。
那系统为什么要回收fd,因为fd资源是有限的,所以必需重复利用。
但在某些情况下,如突然拔掉网线或蓝翔演习挖断光缆,服务端并不能感知到这个连接的异常,但实际上是这个连接已经失效了,如果没有一个回收机制,这类连接将用光所有的fd,导致系统不再能接受新的连接请求,所以就有了心跳机制。
什么是心跳机制?
心跳机制就是业务层来提供一个连接是否存活的一个方法,让系统能判定一个连接是否失效。一般有两种实现方式:
1: 客户端定时发送一个心跳包,告诉服务器我还活着,服务器定时检测所有客户端列表,看他们最后一个心跳包的时间是否过长,如果过长,则认为已无心跳,判定为死连接,主动关闭这个连接。
2: 服务器定时询问所有的客户端,你们还活着么?如果活着,给我个回馈,没得到回馈的客户端,格杀勿论。
两种心跳方案有什么区别?
第一种方案,对服务器和网络的压力更小,而且更具有灵活性,但需要客户端配合定时发送心跳包。
第二种方案,对服务器和网络压力更大,不建议使用。
心跳在swoole里的实现
swoole采用的是第一种方案
swoole会在主进程独立起一个心跳线程,通过定时轮询所有的连接,来判断连接的生死,所以swoole的心跳不会堵塞任何业务逻辑。
那怎么判断连接的生死了?swoole在connection结构体中有 time_t last_time 字段,用来存放最后一次收包的时间戳,进而通过与这个时间对比来判定是否存活
于是,swoole有两个配置:
heartbeat_check_interval: 服务器定时检测在线列表的时间
heartbeat_idle_time: 连接最大的空闲时间 (如果最后一个心跳包的时间与当前时间之差超过这个值,则认为该连接失效)
配置建议
建议 heartbeat_idle_time 为 heartbeat_check_interval 的两倍多一点。
这个两倍是为了进行容错,允许丢一个包
而多一点是考虑到网络的延时。
你可以跟据实际的业务来调整这个容错率(允许丢几个包)。
补充
1、系统层面也提供心跳机制,只不过粒度相对比较粗,而且时间稍长,没有应用层灵活
2、swoole还提供ping的功能,通过配置ping值,swoole内核可以判断只是一个心跳包,而不会,也没必要把数据包转发应用层(onReceive)。
3、心跳不只是swoole独有,大多数tcp的网络服务都会考虑到这个问题
——————————————————————————————————————————————————————————————————————
swoole提供了一个心跳的功能,很多朋友感到困惑。
心跳是什么?
顾名思义,心跳是判断一个事物生还是死的一个标准,在swoole里,心跳是指用来判断一个连接是正常还是断开的。
从TCP协议说起
我们都知道一个五元组标识一个网络连接,创建一个连接有三次握手,而断开一个连接有四次挥手。不管是服务器还是客户端
发起连接的关闭,都会完整的走完四次挥手的过程,这样,一切很完美,系统回收这个fd,应用层也可以通过onClose回调处理相关的事情.
fd是什么?
fd学名是文件描述符,在unix的哲学就是一切皆文件中,这个fd就是系统层暴露给业务层的用来表示一个五元组网络连接的标识。你可以简单的理解为一个索引,通过对这个fd的操作,系统层可以找到相应的连接而且进行的一系列操作,如发送数据到网瞳,进行连接关闭等等。
为什么要心跳?
刚才提到,如果我们要关闭某个连接,我们可以在业务层对fd发起关闭连接的操作,以swoole为例:
$server->close($fd);
正常情况下,都会走完整个四次挥手,(swoole会有onClose回调),系统回收fd,以待分配给其他的连接。
那系统为什么要回收fd,因为fd资源是有限的,所以必需重复利用。
但在某些情况下,如突然拔掉网线或蓝翔演习挖断光缆,服务端并不能感知到这个连接的异常,但实际上是这个连接已经失效了,如果没有一个回收机制,这类连接将用光所有的fd,导致系统不再能接受新的连接请求,所以就有了心跳机制。
什么是心跳机制?
心跳机制就是业务层来提供一个连接是否存活的一个方法,让系统能判定一个连接是否失效。一般有两种实现方式:
1: 客户端定时发送一个心跳包,告诉服务器我还活着,服务器定时检测所有客户端列表,看他们最后一个心跳包的时间是否过长,如果过长,则认为已无心跳,判定为死连接,主动关闭这个连接。
2: 服务器定时询问所有的客户端,你们还活着么?如果活着,给我个回馈,没得到回馈的客户端,格杀勿论。
两种心跳方案有什么区别?
第一种方案,对服务器和网络的压力更小,而且更具有灵活性,但需要客户端配合定时发送心跳包。
第二种方案,对服务器和网络压力更大,不建议使用。
心跳在swoole里的实现
swoole采用的是第一种方案
swoole会在主进程独立起一个心跳线程,通过定时轮询所有的连接,来判断连接的生死,所以swoole的心跳不会堵塞任何业务逻辑。
那怎么判断连接的生死了?swoole在connection结构体中有 time_t last_time 字段,用来存放最后一次收包的时间戳,进而通过与这个时间对比来判定是否存活
于是,swoole有两个配置:
heartbeat_check_interval: 服务器定时检测在线列表的时间
heartbeat_idle_time: 连接最大的空闲时间 (如果最后一个心跳包的时间与当前时间之差超过这个值,则认为该连接失效)
配置建议
建议 heartbeat_idle_time 为 heartbeat_check_interval 的两倍多一点。
这个两倍是为了进行容错,允许丢一个包
而多一点是考虑到网络的延时。
你可以跟据实际的业务来调整这个容错率(允许丢几个包)。
补充
1、系统层面也提供心跳机制,只不过粒度相对比较粗,而且时间稍长,没有应用层灵活
2、swoole还提供ping的功能,通过配置ping值,swoole内核可以判断只是一个心跳包,而不会,也没必要把数据包转发应用层(onReceive)。
3、心跳不只是swoole独有,大多数tcp的网络服务都会考虑到这个问题
[实践OK]AWK的NR和FNR涉及高级技巧,用一行awk命令处理错开又有对应关系的两列,比用Excel更优雅,比paste更精细且相当优雅。
Php/Js/Shell/Go jackxiang 2016-3-24 19:03
背景:我们特别是在想对两个都各带一列且没有行对齐且行数不一致的关联性的文件做关联成一行的时候,会想用自己熟悉的语言去先后打开两个文件(可能高级点的语言可以一次读取到内存,以PHP这种擅长处理字符串的语言为例,且文件要小,当然你可以对PHP占用内存作调整配置。),对文件里面的所有列全部读取到数组,再用循环对数组每行进行分割提取出关联行,再读取另外一个文件一样分离出相同的部分形成数组键,值就是一行,对第一个文件里面的关联列一个一个去第二个文件里面的数组里循环查找到查到为止,找到后,对以找到的这行的key定了,当然就对应上了,这个看起来简单,得6到7行,往往伴随着那个一行里面提取部分,也就是说需要arr=explode(sep,line),取arr某些键值和第一个文件(也可能需要类似explode操作)有关联的显示出来,你还会说,这个不难,有Excel可以实现,先对这两个文件所关联列进行排序,然后,复制粘贴在一块就OK了,感觉很简单也挺棒的,但是,假如两行的数据里面有重复行,两个文件不一样的行数,这个再像linux下的paste俩文件一样行去搞可能就会有问题了,是不是有点难搞,还得去重复啥的,其灵活性可能还是欠佳,往往需求上对重复部分只留下一个就OK的处理方式居多,Excel想做到这样引入了去重复后让两行一样多的操作,SO,有没有简单可行,优雅简洁的处理方式呢?有,那就是上面描述的可以用awk一行搞定,听说由三个数学家的名字首字母发明出来的,它优雅的使用两个类似宏的东西NR,FNR两个变量实现了上面一堆功能,对行和列处理应该相当有水平,在此,我向他们致敬。
—————————————————————————————————————————————————————————————————————————
书上说:
NR,表示awk开始执行程序后所读取的数据行数.
FNR,与NR功用类似,不同的是awk每打开一个新文件,FNR便从0重新累计.
下面看两个例子:
1,对于单个文件NR 和FNR 的 输出结果一样的 :
# awk '{print NR,$0}' file1
1 a b c d
2 a b d c
3 a c b d
#awk '{print FNR,$0}' file1
1 a b c d
2 a b d c
3 a c b d
2,但是对于多个文件 :
# awk '{print NR,$0}' file1 file2
1 a b c d
2 a b d c
3 a c b d
4 aa bb cc dd
5 aa bb dd cc
6 aa cc bb dd
# awk '{print FNR,$0}' file1 file2
1 a b c d
2 a b d c
3 a c b d
1 aa bb cc dd
2 aa bb dd cc
3 aa cc bb dd
在看一个例子关于NR和FNR的典型应用:
现在有两个文件格式如下:
#cat account
张三|000001
李四|000002
#cat cdr
000001|10
000001|20
000002|30
000002|15
想要得到的结果是将用户名,帐号和金额在同一行打印出来,如下:
张三|000001|10
张三|000001|20
李四|000002|30
李四|000002|15
执行如下代码
#awk -F \| 'NR==FNR{a[$2]=$0;next}{print a[$1]"|"$2}' account cdr
注释:
由NR=FNR为真时,判断当前读入的是第一个文件account,然后使用{a[$2]=$0;next}循环将account文件的每行记录都存入数组a,并使用$2第2个字段作为下标引用.
解释,在读取文件1时候,形成如下数组结构:
a[000001]=张三|000001
a[000002]=李四|000002
…………
由NR=FNR为假时,判断当前读入了第二个文件cdr,然后跳过{a[$2]=$0;next},对第二个文件cdr的每一行都无条件执行{print a[$1]"|"$2},此时变量$1为第二个文件的第一个字段,与读入第一个文件时,采用第一个文件第二个字段$2为数组下标相同.因此可以在此使用a[$1]引用数组。
解释,按顺序读取到第二个文件时候,文件二第一行输出数组和第二列,如下:
a[000001] | 10 => 张三|000001 | 10
第一个文件的第二列和第二个文件的第一列关联,a数组存的是第一个文件的按第二列为键值每行。
总结,NR,FNR结合next循环,在数组的key存放关键关联列信息,这个逻辑的核心就在于此,再通过这个awk列$N(N为第几列)优势,只要有关联列,就能这样去匹配出来的行可以任意列输出,相当灵活,优雅,简洁。
=====================自己在日常中的实践如下AddTime:2016-03-25===========================
两个文件里都有UUID的编号及对应的线上机器下载的UUID文件名及后缀,想变成对应的用户上传的中文名加后缀:
(中文名里有各种符号像中文的括号、竖线、空格啥的都得去掉,否则批量肯定会没法成功重命名,需求相当可恶)
windows操作系统虽然好用,但是并不适合研发人员,它的命令行(暂且只说dos, 虽然可以用vb, vbscript,
但是本人不太熟悉,写法上也不太适合做编程)实在是太弱了,想想linux下的shell,用起来还是挺方便的!
方法一:
bianhua_move_comand.txt //得把那个uuid列先单出来,当然,也可用split进行分割直接取数组1,先讲一次性解决,再讲两步来处理。
cee7b22e-f502-4fed-85a4-1db2c8c42468.mp4
1aabd2ac-2133-43d6-921d-b5bd2a34182e.mp4
./bianhua_title_uuid.txt
【新春征集】重庆两江新区《龙兴》 cee7b22e-f502-4fed-85a4-1db2c8c42468
【新春征集】重庆两江新区《伟业》 1aabd2ac-2133-43d6-921d-b5bd2a34182e
awk能够指定分隔符既可以为制表符,又可以为点,那么处理将会变得简单。可以使用正则表达式来指定多个分隔符,格式为 -F[\\t.],
直接指定两个分割符号,分别是\t,和.点,注意斜杠需要转义,awk中-F可指定两种或多种分割符号用[]括起来,awk语句及执行如下所示:
结果达到了mv移动的目的: ......
mv /path/cee7b22e-f502-4fed-85a4-1db2c8c42468.mp4 /path/newfolder/【新春征集】重庆两江新区《龙兴》.mp4
mv /path/1aabd2ac-2133-43d6-921d-b5bd2a34182e.mp4 /path/newfolder/【新春征集】重庆两江新区《伟业》.mp4
方法二:
当然,也可分两次来做,把关联的列都单独出来后,再用awk去做这个事情,总之,都需要写split分割,如下步骤:
awk -F. '{print $1"\t"$0"\t"$2}' bianhua_move_cond.txmat > bianhua_move_comand2.txt
bianhua_move_comand2.txt
经上面的awk处理后其 ./bianhua_move_comand2.txt 结构如下所示:
1aabd2ac-2133-43d6-921d-b5bd2a34182e 1aabd2ac-2133-43d6-921d-b5bd2a34182e.mp4 .mp4
1aabd2ac-2133-43d6-921d-b5bd2a34182e 1aabd2ac-2133-43d6-921d-b5bd2a34182e.mp4 .mp4
把以UUID的文件移到新的目录,并以中文对应名进行赋值,如下:
awk -F\\t 'NR==FNR{a[$1]=$0;next}NR>FNR{if($2 in a) split(a[$2],array,"\\t");print "mv /path/"array[2] " /path/newfolder/"$1array[3]}' bianhua_move_comand2.txt bianhua_title_uuid.txt
其实,去掉NR>FNR也一样可以运行,如下:
最后,还可以去掉in的数组判断,更加简化:
mv /path/cee7b22e-f502-4fed-85a4-1db2c8c42468.mp4 /path/newfolder/【新春征集】重庆两江新区《龙兴》.mp4
mv /path/1aabd2ac-2133-43d6-921d-b5bd2a34182e.mp4 /path/newfolder/【新春征集】重庆两江新区《伟业》.mp4
附录:
split(str,array,sep)
使用分隔符sep把字符串分解成数组array
if($2 in a) //假如这个$2变量在数组里面
-F \\t \| //以斜杠转义下斜杠,制表符和竖线,-F是awk指定的分割符。
假如用PHP实现的大致的流程,和上面一行解决问题起到一个比对作用:
rename.php
实践的最初素材来自:http://www.linuxidc.com/wap.aspx?nid=61174 ,及相关人的讲解,Thanks...
—————————————————————————————————————————————————————————————————————————
书上说:
NR,表示awk开始执行程序后所读取的数据行数.
FNR,与NR功用类似,不同的是awk每打开一个新文件,FNR便从0重新累计.
下面看两个例子:
1,对于单个文件NR 和FNR 的 输出结果一样的 :
# awk '{print NR,$0}' file1
1 a b c d
2 a b d c
3 a c b d
#awk '{print FNR,$0}' file1
1 a b c d
2 a b d c
3 a c b d
2,但是对于多个文件 :
# awk '{print NR,$0}' file1 file2
1 a b c d
2 a b d c
3 a c b d
4 aa bb cc dd
5 aa bb dd cc
6 aa cc bb dd
# awk '{print FNR,$0}' file1 file2
1 a b c d
2 a b d c
3 a c b d
1 aa bb cc dd
2 aa bb dd cc
3 aa cc bb dd
在看一个例子关于NR和FNR的典型应用:
现在有两个文件格式如下:
#cat account
张三|000001
李四|000002
#cat cdr
000001|10
000001|20
000002|30
000002|15
想要得到的结果是将用户名,帐号和金额在同一行打印出来,如下:
张三|000001|10
张三|000001|20
李四|000002|30
李四|000002|15
执行如下代码
#awk -F \| 'NR==FNR{a[$2]=$0;next}{print a[$1]"|"$2}' account cdr
注释:
由NR=FNR为真时,判断当前读入的是第一个文件account,然后使用{a[$2]=$0;next}循环将account文件的每行记录都存入数组a,并使用$2第2个字段作为下标引用.
解释,在读取文件1时候,形成如下数组结构:
a[000001]=张三|000001
a[000002]=李四|000002
…………
由NR=FNR为假时,判断当前读入了第二个文件cdr,然后跳过{a[$2]=$0;next},对第二个文件cdr的每一行都无条件执行{print a[$1]"|"$2},此时变量$1为第二个文件的第一个字段,与读入第一个文件时,采用第一个文件第二个字段$2为数组下标相同.因此可以在此使用a[$1]引用数组。
解释,按顺序读取到第二个文件时候,文件二第一行输出数组和第二列,如下:
a[000001] | 10 => 张三|000001 | 10
第一个文件的第二列和第二个文件的第一列关联,a数组存的是第一个文件的按第二列为键值每行。
总结,NR,FNR结合next循环,在数组的key存放关键关联列信息,这个逻辑的核心就在于此,再通过这个awk列$N(N为第几列)优势,只要有关联列,就能这样去匹配出来的行可以任意列输出,相当灵活,优雅,简洁。
=====================自己在日常中的实践如下AddTime:2016-03-25===========================
两个文件里都有UUID的编号及对应的线上机器下载的UUID文件名及后缀,想变成对应的用户上传的中文名加后缀:
(中文名里有各种符号像中文的括号、竖线、空格啥的都得去掉,否则批量肯定会没法成功重命名,需求相当可恶)
windows操作系统虽然好用,但是并不适合研发人员,它的命令行(暂且只说dos, 虽然可以用vb, vbscript,
但是本人不太熟悉,写法上也不太适合做编程)实在是太弱了,想想linux下的shell,用起来还是挺方便的!
方法一:
bianhua_move_comand.txt //得把那个uuid列先单出来,当然,也可用split进行分割直接取数组1,先讲一次性解决,再讲两步来处理。
cee7b22e-f502-4fed-85a4-1db2c8c42468.mp4
1aabd2ac-2133-43d6-921d-b5bd2a34182e.mp4
./bianhua_title_uuid.txt
【新春征集】重庆两江新区《龙兴》 cee7b22e-f502-4fed-85a4-1db2c8c42468
【新春征集】重庆两江新区《伟业》 1aabd2ac-2133-43d6-921d-b5bd2a34182e
awk能够指定分隔符既可以为制表符,又可以为点,那么处理将会变得简单。可以使用正则表达式来指定多个分隔符,格式为 -F[\\t.],
直接指定两个分割符号,分别是\t,和.点,注意斜杠需要转义,awk中-F可指定两种或多种分割符号用[]括起来,awk语句及执行如下所示:
结果达到了mv移动的目的: ......
mv /path/cee7b22e-f502-4fed-85a4-1db2c8c42468.mp4 /path/newfolder/【新春征集】重庆两江新区《龙兴》.mp4
mv /path/1aabd2ac-2133-43d6-921d-b5bd2a34182e.mp4 /path/newfolder/【新春征集】重庆两江新区《伟业》.mp4
方法二:
当然,也可分两次来做,把关联的列都单独出来后,再用awk去做这个事情,总之,都需要写split分割,如下步骤:
awk -F. '{print $1"\t"$0"\t"$2}' bianhua_move_cond.txmat > bianhua_move_comand2.txt
bianhua_move_comand2.txt
经上面的awk处理后其 ./bianhua_move_comand2.txt 结构如下所示:
1aabd2ac-2133-43d6-921d-b5bd2a34182e 1aabd2ac-2133-43d6-921d-b5bd2a34182e.mp4 .mp4
1aabd2ac-2133-43d6-921d-b5bd2a34182e 1aabd2ac-2133-43d6-921d-b5bd2a34182e.mp4 .mp4
把以UUID的文件移到新的目录,并以中文对应名进行赋值,如下:
awk -F\\t 'NR==FNR{a[$1]=$0;next}NR>FNR{if($2 in a) split(a[$2],array,"\\t");print "mv /path/"array[2] " /path/newfolder/"$1array[3]}' bianhua_move_comand2.txt bianhua_title_uuid.txt
其实,去掉NR>FNR也一样可以运行,如下:
最后,还可以去掉in的数组判断,更加简化:
mv /path/cee7b22e-f502-4fed-85a4-1db2c8c42468.mp4 /path/newfolder/【新春征集】重庆两江新区《龙兴》.mp4
mv /path/1aabd2ac-2133-43d6-921d-b5bd2a34182e.mp4 /path/newfolder/【新春征集】重庆两江新区《伟业》.mp4
附录:
split(str,array,sep)
使用分隔符sep把字符串分解成数组array
if($2 in a) //假如这个$2变量在数组里面
-F \\t \| //以斜杠转义下斜杠,制表符和竖线,-F是awk指定的分割符。
假如用PHP实现的大致的流程,和上面一行解决问题起到一个比对作用:
rename.php
实践的最初素材来自:http://www.linuxidc.com/wap.aspx?nid=61174 ,及相关人的讲解,Thanks...
PHP实现异步调用方法研究
Php/Js/Shell/Go jackxiang 2016-3-18 22:20
浏览器和服务器之间是通过 HTTP 协议进行连接通讯的。这是一种基于请求和响应模型的协议。浏览器通过 URL 向服务器发起请求,Web 服务器接收到请求,执行一段程序,然后做出响应,发送相应的html代码给客户端。
这就有了一个问题,Web 服务器执行一段程序,可能几毫秒就完成,也可能几分钟都完不成。如果程序执行缓慢,用户可能没有耐心等下去,就关闭浏览器了。
而有的时候,我们更本不关心这些耗时的脚本的返回结果,但却还要等他执行完返回,才能继续下一步。
那么有没有什么办法,只是简单的触发调用这些耗时的脚本然后就继续下一步,让这些耗时的脚本在服务端慢慢执行?
经过试验,总结出来几种方法,和大家share:
1. 最简单的办法,就是在返回给客户端的HTML代码中,嵌入AJAX调用,或者,嵌入一个img标签,src指向要执行的耗时脚本。
这种方法最简单,也最快。服务器端不用做任何的调用。
但是缺点是,一般来说Ajax都应该在onLoad以后触发,也就是说,用户点开页面后,就关闭,那就不会触发我们的后台脚本了。
而使用img标签的话,这种方式不能称为严格意义上的异步执行。用户浏览器会长时间等待php脚本的执行完成,也就是用户浏览器的状态栏一直显示还在load。
当然,还可以使用其他的类似原理的方法,比如script标签等等。
2. popen()
resource popen ( string command, string mode );
//打开一个指向进程的管道,该进程由派生给定的 command 命令执行而产生。打开一个指向进程的管道,该进程由派生给定的 command 命令执行而产生。
所以可以通过调用它,但忽略它的输出。
pclose(popen("/home/xinchen/backend.php &"
这个方法避免了第一个方法的缺点,并且也很快。但是问题是,这种方法不能通过HTTP协议请求另外的一个WebService,只能执行本地的脚本文件。并且只能单向打开,无法穿大量参数给被调用脚本。
并且如果,访问量很高的时候,会产生大量的进程。如果使用到了外部资源,还要自己考虑竞争。
3. 使用CURL
这个方法,设置CUROPT_TIMEOUT为1(最小为1,郁闷)。也就是说,客户端至少必须等待1秒钟。
$ch = curl_init(); $curl_opt = array(CURLOPT_URL, 'http://www.example.com/backend.php', CURLOPT_RETURNTRANSFER, 1, CURLOPT_TIMEOUT, 1,); curl_setopt_array($ch, $curl_opt); curl_exec($ch); curl_close($ch);
4. 使用fsockopen
这个方法应该是最完美的,但是缺点是,你需要自己拼出HTTP的header部分。
$fp = fsockopen("www.example.com", 80, $errno, $errstr, 30); if (!$fp) { echo "$errstr ($errno)<br />\n"; } else { $out = "GET /backend.php / HTTP/1.1\r\n"; $out .= "Host: www.example.com\r\n"; $out .= "Connection: Close\r\n\r\n"; fwrite($fp, $out); /*忽略执行结果 while (!feof($fp)) { echo fgets($fp, 128); }*/ fclose($fp); }
所以,总体来看,最好用,最简单的还是第一种方法。
最完美的应该是最后一种,但是比较复杂
如果有更好的办法,欢迎交流。
来自:http://www.laruence.com/2008/04/14/318.html
这就有了一个问题,Web 服务器执行一段程序,可能几毫秒就完成,也可能几分钟都完不成。如果程序执行缓慢,用户可能没有耐心等下去,就关闭浏览器了。
而有的时候,我们更本不关心这些耗时的脚本的返回结果,但却还要等他执行完返回,才能继续下一步。
那么有没有什么办法,只是简单的触发调用这些耗时的脚本然后就继续下一步,让这些耗时的脚本在服务端慢慢执行?
经过试验,总结出来几种方法,和大家share:
1. 最简单的办法,就是在返回给客户端的HTML代码中,嵌入AJAX调用,或者,嵌入一个img标签,src指向要执行的耗时脚本。
这种方法最简单,也最快。服务器端不用做任何的调用。
但是缺点是,一般来说Ajax都应该在onLoad以后触发,也就是说,用户点开页面后,就关闭,那就不会触发我们的后台脚本了。
而使用img标签的话,这种方式不能称为严格意义上的异步执行。用户浏览器会长时间等待php脚本的执行完成,也就是用户浏览器的状态栏一直显示还在load。
当然,还可以使用其他的类似原理的方法,比如script标签等等。
2. popen()
resource popen ( string command, string mode );
//打开一个指向进程的管道,该进程由派生给定的 command 命令执行而产生。打开一个指向进程的管道,该进程由派生给定的 command 命令执行而产生。
所以可以通过调用它,但忽略它的输出。
pclose(popen("/home/xinchen/backend.php &"
这个方法避免了第一个方法的缺点,并且也很快。但是问题是,这种方法不能通过HTTP协议请求另外的一个WebService,只能执行本地的脚本文件。并且只能单向打开,无法穿大量参数给被调用脚本。
并且如果,访问量很高的时候,会产生大量的进程。如果使用到了外部资源,还要自己考虑竞争。
3. 使用CURL
这个方法,设置CUROPT_TIMEOUT为1(最小为1,郁闷)。也就是说,客户端至少必须等待1秒钟。
$ch = curl_init(); $curl_opt = array(CURLOPT_URL, 'http://www.example.com/backend.php', CURLOPT_RETURNTRANSFER, 1, CURLOPT_TIMEOUT, 1,); curl_setopt_array($ch, $curl_opt); curl_exec($ch); curl_close($ch);
4. 使用fsockopen
这个方法应该是最完美的,但是缺点是,你需要自己拼出HTTP的header部分。
$fp = fsockopen("www.example.com", 80, $errno, $errstr, 30); if (!$fp) { echo "$errstr ($errno)<br />\n"; } else { $out = "GET /backend.php / HTTP/1.1\r\n"; $out .= "Host: www.example.com\r\n"; $out .= "Connection: Close\r\n\r\n"; fwrite($fp, $out); /*忽略执行结果 while (!feof($fp)) { echo fgets($fp, 128); }*/ fclose($fp); }
所以,总体来看,最好用,最简单的还是第一种方法。
最完美的应该是最后一种,但是比较复杂
如果有更好的办法,欢迎交流。
来自:http://www.laruence.com/2008/04/14/318.html
[运维用到]PHP的with-config-file-path 这个是用来指定目录,不是指定文件,PHP扩展的ini配置文件目录指定。
Php/Js/Shell/Go jackxiang 2016-3-18 16:01
背景:运行指定扩展配置文件extension.ini的扫描目录,这样结构化有利于运维进行模块添加,也是后来我运维时看到并实践的文章,参考文章,http://jackxiang.com/post/8613/。
参数 --prefix=/usr/local/php --with-config-file-scan-dir=/usr/local/php/etc/
一定要设置正确,多个PHP版本须编译安装在不同路径!!!后面编译后无法修改此项:
Set the path in which to look for php.ini [PREFIX/lib]
--with-config-file-scan-dir=PATH
php.ini的扩展目录,php -c /usr/local/php/etc/php-workerman.ini --ini=/usr/local/php/etc/php-workerman.d --help|grep scan 编译完php二进制后并没有提供参数指定。
作者:风吹我已散博客
链接:https://www.jianshu.com/p/f13402d5217e
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
PHP7在和PHP6一块时注意这个参数,下面就是编译时给指向了PHP5的目录了,出现运行报错,如下:
/usr/local/php7/bin/php start.php
PHP Warning: PHP Startup: Unable to load dynamic library 'redis.so' (tried: /usr/local/php/ext/redis.so (/usr/local/php/ext/redis.so: Undefined symbol "zval_used_for_init"), /usr/local/php/ext/redis.so.so (Cannot open "/usr/local/php/ext/redis.so.so")) in Unknown on line 0
Usage: php yourfile <command> [mode]
还原编译时的命令,如下:
/usr/local/php7/bin/php -i|grep configure 编译参数:
--with-config-file-scan-dir=/usr/local/php7/etc/php.d
个性php.ini里面的参数:
extension_dir => /usr/local/php/ext/ => /usr/local/php/ext/ #这一行没有写,所以就找到/usr/local/php/ext上去了,得写成:
extension_dir => /usr/local/php7/ext/ => /usr/local/php7/ext/
/bin/sed -i 's#; extension_dir = \"\.\/\"#extension_dir = "/usr/local/php/ext/"#' %{buildroot}/%{_prefix}/etc/php.ini
#sed -i "" 's#; extension_dir = \"\.\/\"#extension_dir = "/usr/local/php7/ext/"#' /usr/local/php7/etc/php.ini
737 extension_dir = "/usr/local/php7/ext/"
738 ; On windows:
739 ; extension_dir = "ext"
/usr/local/php/etc/php.d/redis.ini
php -m|grep redis
redis
是因为有:
--with-config-file-scan-dir=/usr/local/php/etc/php.d \
--with-config-file-scan-dir是搜索下面的ini文件和php.ini一起使用,好处就是扩展的那些extension="xx.so"可以放里面,每个扩展一个ini文件,可以方便的用自动化脚本或者部署脚本来搞,看起来模块化了
'—with-config-file-path=/data/software/php-5.6.15/lib/php.ini
open("/data/software/php-5.6.15/bin/php-cli.ini", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/data/software/php-5.6.15/lib/php.ini/php-cli.ini", O_RDONLY) = -1 ENOTDIR (Not a directory)
open("/data/software/php-5.6.15/bin/php.ini", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/data/software/php-5.6.15/lib/php.ini/php.ini", O_RDONLY) = -1 ENOTDIR (Not a directory)
求问这是bug么?
--with-config-file-path=PATH
--with-config-file-scan-dir=PATH
—with-config-file-path 这个是用来指定目录,不是指定文件。
scan这个干嘛的?还能指定php去这个配置目录扫描?
http://php.net/manual/zh/function.php-ini-scanned-files.php
php.conf.d/*.ini
应该一个是cli,一个是运行服务的吧?
不是吧 应该是搜索这个目录下的 *.ini 文件吧
scan是扩展配置文件目录
cli sapi默认都是编译时指定的位置,也可以手动指定
嗯,--with-config-file-scan-dir是搜索下面的ini文件和php.ini一起使用,好处就是扩展的那些extension="xx.so"可以放里面,每个扩展一个ini文件,可以方便的用自动化脚本或者部署脚本来搞,看起来模块化了
关于opcache想编译成静态所谓提高效率:
PHP 5.5.0 及后续版本,
OPcache 只能编译为共享扩展。
—————————————————
理论上性能好点儿,高并发可能瓶颈不在这儿,所以不明显。
静态这个是迷信 嘿嘿,嗯 所以我说这是我自己的迷信 嘿嘿。
参数 --prefix=/usr/local/php --with-config-file-scan-dir=/usr/local/php/etc/
一定要设置正确,多个PHP版本须编译安装在不同路径!!!后面编译后无法修改此项:
Set the path in which to look for php.ini [PREFIX/lib]
--with-config-file-scan-dir=PATH
php.ini的扩展目录,php -c /usr/local/php/etc/php-workerman.ini --ini=/usr/local/php/etc/php-workerman.d --help|grep scan 编译完php二进制后并没有提供参数指定。
作者:风吹我已散博客
链接:https://www.jianshu.com/p/f13402d5217e
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
PHP7在和PHP6一块时注意这个参数,下面就是编译时给指向了PHP5的目录了,出现运行报错,如下:
/usr/local/php7/bin/php start.php
PHP Warning: PHP Startup: Unable to load dynamic library 'redis.so' (tried: /usr/local/php/ext/redis.so (/usr/local/php/ext/redis.so: Undefined symbol "zval_used_for_init"), /usr/local/php/ext/redis.so.so (Cannot open "/usr/local/php/ext/redis.so.so")) in Unknown on line 0
Usage: php yourfile <command> [mode]
还原编译时的命令,如下:
/usr/local/php7/bin/php -i|grep configure 编译参数:
--with-config-file-scan-dir=/usr/local/php7/etc/php.d
个性php.ini里面的参数:
extension_dir => /usr/local/php/ext/ => /usr/local/php/ext/ #这一行没有写,所以就找到/usr/local/php/ext上去了,得写成:
extension_dir => /usr/local/php7/ext/ => /usr/local/php7/ext/
/bin/sed -i 's#; extension_dir = \"\.\/\"#extension_dir = "/usr/local/php/ext/"#' %{buildroot}/%{_prefix}/etc/php.ini
#sed -i "" 's#; extension_dir = \"\.\/\"#extension_dir = "/usr/local/php7/ext/"#' /usr/local/php7/etc/php.ini
737 extension_dir = "/usr/local/php7/ext/"
738 ; On windows:
739 ; extension_dir = "ext"
/usr/local/php/etc/php.d/redis.ini
php -m|grep redis
redis
是因为有:
--with-config-file-scan-dir=/usr/local/php/etc/php.d \
--with-config-file-scan-dir是搜索下面的ini文件和php.ini一起使用,好处就是扩展的那些extension="xx.so"可以放里面,每个扩展一个ini文件,可以方便的用自动化脚本或者部署脚本来搞,看起来模块化了
'—with-config-file-path=/data/software/php-5.6.15/lib/php.ini
open("/data/software/php-5.6.15/bin/php-cli.ini", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/data/software/php-5.6.15/lib/php.ini/php-cli.ini", O_RDONLY) = -1 ENOTDIR (Not a directory)
open("/data/software/php-5.6.15/bin/php.ini", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/data/software/php-5.6.15/lib/php.ini/php.ini", O_RDONLY) = -1 ENOTDIR (Not a directory)
求问这是bug么?
--with-config-file-path=PATH
--with-config-file-scan-dir=PATH
—with-config-file-path 这个是用来指定目录,不是指定文件。
scan这个干嘛的?还能指定php去这个配置目录扫描?
http://php.net/manual/zh/function.php-ini-scanned-files.php
php.conf.d/*.ini
应该一个是cli,一个是运行服务的吧?
不是吧 应该是搜索这个目录下的 *.ini 文件吧
scan是扩展配置文件目录
cli sapi默认都是编译时指定的位置,也可以手动指定
嗯,--with-config-file-scan-dir是搜索下面的ini文件和php.ini一起使用,好处就是扩展的那些extension="xx.so"可以放里面,每个扩展一个ini文件,可以方便的用自动化脚本或者部署脚本来搞,看起来模块化了
关于opcache想编译成静态所谓提高效率:
PHP 5.5.0 及后续版本,
OPcache 只能编译为共享扩展。
—————————————————
理论上性能好点儿,高并发可能瓶颈不在这儿,所以不明显。
静态这个是迷信 嘿嘿,嗯 所以我说这是我自己的迷信 嘿嘿。
php7 memcache 扩展和php7 的redis扩展 。
Php/Js/Shell/Go jackxiang 2016-3-17 17:03
php7 memcache 扩展你们用哪个版本安装成功的?
https://github.com/php-memcached-dev/php-memcached/tree/php7
php7 的redis扩展 有吗?
https://github.com/phpredis/phpredis/tree/php7@tru
https://github.com/php-memcached-dev/php-memcached/tree/php7
php7 的redis扩展 有吗?
https://github.com/phpredis/phpredis/tree/php7@tru
PHP反射类带参数执行反射对象方法传入参数函数示例解析。
Php/Js/Shell/Go jackxiang 2016-3-17 09:05
背景:对于kohana早期框架对类里面的before after以及controller和action的函数均可以用反射类来灵活按既定顺序执行,而在执行的时候假如异常,可以通过PHP提供的异常捕获进行捕获输出,这就涉及到类变对象后其参数的传递问题了,怎么给反射类里面的函数传递多参数乃至引用参数,这个PHP也提供了对应的反射类里函数传入的方法ReflectionMethod::invokeArgs。
使用代码片段如下:
参考更多相关反射的文章:
http://flandycheng.blog.51cto.com/855176/326021/
http://www.phperz.com/article/14/0809/17371.html
自己研究:http://jackxiang.com/post/2090/
ReflectionMethod::invokeArgs
(PHP 5 >= 5.1.0)
ReflectionMethod::invokeArgs — 带参数执行
说明
public mixed ReflectionMethod::invokeArgs ( object $object , array $args )
使用数组给方法传送参数,并执行他。
参数
object
调用方法的对象,如果是静态对象,设置为 null
args
使用 array 传送的方法参数。
返回值
返回方法返回值
错误/异常
如果 object 指定的实例无法执行方法,那么产生 ReflectionException 异常。
如果方法调用失败,产生 ReflectionException
范例
Example #1 ReflectionMethod::invokeArgs() example
<?php
class HelloWorld {
public function sayHelloTo($name) {
return 'Hello ' . $name;
}
}
$reflectionMethod = new ReflectionMethod('HelloWorld', 'sayHelloTo');
echo $reflectionMethod->invokeArgs(new HelloWorld(), array('Mike'));
?>
以上例程会输出:
Hello Mike
注释
Note:
如果函数有参数需为引用,那么它们必须以引用方式传入。
参见
ReflectionMethod::invoke() - Invoke
__invoke()
call_user_func_array() - 调用回调函数,并把一个数组参数作为回调函数的参数
来自:http://help.bitscn.com/php/reflectionmethod.invokeargs.html
使用代码片段如下:
参考更多相关反射的文章:
http://flandycheng.blog.51cto.com/855176/326021/
http://www.phperz.com/article/14/0809/17371.html
自己研究:http://jackxiang.com/post/2090/
ReflectionMethod::invokeArgs
(PHP 5 >= 5.1.0)
ReflectionMethod::invokeArgs — 带参数执行
说明
public mixed ReflectionMethod::invokeArgs ( object $object , array $args )
使用数组给方法传送参数,并执行他。
参数
object
调用方法的对象,如果是静态对象,设置为 null
args
使用 array 传送的方法参数。
返回值
返回方法返回值
错误/异常
如果 object 指定的实例无法执行方法,那么产生 ReflectionException 异常。
如果方法调用失败,产生 ReflectionException
范例
Example #1 ReflectionMethod::invokeArgs() example
<?php
class HelloWorld {
public function sayHelloTo($name) {
return 'Hello ' . $name;
}
}
$reflectionMethod = new ReflectionMethod('HelloWorld', 'sayHelloTo');
echo $reflectionMethod->invokeArgs(new HelloWorld(), array('Mike'));
?>
以上例程会输出:
Hello Mike
注释
Note:
如果函数有参数需为引用,那么它们必须以引用方式传入。
参见
ReflectionMethod::invoke() - Invoke
__invoke()
call_user_func_array() - 调用回调函数,并把一个数组参数作为回调函数的参数
来自:http://help.bitscn.com/php/reflectionmethod.invokeargs.html
Comments starting with '#' are deprecated in Unknown on line 1是因为php-fpm.ini里有#号注释引起的。
Php/Js/Shell/Go jackxiang 2016-3-8 23:25
总之,这种情况主要还是因为php-fpm.conf或php.ini里有#号引起的,我发现尽管php-fpm.conf里用#号能注释,但是会有影响,
我之前安装的是PHP 5.6.18,在运行程序时往往运行nginx请求出现:Comments starting with '#' are deprecated in Unknown on line 1,
后来我再次安装低版本时默认启动没有问题,再将PHP 5.6.18里的php/etc/php-fpm.conf挪动回来后再启动就发生:Comments starting with '#' are deprecated in Unknown on line ,原来里面有一些以#号的中文注释导致的,如:
结论:尽量别用#号注释,php.conf和php-fpm.conf两个,一个是;注释,别用#号,另一个是尽量别用#号,一个#都不要留更好。
===========================================================================
ErrorException [ 8192 ]: Comments starting with '#' are deprecated in Unknown on line 1
find /usr/local/php/ -name "*.ini" -exec sed -i -re 's/^(\s*)#(.*)/\1;\2/g' {} \;
来自:http://stackoverflow.com/questions/29211550/track-down-php-error-comments-starting-with-are-deprecated-in-unknown-on-li
8192 E_DEPRECATED (integer) 运行时通知。启用后将会对在未来版本中可能无法正常工作的代码给出警告。 since PHP 5.3.0
错误码来自:http://www.jb51.net/article/47793.htm
应该是新版本的PHP出现的一个mysql推荐用mysqlli和pdo提示的问题,把错误关掉,再打开就好了,这块儿可能PHP还是有点问题:
error_reporting(E_ALL ^ E_NOTICE ^ E_DEPRECATED);//解决Deprecated: mysql_connect(): The mysql extension is deprecated and will be removed in the future:
ini_set('display_startup_errors', 0);
ini_set('display_errors', 0);
阅读全文
我之前安装的是PHP 5.6.18,在运行程序时往往运行nginx请求出现:Comments starting with '#' are deprecated in Unknown on line 1,
后来我再次安装低版本时默认启动没有问题,再将PHP 5.6.18里的php/etc/php-fpm.conf挪动回来后再启动就发生:Comments starting with '#' are deprecated in Unknown on line ,原来里面有一些以#号的中文注释导致的,如:
结论:尽量别用#号注释,php.conf和php-fpm.conf两个,一个是;注释,别用#号,另一个是尽量别用#号,一个#都不要留更好。
===========================================================================
ErrorException [ 8192 ]: Comments starting with '#' are deprecated in Unknown on line 1
find /usr/local/php/ -name "*.ini" -exec sed -i -re 's/^(\s*)#(.*)/\1;\2/g' {} \;
来自:http://stackoverflow.com/questions/29211550/track-down-php-error-comments-starting-with-are-deprecated-in-unknown-on-li
8192 E_DEPRECATED (integer) 运行时通知。启用后将会对在未来版本中可能无法正常工作的代码给出警告。 since PHP 5.3.0
错误码来自:http://www.jb51.net/article/47793.htm
应该是新版本的PHP出现的一个mysql推荐用mysqlli和pdo提示的问题,把错误关掉,再打开就好了,这块儿可能PHP还是有点问题:
error_reporting(E_ALL ^ E_NOTICE ^ E_DEPRECATED);//解决Deprecated: mysql_connect(): The mysql extension is deprecated and will be removed in the future:
ini_set('display_startup_errors', 0);
ini_set('display_errors', 0);
阅读全文