PHP开发者经常会犯的另外7个错误

本文原始链接:7 More Mistakes Commonly Made by PHP Developers。作者:Bruno Skvorc

Thanks for Sitepoint.com authorization for translation and publication in my blog.

本文翻译力求忠实原始文档。

==========译文开始分割线==============

在6月的时候,TopTal(自由编程人员市场)发表了一篇文章,题为《PHP程序员最常犯的10个错误》。那个列表当然不是穷尽的,但确实写得不错,并指出了一些非常有趣的、值得每个人关注的陷阱——即便如我个人都不会将这些错误认为是很常见的。

我希望你对这篇文章加以通读——其中有一些确实很有价值的、你需要知道的信息,特别是前八个要点。几天前,Anna Filina扩展了这个列表,并加入了七个新的项目。尽管这些地方不那么特定也不那么常见,她的观点还是有分量的,需要在开发时加以考虑。

PHP开发者经常会犯的另外7个错误

TopPal中某位仁兄请我看看他们的列表,还有没有补充,社交网络上的一些粉丝也表示有兴趣看到这个列表继续。所以,我愿意借此机会在这个列表中加入我自己的一些事项。这些都是我不断需要去警示我的团队或者粉丝们的。

  1. 使用mysql扩展

这个消息其实很旧了,但是尚未注意这个事实的开发者数量还是大到令人担忧。如果用到SQL数据库,特别是MySQL,有太多的开发者还是倾向于使用mysql扩展。这个扩展已经官方认定过时。它不安全,不可靠,不支持SSL,不支持MySQL中的一些现代特性。它也会产生过时提醒,出现在你的应用的最顶部——但不会中断应用。滑稽的是,这意味着我们可以简单地Google这个关键词,就能找到大量这样还是用着这一不安全设置的站点。因为这个,这些应用所面对的伤害是令人震惊的。

避免使用mysql,我们可以选择:MySQLi或者PDO。例如,使用MySQLi简单到几乎只要在API调用后加一个“i”即可:

$c = mysql_connect(host, user, pass);
mysql_select_db(database);
$result = mysql_query(SELECT * FROM posts LIMIT 1);
$row = mysql_fetch_assoc($result);

对比:

$mysqli = new mysqli(host, user, pass, database);
$result = $mysqli->query(SELECT * FROM posts LIMIT 1);
$row = $result->fetch_assoc();

使得我们的设置变得更安全,所要做的就是这些。 不过你应该选择PDO。详见第2点。

  1. 不使用PDO

不要误会,mysqli确实(确实确实)比古老的mysql扩展超出了好几代。它更新及时,安全,可靠,快速。但是,它只适用于MySQL。使用PDO可以让你使用一些美妙而实用的面向对象语法,也能让你做好准备使用另外的SQL数据库(如PostgreSQL,MS SQL以及其它)。另外,PDO可以让你使用命名参数。这一特性非常有用,只要充分利用它带来的好处,就很少有人能想象不这么做。最后,还有这点:你可以直接将获取的数据注入到一个新对象中,对于大项目而言,这能节省时间,而且是令人愉悦的。

  1. 不重写URL

这是一个常常被忽略却也容易修正的问题。诸如myapp.com/index.php?p=34&g=24这样的URL如今简直就是不能被接受的。由于几乎不可能写出一个好的URL重写规则来涵盖每个服务器和框架,几乎每个框架都有一个指南,告诉我们如何设置干净的URL(Laravel, Phalcon, Symfony, Zend)。如果哪个框架不这么做,那么它就不值得我们使用——这些框架显然不关注现代化的实践。

  1. 抑制错误提示

我在以前的一篇文章中写过这个问题,但还是有必要再说一说。任何时候你发现自己使用@运算符,请再考虑考虑,尝试从另一个角度更认真地处理这个问题。用我的话来说,在一个应用的功能中包含20行引用的cURL代码也比单单一行前放一个@来的好。

我个人的经验告诉我,我在原来的帖子中建议的方法是一个好方法:打开所有的提示并转化其为致命错误。要确保在错误日志中没有任何记录,因为确实没有要记录的东西要比用@遮在眼前,装作看不见有错误发生要好。

最近我们发现了一些Heroku add-ons可以用来开发生产环境下的PHP应用,其中一个Papertrail很棒。这个add-on让你将应用所有的错误推送到后台,从而可以轻松的加以搜索、分组并在日后加以清除。所以,即使真的有错误发生,让它们被记录下来,然后通过修订代码来消除错误。这比抑制它们,愚弄你的用户来的好。

  1. 条件判断中的赋值

