为什么2013年是PHP之年[原创翻译]

2012年是PHP社区杰出的一年,由于一些迫切需要的功能加入到了5.4版本,而且还有无数的项目,使得PHP达到了新的高度。
在这篇文章里,我将和大家重温下过去人们对PHP的大量疑问,同时一窥为什么我说2013是PHP之年。

敌意
这可能令你惊讶,但是许多人对php开发者有偏见,当然对php语言本身也一样。你应该知道我的意思,如果你在过去的几年里由于来自别人的压力考虑过学习ruby。
“可是,在你改变主意是,你应该扪心自问:为什么PHP有这么多的污点?”
好吧,就想很多生活中的重要问题,这没有一个十分明确的答案。在网上搜索过一些关于php的意见之后,你会发现大概有80%的关于反对php的意见都是来自于他们的根深蒂固的无知,不管以什么样的形式的表达。

初学者
有这样的初学者,他们并没有真正了解的运行原理。这导致了问题出现,就像:为什么你不能利用php监听按钮的事件?包括一些相似的关于AJAX的问题。

一种语言统治了一群人
下面,看看这样一群人,他们除了自己用的不知道其他的语言或者框架。这就是对php产生意见的某些人,比如坚持说rails比php简单多了的哪些人等等。

还在php4里面挣扎的人
第三种误解来自那些没有跟着php的发展与时俱进的一群人。相反,他们仍然还在古老的语言里面纠结,尽管它已经是很多年前的语言了。这导致了一些论调,比如:php不是面向对象的,或者:php真垃圾,不支持命名空间。哈哈,你懂我的意思。

规模
还有,有很多的天才开发者,他们坚持认为php不能形成规模,或者php没有标准等等。当然,这些是完全错误的。规模和语言本身没什么关系,和服务关系更大,当然还有你的应用的架构。至于标准,哈哈,你去google一下PHP-FIG.
——————————————————————————————————————————–
小贴士:
什么是PHP-FIG?
这个组织旨在为了项目成员来讨论我们项目之间的共性,还有找到我们写作的方法。我们的主要受众就是我们自己,但是我们也意识到剩下的PHP社区正在观望,如果其他人愿意把我们现在在做的移植过去,这是很受欢迎的,但是这不是目的。
——————————————————————————————————————————–

不幸的事实就是,弥漫在互联网的这些对php的意见基本都是错的,或者是过时的
PHP不完美
不过,在这些批评里面也有一些是事实。PHP确实不是完美的。有一些核心特性和方法的实现是不合理的,这些意见是完全正确的。
尽管这些不合理之处并不是毫无缘由的。我们今天所说的php源自一种模板语言。自从那时候起,他演变成过各种各样的形式,转变成一门实用的语言,然后又进化成我们现在在用的完全面向对象的语言。在这演变历史中,有很多优秀的项目浮现过,也有越来越多点人掌握了新加入的东西。这却导致了一门语言中各种不同‘风格’的代码。现在你可能会疑问,为什么不可以去反对这么语言中这些并不好的部分。
这个问题的答案就想为什么我们仍然在做网站的时候兼容老版本的IE浏览器一样。不要误会我的意思,我也很想去放弃它,但是很多这种重大的改动不是一蹴而就的。希望随着时间的变化,PHP能进一步的推动面向对象编程,形式上来讲,可以用点号操作符来替代他的对象的函数用法,并不仅仅是可以接受的‘->’操作符的使用。比如。作为‘array_push($arr, “Value”)’的替代形式可以是这样的‘$arr.push(“value”)’
别着急,这种事情都是发展的很慢的看看PHP5.5的特性。老式的面向函数的MYSQL操作已经被摒弃了,这有利于更新的面向对象的实现。

当前形势
说完了过去,我们来说说现在。有一些相当酷的项目,有一些汲取了别的语言的优点,来推动PHP达到更高的水平。让我们来看看这些:
1.Composer(PHP包管理器)
2.Laravel框架
3.测试驱动的开发
4.PHP5.4/5.5

Composer
受到一些工具的启发,比如打包机和网络打印机管理器,PHP社区现在已经有了防止重造轮子的方法,向Composer致敬。Node.js 是第一种我用packages比较舒适的语言,如果你以前用过它,你就知道我指的是什么。Packages是转载你本地的项目目录,对大多数插件来讲,很容易找到文档,这也是的你提交自己的packages时相对比较简单。
PEAR?
PHP很多年来一直给用户提供一个大型库的选择,那就是PEAER,但它并不是想象中的那么好用。如果我只是要去获取一些纯文本文件,会感觉它非常之笨重。而且,你必须要全局地安装它所有的包。这就使得你在你发布项目源码的时候必须去通知所有人那些包你用了,这会导致一些版本不统一的问题,还有其他类似的问题。
Composer只需要本地的包就解决了所有的此类问题。也可以去创建每个项目的独立文件。这意味着你可以很容易的去发布你的项目,只需要这写独立文件,这样其他人就可以用他们自己的Composer的拷贝去纸动画的下载所有具体的单独文件,同时使他们保持更新。
还有一点,Composer是用PHP写的一款轻型应用,它本身就有一个自动加载的特性。这个没有遵循PSR-0标准(上文提到的),这项功能是只有在你需要的时候才去加载需要的文件,这样你的应用就能保持竟可能的精简。
所有的这些特性都是一定的进步,可是,没有社区的共性,这一切都是不存在的。我很高兴告诉你它是很受欢迎的。大型项目,比如Symfony和Laravel,已经将它们的组件上传到了Composer的库,这里是列表(https://packagist.org/)。将框架分解成一些组件意味着你可以很容易的创建你自己的自定义的框架来满足你的需求。从另一方面来讲,再也没有臃肿的框架束缚了。如果你想试试,你可以去选择你需要的组件了。

Laravel
现在如果不详细讨论下Laravel,那就不是一篇关于PHP特性的文章了。我们总是被问到,为什么你们总是 推崇Laravel。其实这是个不对的问题,应该说,为什么不呢?
即使你有一些关于PHP的问题,Laravel几乎将它们全抽象化了,给你的是一种语言的优雅感,像Ruby,但是是用的简易舒适的PHP。
Laravel是由Eloquent(https://packagist.org/packages/illuminate/database)发展而来的,一个完全重新设计的处理数据库的对象关系模型,你从数据库中得到的是一个资源对象,你必须通过一个成员方法来从这个资源对象获取结果。在Laravel中,所有的返回值都遵循PHP标准,你得到的对象可以修改和保存。你可以进行多表查询,得到的结果利用数据调用来保存,当然,仅仅做这些是可笑的,比如验证和自定义查询。另外,如果你不喜欢写SQL,那么这些工作都可以通过面向对象的方式来完成,用简单的可读性搞的方法,比如find和delete
我们只看到了冰山一角,但是,你已经能看到这些改进。Laravel把这种革新带到了PHP的几乎每一个领域包括,模板,路由,迁移,REST风格的类,等等。不过,最好的部分是,在每一个新的版本, Laravel的创造者Taylor Otwell,不断地在改进。
“如果你想更深入地学习下Laravel,我推荐Tuts+ Premium课程,Laravel Essentials(https://tutsplus.com/course/laravel-essentials/),讲师是我们的Jeffrey Way.我不是指的Nettuts+的成员,而是一个看这些教程的家伙。我很诚实地告诉你,我对Laravel的了解是零,但是Jeffrey在这个方面做的是尽可能的优秀”
这不是关于这个框架的文章,但是有社区的支持。一个项目只要有支持维护,它就会有不断的更新和相关的观点。如果你担心它能流行的时间不是太长,那么,只要积极地使用它,那么你就是在加强你的优势。

PHP5.4/5.5
下一件我想讨论的事情是2012年PHP发布的新版本。随着PHP5.4版本的发行,大量的新特性出现了。你可以看下这两篇文章来一窥大概5.4(http://net.tutsplus.com/tutorials/php/php-5-4-is-here-what-you-must-know/),5.5(http://net.tutsplus.com/tutorials/php/what-to-expect-from-php-5-5/)
不过,下面还是要讲讲我最喜欢的几点新特性
Traits
traits使得PHP可以创建“partials”类,这在你不需要覆写的情况下创建相同的对象.(不是太明白这个,可以参考鸟哥的文章http://www.laruence.com/2011/07/02/2097.html);
Generators
Generators可以让你通过数据列表来做一些很酷的事情,也能让你从所有特性中获益
CLI Web Server
另一项伟大的特性是内置的web服务器,通过这个你可以测试你的程序在不同版本php中的兼容性,这一切都不需要类似apache这种服务器软件的支持
Dereferencing
Dereferencing不是一个大的功能,但是它可以在不用方法的情况下来调子元素(这段不明白)。这包括了就像通过下标来引用字符串的字符一样的功能(见http://www.laruence.com/2011/07/02/2097.html)
新的密码散列API
通过这个新的API,你可以去加密字符串,验证或者加强密码,当然你不需要去了解任何的bcrypt或者别的哈希算法

这些特征只是很少一部分的新特性,还有一整个列表的特性正在为了下个版本的发布处于讨论阶段,按照日程应该在今年的晚些时候发布。

测试驱动的开发
最后,让我们讨论下测试的问题。尽管在2012年里,被接纳的有点晚了,我们的社区还是看到了测试驱动开发模式的广泛被采纳。我可以去调查下这方面增长的百分比,但是我感觉你去看看不通的开发者站点还有论坛能更好的说明这个增长。你肯定能看到一个spike!说到PHP中的测试,PHPUnit是一个很好被接受的标准
为什么测试很重要?
很多时候,你准备写代码了,但是你在实现需求的时候漏掉了很多东西。我说这些是指的你计划一件事情的时候,当你实现它的时候,容易失去大局,漏掉一些细节。另一个普遍的问题一直在增长,当给大项目写代码的时候,结束的时候,你可能写了大量的类和大量的文件他们都是不相干的。你剩下的可能是一些纠结的方法的演化,这样才能跟上进度。就像搭积木游戏,随着一块积木的增加,你可能搞倒了另一块,毁了整个项目。这只是两个例子,当然还有很多其他的。
测试驱动开发带来哪些帮助?
你在写任何产品的代码之前写好了清晰的测试样例。这意味着,当你开始写真实代码的时候,这就被限定必须遵循最开始的计划。不光这一段,是完全彻底地,所有都被你的测试所跟进。如果你更新了代码,不经意间没有通过测试,你会马上发现。
是的,实现这些测试需要额外的步骤,但是请三思后行。有任何人通过这种模式的开发获益么?当然没有。测试也是一样的,在你开始开发项目之前,多加思考,就想一个牛仔。
延伸阅读
测试驱动的开发(https://tutsplus.com/course/test-driven-php/)
PHP中的测试驱动开发(http://net.tutsplus.com/sessions/test-driven-php/)

总结
这个时代成为php开发者是令人振奋的。很多既有的问题正在或者已经被解决了,至于其他的问题,我们都可以通过框架和测试来找到解决方案
你的想法呢?你是否已经在码字?不同意我们?如果这样的话,在下面留言吧。

[本文译自netTuts+,转载请保留出处,本文固定链接http://coderaladdin.com/why-2013-is-the-year-of-php/ ‎]

mysql复合查询结果集顺序的一个问题

刚到家,@冰冻的狐狸在qq上给我留言,问这两句SQL为什么查询结果的排序不同

SELECT * FROM `pp_user_history` order by id desc;
SELECT * from (SELECT * FROM `pp_user_history` order by id desc) as hh GROUP BY hh.item_id;

我在本地用两条sql测试了下

SELECT * FROM words ORDER BY id ASC;
SELECT * FROM (SELECT * FROM `words` ORDER BY id ASC) AS hh GROUP BY hh.pinyin_s;

果然是不同的

仔细结果集发现
YJ1_21]E_LOZ6ET7`L`VRI7
通过红框圈出来的那个字段得到如下结论:

结果集排序默认按照主查询的group by字段升序排

BTW.明天年会,尼玛还有一个项目要赶着上线,哥要是不是请了将近三天假陪老娘在医院哥也搞完了啊,催个毛线!今天组里有个同事提离职了,我也和老大说了自己的想法和看法。人是需要成长的,路,也该是不断探索的,我想如果我不按照寻常路走下去,或许我是会遭受许多的挫折和磨难,但是我想也会得到更多。

在此新年之际,谢过老大一年来对我的悉心教导。谢谢!

Apache虚拟主机支持rewrite的设置

今天在用CI写东西的时候,要优化下url,结果.htaccess中rewrite无效,google了很多文章,看了很多CI中国的帖子,没一个说到虚拟主机的apche配置的,甚至社区里面的“前辈大牛”还说和apche配置无关。经过多番尝试,发现在虚拟主机中对url重写的配置需要在虚拟主机配置的前面才行,不知道我得出的这个结论是否正确,请各位访客指正。

顺便感慨下,今天也和斌哥说到的,虽然在公司里面做的产品有这么大流量,看起来是个很好的平台,但是有关服务器,有关负载均衡等方面的东西我们毫不涉及,这些都是需要我们自己平时去充实的知识。当然,写好当下自己该写好的代码是最重要的。

apache配置如下

<VirtualHost *:80>
<Directory "D:/wamp/www/CodeIgniter">
    AllowOverride All
</Directory>
ServerName loc.ci.com
DocumentRoot "D:/wamp/www/CodeIgniter"
</VirtualHost>

母亲周三又要过来这边医院检查了,希望一切都好,努力挣钱!!!

更正下,刚突然想到去看了下vps上本博客的apache virtualhost配置,发现顺序是可以不放前面的
像这样

<VirtualHost *:80>
ServerName loc.ci.com
DocumentRoot "D:/wamp/www/CodeIgniter"
<Directory "D:/wamp/www/CodeIgniter">
    AllowOverride All
</Directory>
</VirtualHost>

Directory后面的路径要写全

curl获取头信息遇到的诡异事件

my problem code

<?php
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, 'http://www.tudou.com/programs/view/qyT7G6gVFSs');
curl_setopt($curl, CURLOPT_HEADER, 1);
curl_setopt($curl , CURLOPT_NOBODY, true);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
$data = curl_exec($curl);
curl_close($curl);
var_dump($data);

the response is

string(241) “HTTP/1.1 405 Method Not Allowed Server: Tengine/1.4.0 Date: Sat, 01 Dec 2012 15:53:32 GMT Content-Type: text/html;charset=GBK Content-Length: 1085 Connection: close appSrv: itemview-app4-app_admin Vary: Accept-Encoding Allow: GET ”

then my correct code is

<?php
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, 'http://www.tudou.com/programs/view/qyT7G6gVFSs');
curl_setopt($curl, CURLOPT_HEADER, 1);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
$data = curl_exec($curl);
curl_close($curl);
var_dump($data);

the result is string(313) “HTTP/1.1 302 Moved Temporarily Server: Tengine/1.4.0 Date: Sat, 01 Dec 2012 16:17:25 GMT Content-Length: 0 Connection: close appSrv: itemview-app5-app_admin Vary: Accept-Encoding Pragma: No-Cache Cache-Control: no-cache, no-store Expires: Thu, 01 Jan 1970 00:00:00 GMT Location: http://tv.tudou.com/

这11月

从学校毕业的第五个月结束了,如果算上实习,这是我工作的第十七个月,除去中间的两个月在学校,说起来也是有一年多工作经验了。就是这个月里犯下了很多的错,闯下了很多的祸,连累了很多同事的奖金,绩效。阿拉丁在此向各位道歉,更是辜负了刘哥对我的期望,十分惭愧。
11月期间陆续闯下的祸有这些:

  1. 更改内页统一头的js没有在ie6下测试,仅在chrome下测试完就直接上线了,导致一整晚ie6用户无法打开页面,原因是这个js在head标签未加载完成时做了appendChild的操作,ie6直接报错无法打开
  2. 迁移整站静态资源到图片中心,期间改某个模板的时候,路径改错了,导致内部统计平台没有统计到下午6个小时的访问ip,这在公司内部是个很严重的问题,也是强调过多次其严重性的问题
  3. 最严重的一个,今天在上线一个需求的时候,没有细心比对代码,上传的代码中有测试服务器上另一个同事修改的测试阶段的代码,尽管我确实有上传代码的时候确实有用乌龟diff的习惯,但是看着那两行黄色的代码,我依然直接上传了,导致10分钟后9台服务器全线崩溃,由于上传的代码文件较多,过了半小时左右才找出问题,加上恢复时间整个项目宕机将近一小时。

因为这几起我个人犯下的错误,运维,同事,产品,还有老大,他们的kpi,评价等都受到了我的连累,他们接受的处罚很多都会比我这个小小工程师受到的处罚要重,这是最让我惭愧的事情,别人因为我的错误而遭受处罚,我也在想是不是每个人成长过程中都会经历这些残忍,我不知道这些问题算大还是算小,只是于我个人来说,我不希望去连累他人,不希望去辜负那些对我好对我有期望的人。

反思自己,在每天的工作生活中,存在非常多的问题。

  1. 对公司各种制度的不满,对公司产品的不满,对公司技术人员地位的不满,导致我的对待工作的态度不够端正
  2. 容易因为一些繁琐的事情把自己搞的很烦躁,然后工作变得没有条理,然后导致各种各样的错误,这主要还是因为自己的心没有沉下来做技术,心浮气躁
  3. 粗心大意,毛手毛脚,做事情带侥幸心理,没有做IT人的严谨态度
  4. 不愿意改变现状,对已知的代码存在的问题不愿意花额外的心思去改进,得过且过,总是给自己找借口去逃避各种问题,总对知己说:这个问题以后解决,先这样了。这是个极其危险的早衰的现象

以后的工作生活中,多约束自己,克服各种惰性,抛掉过去的各种不满,写好自己的代码,完成该完成的需求,事无巨细,都要做记录,写清单。对自己心知肚明该怎么优化的一些问题立马着手,不要等‘以后’!

BTW,物质基础决定上层建筑,现在某种程度上来讲学识经验决定了物质基础.so, I’ll do what I need to do!

11月,对自己的评价是向下的小拇指。

Apache的Order Allow,Deny 详解

Allow和Deny可以用于apache的conf文件或者.htaccess文件中(配合Directory, Location, Files等),用来控制目录和文件的访问授权。

所以,最常用的是:
Order Deny,Allow
Allow from All

注意“Deny,Allow”中间只有一个逗号,也只能有一个逗号,有空格都会出错;单词的大小写不限。上面设定的含义是先设定“先检查禁止设定,没有禁止的全部允许”,而第二句没有Deny,也就是没有禁止访问的设定,直接就是允许所有访问了。这个主要是用来确保或者覆盖上级目录的设置,开放所有内容的访问权。

按照上面的解释,下面的设定是无条件禁止访问:
Order Allow,Deny
Deny from All

如果要禁止部分内容的访问,其他的全部开放:
Order Deny,Allow
Deny from ip1 ip2
或者
Order Allow,Deny
Allow from all
Deny from ip1 ip2

apache会按照order决定最后使用哪一条规则,比如上面的第二种方式,虽然第二句allow允许了访问,但由于在order中allow不是最后规则,因此还需要看有没有deny规则,于是到了第三句,符合ip1和ip2的访问就被禁止了。注意,order决定的“最后”规则非常重要,下面是两个错误的例子和改正方式:

Order Deny,Allow
Allow from all
Deny from domain.org
错误:想禁止来自domain.org的访问,但是deny不是最后规则,apache在处理到第二句allow的时候就已经匹配成功,根本就不会去看第三句。
解决方法:Order Allow,Deny,后面两句不动,即可。

Order Allow,Deny
Allow from ip1
Deny from all
错误:想只允许来自ip1的访问,但是,虽然第二句中设定了allow规则,由于order中deny在后,所以会以第三句deny为准,而第三句的范围中又明显包含了ip1(all include ip1),所以所有的访问都被禁止了。
解决方法一:直接去掉第三句。
解决方法二:
Order Deny,Allow
Deny from all
Allow from ip1

 

下面是测试过的例子:
——————————–
Order deny,allow
allow from all
deny from 219.204.253.8
#全部都可以通行
——————————-
Order deny,allow
deny from 219.204.253.8
allow from all
#全部都可以通行
——————————-
Order allow,deny
deny from 219.204.253.8
allow from all
#只有219.204.253.8不能通行
——————————-
Order allow,deny
allow from all
deny from 219.204.253.8
#只有219.204.253.8不能通行
——————————-
——————————-
Order allow,deny
deny from all
allow from 219.204.253.8
#全部都不能通行
——————————-
Order allow,deny
allow from 219.204.253.8
deny from all
#全部都不能通行
——————————-
Order deny,allow
allow from 219.204.253.8
deny from all
#只允许219.204.253.8通行
——————————-
Order deny,allow
deny from all
allow from 219.204.253.8
#只允许219.204.253.8通行
——————————-
——————————–
Order deny,allow
#全部都可以通行(默认的)
——————————-
Order allow,deny
#全部都不能通行(默认的)
——————————-
Order allow,deny
deny from all
#全部都不能通行
——————————-
Order deny,allow
deny from all
#全部都不能通行
——————————-
对于上面两种情况,如果换成allow from all,则全部都可以通行!
——————————-
Order deny,allow
deny from 219.204.253.8
#只有219.204.253.8不能通行
——————————-
Order allow,deny
deny from 219.204.253.8
#全部都不能通行
——————————-
Order allow,deny
allow from 219.204.253.8
#只允许219.204.253.8通行
——————————-
Order deny,allow
allow from 219.204.253.8
#全部都可以通行
——————————-
——————————-
order deny,allow
allow from 218.20.253.2
deny from 218.20
#代表拒绝218.20开头的IP,但允许218.20.253.2通过;而其它非218.20开头的IP也都允许通过。
——————————-
order allow,deny
allow from 218.20.253.2
deny from 218.20
#和上面的差不多,只是掉换的order语句中的allow、deny先后顺序,但最终结果表示全部都拒绝!

form:http://hi.baidu.com/enjoypain/blog/item/f48c7aecdba298d12f2e21ac.html

前段时间做了个Apache的HTTP代理服务器,其中的order allow,deny这部分弄的不太懂,于是上网找资料看,谁知道越看越糊涂,其中有些难以分辨对错甚至是误导。就像破解windows系统密码的一些文章那样,很多都是人云亦云的,并没有经过测试。废话少说,先把我经过测试后分析总结出来的结论show出来,相信这对大家的理解非常有帮助。

 

总则——

影响最终判断结果的只有两点:

1. order语句中allow、deny的先后顺序;

2. allow、deny语句中各自包含的范围。

 

温馨提醒——

1. 修改完配置后要保存好并重启Apache服务,配置才能生效;

2. 开头字母不分大小写;

3. allow、deny语句不分先后顺序,谁先谁后不影响最终判断结果;但都会被判断到;

4. order语句中,“allow,deny”之间“有且只有”一个逗号(英文格式的),而且先后顺序很重要;

5. Apache有一条缺省规则,“order allow,deny”本身就默认了拒绝所有的意思,因为deny在allow的后面;同理,“order deny,allow”本身默认的是允许所有;当然,最终判断结果还要综合下面的allow、deny语句中各自所包含的范围;(也就是说order语句后面可以没有allow、deny语句)

6. allow、deny语句中,第二个单词一定是“from”,否则Apache会因错而无法启动,

7. “order allow,deny”代表先判断allow语句再判断deny语句,反之亦然。

 

上面说的都是要记住的,而下面说的是我独创的理解方法。如果有人看了而没有豁然开朗的感觉,那算是我的失败!

 

判断原则分4步走——

1. 首先判断默认的;

2. 然后判断逗号前的;

3. 最后判断逗号后的;

4. 最终按顺序叠加而得出判断结果。

 

上面三点我说的简单而形象,主要是为了便于记忆。暂时不理解不要紧,继续看下面详细的解说自然会明白。下面以一个普通例子来做解释——

order deny,allow

allow from 218.20.253.2

deny from 218.20

1. 所谓“首先判断默认的”,就是判断“order deny,allow”这句,它默认是允许所有;

2. 所谓“然后判断逗号前的”,因为在本例子中的order语句里面,deny在逗号的前面,所以现在轮到判断下面的deny语句了——“deny from 218.20”;

3. 所谓“最后判断逗号后的”,因为在本例子中的order语句里面,allow在逗号的后面,所以最后轮到判断下面的allow语句了——“allow from 218.20.253.2”。

4. 所谓“最终按顺序叠加而得出判断结果”,这是一个形象化了的说法,我把每一步判断都看作一个“不透明的图层”,然后一步步按顺序叠加上去,最终得出的“图像”就是判断结果。

 

用过作图软件的人应该都知道“图层”是怎么回事,我估计Apache关于order allow deny这方面的设计理念和photoshop等作图软件关于图层的设计理念是一样的。即“游戏规则”是一样的。

那么上面的例子就可以是这么一个步骤和图像——

1. 先画一个白色的大圆,代表“order deny,allow”语句,默认意思是允许所有;

2. 然后画一个小一点的黑色圆,代表“deny from 218.20”语句,意思是拒绝所有以218.20开头的IP,放进白色的大圆里面;

3. 最后再画一个白色的圆,代表“allow from 218.20.253.2”语句,意思是允许218.20.253.2通过,放在黑色圆的上面。

4. 到此为止,我们已经可以看到一个结果了,白色大圆上面有一个黑色圆,黑色圆上面还有一个白色圆。最后,我们所能看到的黑色部分就是拒绝通行的,剩下的白色部分都是允许通行的。判断的结果就是这么简单形象!

 

如果不懂的用作图软件,我们再来个非常贴近生活的比喻——

把上面的例子改动一点点,以便更好的理解:

order deny,allow

allow from 218.20.253.2

deny from 219.30

1. 首先拿一张A4白纸,代表第order语句,意思是允许全部;

2. 然后拿一张黑色纸剪一个圆,放在A4纸里面的某个位置上,代表deny语句,意思是拒绝所有以219.30开头的IP;

3. 最后拿白纸再剪一个圆,放在黑色圆的旁边,代表allow语句,意思是允许218.20.253.2通过;注意,这个例子不是放进黑色圆里面了,因为deny和allow语句不再有相互包含的关系了。

4. A4纸上面有一个黑色圆和一个白色圆,结果自然很明显了。不过白色的A4纸上再放一个白色的圆,显然是多余的了,因为大家都是白色的,都代表允许,所以就重复了,可以去掉白色的圆而不会影响判断结果。

 

如果看到这里还没明白,那一定是我还有什么没说清楚的。那么请好好分析我所做过的测试例子,将在最后列出来。

在这里再啰嗦一下,allow、deny语句后面跟的参数有多种形式,有不同的表达方式,我在网上看到的做法是deny from IP1 IP2 IP3或allow from domain.com等。其它的表达方式大家再找别的资料看吧。我想说的是另一种表达方式:

order deny,allow

allow from IP1 IP2

allow from domain.info

allow from 219.20.55.0/24

deny from all

我没具体验证过这是否对,不过这样是可以正常启动Apache服务的,按道理应该是正确的表达方式。哈哈,像我这样的入门者只能这样了,还希望大家多多指教!

下面是测试过的例子:
——————————–
Order deny,allow
allow from all
deny from 219.204.253.8
#全部都可以通行
——————————-
Order deny,allow
deny from 219.204.253.8
allow from all
#全部都可以通行
——————————-
Order allow,deny
deny from 219.204.253.8
allow from all
#只有219.204.253.8不能通行
——————————-
Order allow,deny
allow from all
deny from 219.204.253.8
#只有219.204.253.8不能通行
——————————-
——————————-
Order allow,deny
deny from all
allow from 219.204.253.8
#全部都不能通行
——————————-
Order allow,deny
allow from 219.204.253.8
deny from all
#全部都不能通行
——————————-
Order deny,allow
allow from 219.204.253.8
deny from all
#只允许219.204.253.8通行
——————————-
Order deny,allow
deny from all
allow from 219.204.253.8
#只允许219.204.253.8通行
——————————-
——————————–
Order deny,allow
#全部都可以通行(默认的)
——————————-
Order allow,deny
#全部都不能通行(默认的)
——————————-
Order allow,deny
deny from all
#全部都不能通行
——————————-
Order deny,allow
deny from all
#全部都不能通行
——————————-
对于上面两种情况,如果换成allow from all,则全部都可以通行!
——————————-
Order deny,allow
deny from 219.204.253.8
#只有219.204.253.8不能通行
——————————-
Order allow,deny
deny from 219.204.253.8
#全部都不能通行
——————————-
Order allow,deny
allow from 219.204.253.8
#只允许219.204.253.8通行
——————————-
Order deny,allow
allow from 219.204.253.8
#全部都可以通行
——————————-
——————————-
order deny,allow
allow from 218.20.253.2
deny from 218.20
#代表拒绝218.20开头的IP,但允许218.20.253.2通过;而其它非218.20开头的IP也都允许通过。
——————————-
order allow,deny
allow from 218.20.253.2
deny from 218.20
#和上面的差不多,只是掉换的order语句中的allow、deny先后顺序,但最终结果表示全部都拒绝!

php中的(多线程)curl批量处理

function getMultiUrls($urls, $timeout = 30)
	{
		$queue = curl_multi_init();
		$map = array();
	
		foreach($urls as $id=>$url)
		{
			$ch = curl_init();
			curl_setopt($ch , CURLOPT_URL , $url);
			curl_setopt($ch , CURLOPT_TIMEOUT , $timeout);
			curl_setopt($ch , CURLOPT_RETURNTRANSFER , 1);
 			curl_setopt($ch, CURLOPT_HEADER, true);
// 			curl_setopt($ch , CURLOPT_HEADER , 0);
			curl_setopt($ch, CURLOPT_NOBODY, true);
			curl_setopt($ch , CURLOPT_NOSIGNAL , true);
	
			curl_multi_add_handle($queue , $ch);
			$map[(string) $ch] = $id;
		}
	
		$responses = array();
		do
		{
			while(($code = curl_multi_exec($queue , $active)) == CURLM_CALL_MULTI_PERFORM);
			if($code != CURLM_OK)
			{
				break;
			}
	
			// a request was just completed -- find out which one
			while($done = curl_multi_info_read($queue))
			{
	
				// get the info and content returned on the request
				$content = curl_multi_getcontent($done['handle']);
	
				$responses[$map[(string) $done['handle']]] = $this->parseHead($content);
	
				// remove the curl handle that just completed
				curl_multi_remove_handle($queue , $done['handle']);
				curl_close($done['handle']);
			}
	
			// Block for data in / output; error handling is done by
			// curl_multi_exec
			if($active > 0)
			{
				curl_multi_select($queue , 0.5);
			}
		}
		while($active);
		curl_multi_close($queue);
		return $responses;
	}
	
	function parseHead($headSream)
	{
		$headArrayTemp = explode("\r\n", $headSream);
		foreach ($headArrayTemp as $k=>$v)
		{
			if ($k==0)
			{
				$httpstas = explode(" ",$v);
				$headArray["http-edition"] = trim($httpstas[0]);
				$headArray["http-state"] = trim($httpstas[1]);
				$headArray["http-describe"] = "";
				for($i=2;$i<count($httpstas);$i++){
						$headArray["http-describe"] .= " ".trim($httpstas[$i]);
				}
			}
			else
			{
				if ($v == '')
				{
					break;
				}
				$headArray[strtolower(substr($v, 0, strpos($v, ':')))] = substr($v,strpos($v, ':')+1);
			}
		}
		
		return $headArray;
	}

CentOS下搭建SVN服务端

安装

yum install subversion

新建目录

mkdir -p /home/svn

新建项目

svnadmin create /home/svn/test

编辑配置文件
1. /home/svn/test/conf/svnserve.conf
将下列去掉注释:
anon-access = none
auth-access = write
password-db = passwd
authz-db = authz

realm = test

 

2. /home/svn/test/conf/passwd 添加账号密码

3. /home/svn/test/conf/authz 添加账号认证

具体案例看文章最后的附录

启动svnserver

/usr/bin/svnserve -d -r /home/svn/

加入到启动项

echo /usr/bin/svnserve -d -r /home/svn/ >> /etc/rc.d/rc.local

修改密码、添加新项目等都不需要重启svn进程;
上述test项目的默认svn地址为: svn://xxx.xxx.xxx/test (其中xxx.xxx.xxx为服务器ip)

附录:
svnserve.conf

### This file controls the configuration of the svnserve daemon, if you
### use it to allow access to this repository.  (If you only allow
### access through http: and/or file: URLs, then this file is
### irrelevant.)

### Visit http://subversion.tigris.org/ for more information.

[general]
### These options control access to the repository for unauthenticated
### and authenticated users.  Valid values are "write", "read",
### and "none".  The sample settings below are the defaults.
anon-access = none
auth-access = write
### The password-db option controls the location of the password
### database file.  Unless you specify a path starting with a /,
### the file's location is relative to the conf directory.
### Uncomment the line below to use the default password file.
password-db = passwd
### The authz-db option controls the location of the authorization
### rules for path-based access control.  Unless you specify a path
### starting with a /, the file's location is relative to the conf
### directory.  If you don't specify an authz-db, no path-based access
### control is done.
### Uncomment the line below to use the default authorization file.
authz-db = authz
### This option specifies the authentication realm of the repository.
### If two repositories have the same authentication realm, they should
### have the same password database, and vice versa.  The default realm
### is repository's uuid.
# realm = My First Repository

pass

### This file is an example password file for svnserve.
### Its format is similar to that of svnserve.conf. As shown in the
### example below it contains one section labelled [users].
### The name and password for each user follow, one account per line.

[users]
# harry = harryssecret
# sally = sallyssecret

root  = xxxxx

authz

### This file is an example authorization file for svnserve.
### Its format is identical to that of mod_authz_svn authorization
### files.
### As shown below each section defines authorizations for the path and
### (optional) repository specified by the section name.
### The authorizations follow. An authorization line can refer to a
### single user, to a group of users defined in a special [groups]
### section, or to anyone using the '*' wildcard.  Each definition can
### grant read ('r') access, read-write ('rw') access, or no access
### ('').

[groups]
# harry_and_sally = harry,sally

# [/foo/bar]
# harry = rw
# * =

# [repository:/baz/fuz]
# @harry_and_sally = rw
# * = r

[/]
root = rw

(r表示可读,w表示可写)

详解mysql数据库sql_mode模式

mysql可以运行在不同sql mode模式下面,sql mode模式定义了mysql应该支持的sql语法,数据校验等!

查看默认的sql mode模式:
select @@sql_mode;
我的数据库是:
STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
在此模式下面,如果插入的数据的长度大于定义的长度,那么就会报错!

set session sql_mode=’REAL_AS_FLOAT,PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ANSI’;
在这种模式下面:插入的数据的长度大于定义的时候,就会截取,并警告,但是可以插入进去
session表示只在本次中有效
global:表示在本次连接中不生效,而对于新的连接就生效

启用NO_BACKSLASH_ESCAPES模式,使反斜线成为普通字符,在导入数据时候,如果数据中有反斜线,启用这个模式是个不错的选择

启用PIPES_AS_CNCAT模式,将||看成是普通字符串

常用的sql mode:
sql mode值 说明
ANSI: ‘REAL_AS_FLOAT,PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE和ANSI组合’,这种模式使语法和行为更符合标准的sql
STRICT_TRANS_TABLES : 使用与事务和非事务表,严格模式
TRADITIONAL :也是严格模式,对于插入不正确的值给出错误而不是警告。用在事务时,只要发生错误就立即回滚

在Mysql5.0以下,默认的sql mode(sql mode参数)有:real_as_float,pipes_as_concat,ansi_quotes,gnore_space和ANSI。在这些模式下可以插入超过字段定义长度的数据,或是在字段中没有定义的元素数据(如,enum)。不过在插入后会有一个warning(可以用 show warnings来查看)。
在Mysql5.0以上版本中,有三种sql mode模式(ANSI、TRADITIONAL和STRICT_TRANS_TABLES(严格模式))可以用来解决以下问题:
(1). 通过设置不同的sql mode,可以在不同严格程序进行数据校验,有效地保证了数据准确性.
(2).通过设置sql mode为ANSI模式,来保证大多数SQL符合标准SQL的语法,这样在不同数据库之间迁移时,不需要对业务修改太多.
通过设置sql mode为STRICT_TRANS_TABLES(严格模式)来实现数据的严格校检,使错误数据不能插入,从而保证数据准确性。TRADITIONAL 模式也属于严格模式,同样可以实现严格校检,使错误数据不能插入,从而保证数据准确性。不过在这种模式MAX(X,0)返回的结果是NULL,所以在包含有MAX的运算中根据实际情况设定好sql mode.
ENUM是一个字符串对象,其值来自表创建时在列规定中显式枚举的一列值。在某些情况下,ENUM值也可以为空字符串(”)或NULL:如果你将一个非法值插入ENUM(也就是说,允许的值列之外的字符串),将插入空字符串以作为特殊错误值。该字符串与“普通” 空字符串不同,该字符串有数值值0。
如果将ENUM列声明为允许NULL,NULL值则为该列的一个有效值,并且 默认值为NULL。如果ENUM列被声明为NOT NULL,其默认值为允许的值列的第1个元素。
(1)sql mode为ANSI

mysql> create table test(id bigint(20) auto_increment primary key, browsertype enum('ie','firefox','other')); 
mysql> insert into test(browsertype) values('ie') ; 
Query OK, 1 row affected (0.07 sec) 
mysql> insert into test(browsertype) values('maxthon') ; 
Query OK, 1 row affected (0.03 sec) 
mysql> show warnings;(数据虽然成功insert,但有warning) 
+---------+------+--------------------------------------------------+ 
| Level | Code | Message | 
+---------+------+--------------------------------------------------+ 
| Warning | 1265 | Data truncated for column 'browsertype' at row 1 | 
+---------+------+--------------------------------------------------+ 
1 row in set (0.01 sec) 
mysql> select * from test; 
+----+-------------+ 
| id | browsertype | 
+----+-------------+ 
| 1 | ie | 
| 2 | | 
+----+-------------+ 
2 rows in set (0.01 sec)

(2)使用严格模式(STRICT_TRANS_TABLES)

mysql> set session sql_mode='STRICT_TRANS_TABLES'; 
Query OK, 0 rows affected (0.00 sec) 
mysql> select @@sql_mode; 
+---------------------+ 
| @@sql_mode | 
+---------------------+ 
| STRICT_TRANS_TABLES | 
+---------------------+ 
1 row in set (0.00 sec) 
mysql> insert into test(browsertype) values('maxthon') ; 
ERROR 1265: Data truncated for column 'browsertype' at row 1 

mysql> insert into test(browsertype) values('firefox') ; 
Query OK, 1 row affected (0.00 sec) 
mysql> select * from test; 
+----+-------------+ 
| id | browsertype | 
+----+-------------+ 
| 1 | ie | 
| 2 | | 
| 3 | firefox | 
+----+-------------+ 
3 rows in set (0.00 sec)

(3) TRADITIONAL模式

mysql> create table t11 (i int); 
Query OK, 0 rows affected (0.02 sec) 
mysql> set sql_mode='ANSI'; 
Query OK, 0 rows affected (0.00 sec) 
mysql> insert into t11 values(9%0); 
Query OK, 1 row affected (0.00 sec) 
mysql> select * from t11; 
+------+ 
| i | 
+------+ 
| NULL | 
+------+ 
1 row in set (0.00 sec) 
mysql> set sql_mode='TRADITIONAL'; 
Query OK, 0 rows affected (0.00 sec) 
mysql> insert into t11 values(9%0); 
ERROR 1365: Division by 0 
mysql> show warnings; 
+-------+------+---------------+ 
| Level | Code | Message | 
+-------+------+---------------+ 
| Error | 1365 | Division by 0 | 
+-------+------+---------------+ 
1 row in set (0.02 sec)