-
个人简介:
PHP开发者,高可用性、分布式集群实践者,伪Python、GAE开发者,伪Linux系统管理员,伪MySQL管理员
2009年8月至今服务于阿里巴巴云计算公司
2008年8月至2009年7月31日服务于博客大巴
-
归档
- 2012 年一月
- 2011 年十一月
- 2011 年九月
- 2011 年八月
- 2011 年七月
- 2011 年六月
- 2011 年五月
- 2011 年三月
- 2011 年二月
- 2011 年一月
- 2010 年十二月
- 2010 年十一月
- 2010 年十月
- 2010 年九月
- 2010 年八月
- 2010 年七月
- 2010 年六月
- 2010 年五月
- 2010 年四月
- 2010 年三月
- 2010 年二月
- 2010 年一月
- 2009 年十二月
- 2009 年十一月
- 2009 年十月
- 2009 年九月
- 2009 年八月
- 2009 年七月
- 2009 年六月
- 2009 年五月
- 2009 年四月
- 2009 年三月
- 2009 年二月
- 2009 年一月
- 2008 年十二月
- 2008 年十一月
- 2008 年十月
- 2008 年九月
- 2008 年八月
- 2008 年七月
- 2008 年六月
- 2008 年五月
- 2008 年四月
- 2008 年三月
- 2008 年二月
- 2008 年一月
- 2007 年十二月
- 2007 年十一月
- 2007 年四月
-
杂项
标签归档:PHP
利用CodeIgniter缓存进行攻击
CI自带的缓存系统确实很方便,但她存在一个很大的弊端,看缓存系统的源码: CI把md5(index.php+uri_string)作为缓存文件名(没完全copy,详见libraries/output.php) 这个uri_string允许URI串夹杂垃圾信息,比如: http://ci-site.com/index.php/index/index/1 http://ci-site.com/index.php/index/index/1/2 http://ci-site.com/index.php/index/index/1/2/3 上面三个请求,CI将生成3个不同的缓存文件 问题来了,假如攻击者写一个并发访问脚本: 每秒并发访问100次(任何adsl用户都有足够带宽发起攻击) 循环访问 index.php/index/index/1 至 index.php/index/index/10000000 那么服务器将生成一千万个首页垃圾缓存,在同一个目录里面! 假如你的网站首页html有10kb(一般来讲,10kb作为首页不算大) 这个缓存目录的尺寸将达到:10kb x 10,000,000 = 100GB 完成攻击所需时间:大约27小时 更重要的是CodeIgniter本身并没有提供更详细的缓存检测机制和缓存容量限制机制,加入你没有对cache目录进行磁盘配额限制的话,那么一轮并发高的缓存攻击将有可能将硬盘塞满,之后网站就会变得异常缓慢。而且更要命的是CodeIgniter本身没有缓存清除机制,只能干等着缓存过期或者手动清除,CodeIgniter最大的优势在于它的性能和学习曲线。 总觉得CodeIgniter本身就是一个半成品,没有缓存清除机制也就算了,还没有模块化缓存(即只缓存页面某个或者某几个部分)的的机制,CodeIgniter这么优秀的Framework在缓存方面算是做得很失败了,不过得益于它优秀的扩展性能,仍然有很多解决方法,况且任何Framework都不是完美的。 解决CodeIgniter大体上有四种方法 1)关闭缓存,我觉得这基本上算不得一种解决方法,因为这牺牲了网站的性能 2)架设缓存服务器,对于一般的中小型网站来说这也比较奢侈,且不说squid或者vanish的学习曲线有点长,也没与服务器设备。 3)增加严格的检测机制,这是一个非常可行的方案,比如对URI每个传入参数的类型进行严格的验证,在一个页面显示前进行详细的处理,比如ID为10000的记录数据库中根本不存在,那么使用show_404()方法输出404页面,这个页面并不会被缓存,假如没有增加这个验证,程序输出的页面将会被缓存,只是页面的某个区域的内容为空而已。比如显示文章的区域是空,侧边栏和头部都是从模板中继承过来了,仍然被缓存了。 4)使用其他cache类替代CodeIgniter的缓存类,比如APC
Zend Framework学习笔记(二)
很多天没再研究Zend Framework了,趁着还有些闲时间,再次研究一下,Zend Framework学习笔记(一)中大概了解了一下Zend Framework的代码接口分布,《Zend Framework in Action》一书中给出的标准文件夹结构如下图: 个人觉得这个结构只适合很小的项目或者不太复杂的项目,因为zend Library是包含在项目里面与web_root同一级,假如我需要创建一个helloword_2的项目,那么不得不再复制一个同样的文件夹结构,Zend Library将会有两份,如果有十几个或者更多的这样的工程,那么Library将会有很多,Zend Framework是个很活跃的框架,没准哪天就升级了好几个版本,如果你需要升级或者打补丁,那么就会烦死。 当然在application下新建一个modules文件夹,将各个功能放在这里也是一个方法,但是你肯定不想一堆一点关联都没有的项目堆在一起,比如豆瓣的九点和群组,这两个几乎没有任何关联,当然实际应用中还有一个非常重要的用户模块。每个应用只做自己该做的事情,才会最大限度的独立很分散,无论是为了负载均衡进行多点发布还是代码维护都非常有用。而且所有的应用都通过一个入口(web_root中的index.php)和同一个分配器来处理,显然并发能力和容错能力都会下降,稍微有点差错,所有的应用都挂了。入口,分配器等属于全局的东西会影响所有应用,事实上可能很多东西对别的应用毫无用处,但是又有很多应用又需要,这时候就产生了浪费。 不过Zend Framework是个自由度很高的框架,可以自己定义一些东西,让Library从项目中独立出来,与项目目录平级,每个项目拥有自己的独立名称、web_root、入口和分配器,这样做可以为每个项目单独添加Vhost,升级内核(zend Library)也只要升级一个即可,有更高的自由度和松散度。所以我推荐如下的结构: 图中的test是一个项目名,请注意是项目名,不是功能名称,在application中你可以为这个项目建立很多modules,我在图中没有建立这样的文件夹,你可以建立test2,test3……项目,这些项目毫不相关,或者关联度很低,比如用户就得是一个独立的项目,其他的功能可能是一个或者几个独立的项目,事实上还有更好的目录结构,我是从神仙那里学过来的.在controllers文件夹中建立front, backend, amdin,三个文件夹,在view中也建立对应的文件夹,放在front中的内容不做任何限制,backend中需要登录,admin就不用说了,渲染views中对应文件夹的模板,全局进行权限控制,似乎神仙这样的结构不能提供精细访问权限,zend Framework提供了这样的精细权限控制。 如果你的代码要改成左图的结构,需要改动一些代码,首先是需要在入口文件中注册这些目录的位置代码如下: define(’APP_PATH’, dirname( dirname ( __FILE__ ) ) ); define(’LIB_PATH’, dirname( APP_PATH ) . "/library"); date_default_timezone_set(’Asia/Shanghai’); //directory setup and class loading … 继续阅读
无知害死人
最近我接连犯了两个比较重大的失误,非常的低级,低级到我无法原谅我自己。 一个是数据删除操作,因为采用全新的框架,不是很熟悉流程,所以在删除前进行了一些断点测试,查看参数调用情况,一直跟踪到核心代码,最后一次测试的时候,字段名没有传入,事实上这完全是我的故意,因为我想知道,字段名没有传入到底框架会给出什么样的错误提示,写了一个这样的SQL语句 DELETE FROM post WHERE ’123456′ AND ‘ 456789′ 这是执行这个语句花了一份多钟,我还以为发生错误了,因为是周六晚上调试的,周日早上睡大觉,运营的同学打电话给我们系统管理员,很多用户反映日志丢失了,我猜想我完了,就昨天我发布了新的功能,因为周末太闲。在mysql 的bin log中查到一条类似如上的SQL语句,转念一想,这个WHERE根本就没用,没有字段的where查询,后面都是true,相当于: DELETE FROM post WHERE true AND true 执行了之后的结果是,整个表被清空!还好我们采用的是分库分表的策略,我删除的不过几百个表中的一个,丢掉近一万个用户数据,最后劳烦我们万能的系统管理员花开同学 从备份中给找回来了。这其中得到神仙的协助, 虽然没有任何人批评或指责我,我永远记得这个教训。 第二个是关键词匹配系统,主要用来查找包含关键字的垃圾文章(spam)。这个是写的第一个完全不需要模板的程序,说白了,就是命令行运行的东西,但还算不上真正意义上CLI程序,关键字存在一个表的一个字段中,以回车分割每个字符,这个是通过另外的一套WEB界面输入的,我提取关键词的方法是explode(‘\n’, $str),结果运行了好几十次,查到的匹配文章少的可怜,今天晚上(2009-03-10)老魏告诉我,每天的spam远远大于我查找的数量,我查到的几乎可以忽略不计,这下我汗颜了,我一直以为是我们所有的用户都非常纯洁,所以才只有那么几个spam,原来是我程序出问题了,之前我都是直接增加一个常用的词进行测试的,比如“的”,查找非常准确,所以我深信我的程序没有问题,最后在刚哥(我刚到Bus时被指定的师傅,一位做了8年开发的牛人)的排查下,原来是windows下的换行和Linux下的换行根本就不是一回事,windows下是以 \r ,Linux下是\n,在将每个关键字trim一下之后,搜20个表就搜了近千篇垃圾文章。 我应该好好检讨我自己,无知有时候真的会害死人,因为不知道,所以死了也不知道怎么死了!
Zend Framework学习笔记(一)
1、请求 ,Zend_Controller_Request_Http 类提供了整个的HTTP访问需要的环境。 2、路由 ,路由特性是由 Zend_Controller_Router_Interface实现的,由Zend_Controller_Router_Rewrite提供URL重写功能。 3、分配器 ,Zend_Controller_Dispatch_Standard类控制 4、Actiong ,所有的动作都是源自于Zend_Controller_Action这个抽象类,Zend_Controller_Action提供了两个级别的处理请求,一个是init(),另外一个是preDispatch() init()函数是在控制器被调用的时候触发的 ,如果该控制器被调用多次,那么preDispatch()将被调用多次,而init()只调用一次。 5、Response(响应) Zend_Controller_Response_Http 是为编写web程序准备的 Zend_Controller_Response_CLI适应更多的场合 Zend_Controller_Response_Http包含三种信息:header,body和exception(异常) 6、Front Controller Plug-ins(前端控制器插件) 所有的插件都实现于Zend_Controller_Plugin_Abstract这个抽象类,一共有六个事件方法可以被重写。 1)routeStartup() 2)dispatchLoopStartup() 3)preDispatch () 4)postDispatch() 5)dispatchLoopShutDown() 6)routeShutDown()
PHP服务器变量$_SERVER详解
1、$_SESSION['PHP_SELF'] — 获取当前正在执行脚本的文件名 2、$_SERVER['SERVER_PROTOCOL'] — 请求页面时通信协议的名称和版本。例如,“HTTP/1.0”。 3、$_SERVER['REQUEST_TIME'] — 请求开始时的时间戳。从 PHP 5.1.0 起有效。和time函数效果一样。 4、$_SERVER['argv'] — 传递给该脚本的参数。我试了下,get方法可以得到$_SERVER['argv'][0];post方法无法给他赋值。 5、$_SERVER['SERVER_NAME'] — 返回当前主机名。 6、$_SERVER['SERVER_SOFTWARE'] — 服务器标识的字串,在响应请求时的头信息中给出。 如Microsoft-IIS/6.0 7、$_SERVER['REQUEST_METHOD'] — 访问页面时的请求方法。例如:“GET”、“HEAD”,“POST”,“PUT”。 8、$_SERVER['QUERY_STRING'] — 查询(query)的字符串(URL 中第一个问号 ? 之后的内容)。 9、$_SERVER['DOCUMENT_ROOT'] — 当前运行脚本所在的文档根目录。在服务器配置文件中定义。 如E:\server 10、$_SERVER['HTTP_ACCEPT'] — 当前请求的 Accept: 头信息的内容。 … 继续阅读
为什么要做持久化和ORM设计
在目前的企业应用系统设计中,MVC,即 Model(模型)- View(视图)- Control(控制)为主要的系统架构模式。MVC 中的 Model 包含了复杂的业务逻辑和数据逻辑,以及数据存取机制(如 JDBC的连接、SQL生成和Statement创建、还有ResultSet结果集的读取等)等。将这些复杂的业务逻辑和数据逻辑分离,以将系统的紧耦合关系转化为松耦合关系(即解耦合),是降低系统耦合度迫切要做的,也是持久化要做的工作。MVC 模式实现了架构上将表现层(即View)和数据处理层(即Model)分离的解耦合,而持久化的设计则实现了数据处理层内部的业务逻辑和数据逻辑分离的解耦合。而 ORM 作为持久化设计中的最重要也最复杂的技术,也是目前业界热点技术。 简单来说,按通常的系统设计,使用 JDBC 操作数据库,业务处理逻辑和数据存取逻辑是混杂在一起的。 一般基本都是如下几个步骤: 1、建立数据库连接,获得 Connection 对象。 2、根据用户的输入组装查询 SQL 语句。 3、根据 SQL 语句建立 Statement 对象 或者 PreparedStatement 对象。 4、用 Connection 对象执行 SQL语句,获得结果集 ResultSet 对象。 5、然后一条一条读取结果集 ResultSet 对象中的数据。 6、根据读取到的数据,按特定的业务逻辑进行计算。 7、根据计算得到的结果再组装更新 … 继续阅读
When you get troubles
Read the official document of each software Search by using Google Read the error messages from screen and log files carefully, try to understand them Use your head to think and use your hand to do it
PHP设计模式–单列模式
关于单列模式: BookSingleton.php 单列模式可以将其本身的实例分配到其他的类中。 //copyright Lawrence Truett and FluffyCat.com 2005, all rights reserved class BookSingleton { private $author = ‘Gamma, Helm, Johnson, and Vlissides’; private $title = ‘Design Patterns’; private static $book = NULL; private static $isLoanedOut = FALSE; … 继续阅读
【翻译】PHP设计模式手册与实例—抽象工厂
关于抽象工厂 在抽象工厂设计模式中,抽象工厂决定了什么样的对象是非抽象的,哪些具体的工厂需要被创建。 具体工厂必须建立正确的对象的范围,确保所有被具体工厂所创建的对象能够在给定条件下正常的工作。 在这个例子中我们有一个抽象工厂 AbstractBookFactory,指定的两个类AbstractPHPBook和AbstractMySQLBook ,他们需要具体工厂来创建。 实例类OReillyBookfactory继承自AbstractBookFactory,并且可以创建OReillyMySQLBook 和 OReillyPHPBook类。 AbstractBookFactory.php //copyright Lawrence Truett and FluffyCat.com 2007 abstract class AbstractBookFactory { abstract function makePHPBook(); abstract function makeMySQLBook(); }
正则表达式入门之顺序环视(lookahead)
在 以前的编码过程中,总是遇到货币数值的问题,比如¥10000000,根据习惯,¥10,000,000更容易阅读,我从前的做法很复杂,要先计算字符串的位数,然后根据位数再决定将第一个逗号放在第一位数字后面还是第二、第三位,后面的数字每个三位加上一个逗号,最后一位不加逗号,设计如此复杂的算法的原因是我没办法,像手动添加逗号一样,自右向左添加每三个数字添加一个逗号,当然也可能是我愚钝,高人会有更好的解决方法。如果您刚好知道一个更好的算法,请告诉,我会感谢您的。 正则表达有个叫lookahead的东西,我也不知道为什么翻译成顺序环视,姑且就这么叫吧,知道是这么回事就行了。顺序环视是自左至右查看文本,尝试匹配子表达式,如果能够匹配,就返回匹配成功信息。顺序环视又分为肯定型顺序环视和逆序环视,解决上面问题,当然是用到逆序环视了。 肯定型顺序环视用的特殊序列是:?=……来表示,省略号表示需要匹配的内容,匹配的顺序是习惯性匹配即自左向右,例如:?=\d,它表示如果位置右边的字符是数字则匹配成功,另一种环视的特殊序列是:?<=……来表示,例如:?<=\d,它表示如果当前位置的左边有一位是数字则匹配成功. 现在来解决本文开始部分提出的数字问题,代码段如下: /(?<=\d)(?=(\d{3})+\b)/,/g 对代码段解释如下: (?<=\d)是要限定匹配的位置,保证数字字符串刚好是3的倍数的时候不会出现 ,200,000 这种情况,即逗号的左边是必须有数字的 (?=(\d{3})+\b)是查询每个三个数字的位置,有意思的是段不匹配任何文本,而只是匹配一个位置,所以如果你试图输出每个匹配,那么显示的结果将是NULL g表示全局替换,跟i表示忽略大小写一样的用法 顺序环视还有其他的内容,我们这里只用到肯定逆序环视和肯定顺序环视,还有否定逆序环视和否定顺序环视,读者可以举一反三,从名称上揣测他们的用法,顺带着找一些资料阅读下便可,这里不再赘述