即使再有经验的程序员有时也会手指一滑,写下if ($condition = 'value') {而不是if ($condition == 'value') {。我们的手会打滑,键盘可能没有记录按键,我们从代码的另一部分——那一部分确实进行的是赋值操作——拷贝了代码。这些都有可能,而我们只有在运行应用时才发现问题。

要完全避免这个问题,有几个方法:

  • 使用一个好的IDE。任何好IDE(比如PhpStorm)会在检测到这一问题时警告说”条件判断中进行了赋值“。
  • 使用“Yoda Conditions”。在众多流行项目,甚至大型框架中,都会看到这个应用。通过交换比较双方(if ('value' = $condition) {),即使比较弱的IDE也能注意到这个问题。有人认为Yoda语法很讨厌而且毫无意义,其信条是绝不使用(“更小心地编码,蠢货!”)。单就个人而言,如果能帮到你的话,我是建议使用的。如果我们都是优秀人物,那么WordPress和Zend Framework就不会存在了。
  • 牢牢记住,每次写的时候都要检查一次。所要的知识练习,但即使对于最好的开发人员而言,这也可能发生。所以前两点会有用。
  1. 太透明了

我这么说可能会有反对意见,不过我还是要说。除非你对框架的开发者有100%的信心,或者也不运行高利润、高流量的商务关键应用,你应该总是努力隐藏你的后台——不要告诉大家你的应用基于什么框架。这实际上能对防止攻击起到作用——如果发现了该框架的一个安全漏洞的话。例如:

If you use Symfony2 translator and have a route with a {_locale} parameter upgrade NOW http://t.co/jihXHB8MzT— Jérémy DERUSSÉ (@jderusse) July 15, 2014

在该Tweet中,有关代码注入的一个严重问题已经变成了广为人知的知识。如果你正在上班,可以立即升级而不用担心开发问题或者让团队停止,那很好。但是对大部分使用Symfony的人和公司而言,情况不是如此。即便Symfony可以通过Composer升级(如Ryan在评论中提到的那样),在大的多层环境的团队中,通常这要花一些时间来获得批准。所有使用这一翻译机制的站点,并且也声明了是Symfony的用户的站点,就会面临该缺陷,直到被修正。

上面提到的使用Symfony,只是一个例子。多年来,类似的情形发生在无数其它的软件中。我还在使用ZF框架开发商业应用那会,也发生过这样的情况,并因此受到了攻击。WordPress也有其安全性漏洞,而我们也知道世上有多少站点是由它来运行的。会发生这些事情。有时,开源和透明不是最好的方法来处理那些承担公司主要收入来源的应用。

  1. 没有移除开发配置

最后,我要提一提移除开发配置。最近(声明,我再次提到Symfony纯粹是巧合),Cnet遭受了一次攻击,原因就是没有移除它们的开发配置。

Uhmmm no: http://t.co/rAQis1ycWq #security #symfony— Marco Pivetta (@Ocramius) July 15, 2014

Cnet是全球最大的技术新闻站点之一,它基于Symfony。你可能知道,Symfony有两个应用入口:app.php和app_dev.php。你的浏览器访问其中之一,进入的是生产环境,如果访问带有_dev后缀的那个,显然你会进入开发环境,从而有除错器、敏感数据以及诸如此类。这样是好是坏可是很多讨论的话题(再次感谢Ryan指出了这点)。但无可否认的是,它让一些比较笨拙的开发者面临着Cnet面临的同样的错误。另外,通过app_dev访问的任何其它URL也会导向其它的app_dev相关的URL。换句话说,不仅是首页在开发环境下运行,而是整个站点——放在Cnet的案例中,这可是大量的访问。

如果你跟踪了Twitter上的讨论,情形很快就糟糕到令人尴尬——而更可悲的是,只要几秒钟的工作就可以避免:

  • 开发者应该在生产用服务器中删除app_dev.php
  • 开发者应该将可以访问app_dev.php的IP放入白名单,这也是缺省配置——除非你故意放松了这些限制

任何一个方法都可以完全避免所有的问题。记住,在发布到生产环境时,要确保你的开发配置要么完全不可访问,要么只有在白名单中的IP可以访问。

结论

(本文收录于[go4pro.org])

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *