29
三/10
2

CodeIgniter 入门

终于花了1个半星期的时间看完了“CodeIgniter 1.7”这本书,300多页,不过内容还算丰富。从web开发的各个方面介绍了CodeIgniter这个PHP框架,章节的安排跟那本“Pro Drupal Development”类似。看完本书后,感觉codeigniter确实能弥补一些目前的PHP框架开发现状,目前来说基于PHP的CMS比较全,国外流行的有drupal,joomla,CMSMS等等,国内的就更数不胜数了。但提到framework,大家都想到zend framework,研究过一段时间这个框架,感觉过于庞大了,至于剩下的cakePHP,thinkPHP,国内的FleaPHP都没有涉及过,第一个接触的正式PHP框架(正式是针对drupal来说)就是CodeIgniter了。

使用drupal2年多,已经身心疲惫。总是感觉还不是那么的灵活,性能还不是那么的好,总想对它控制得更多,但我们能做的只有hook。不可否认,drupal在快速搭建一些中小型站点确实是不错的选择,模块很多,社区很活跃,但是如果用来开发一些大型的应用就显得力不从心了,比如我们开发一个万人活跃用户的SNS社区,一个多应用服务器架构的系统。drupal本身是面向过程的PHP通过HOOK机制组织起来的,这时我们就迫切需要一款MVC的面向对象设计的框架。codeigniter正是如此。

比较喜欢CI(codeigniter的简称)的一些设计理念,第一个就是从不强迫用户,CI为开发者提供了很多功能(helper,plugin,library等等),方便开发者,但它不强迫你使用这些功能,你完全可以自定义开发自己的功能模块,甚至可以很方便的集成第三方工具进来,不像drupal,你必须对drupal机制要很了解,才能做一些比较深入的工作。另外,CI的定制性很高,你可以参考CI的文档对其任意定制,足以迷惑用户是不是CI开发出来的站点。

网上有一个老外做的视频,20分钟用CI搭建一个blog系统,虽说有些夸张,但功能也太简陋了,不管是安全性还是UE都没有考虑太多,我做过一个测试,3-4个小时开发出来一套多用户blog系统是完全可行的。

此外,CI为我们提供了很多类库,涵盖的功能如下:

  • 文件下载
  • 邮件发送,可包含附件
  • 表单
  • FTP
  • 分页

。。。

CodeIgniter,值得学习。

11
十二/09
0

关于drupal架构的思考

自从drupalchina推荐我的blog后,很多drupal的开发者和我讨论drupal的性能,drupal的缺陷,大有感触。

很多人都说drupal站点不适合扩展,或者简单的做到数据库和代码分离后就茫然了。最近参考了很多软件和web架构的书,反过来对drupal这个系统做了一些关于架构扩展的思考。

以自己现有水平来看,drupal的瓶颈似乎在PHP代码执行层面。网上说使用APC加速可以大大加强drupal的性能,自己还没有手动进行测试,所以没有发言权。但目前在自己使用过程中,还是看到drupal一些小尴尬。

drupal的缓存系统比较简单,只是对匿名用户(因为匿名用户访问页面变更比较少)进行页面缓存,并且是以数据库的形式进行缓存。直接序列化页面到cache_page表中,这种性能可想而知,如果对百万级的访问量来说,db将会是个噩梦。

drupal用apache的rewrite模块实现了简洁链接,伪静态页面是提高了SEO效果,但是针对生成静态页面来说,还是比较困难的。另外,drupal的代码可以更加精简,否则为了强大的扩展性损失大幅性能也是不可取的。

有人说代码和架构扩展没有关系(忘记哪位大牛说的),其实我不是很赞同这句话,代码和数据库刚开始的设计决定或者制约了很多后面需要扩展的条件,比如水平划分数据库表的时候,最好是选取primary key,但是这个字段最好不是auto_increment的(道理很容易想到),再比如数据库抽象层的代码如果做memcache缓存,好修改吗?

很多时候,代码级别制约扩展性的很大一个因素就是联合查询,因为在做垂直划分数据库的时候,分离的都是一些关联性不大,并且不会牵扯到联合查询的库表,但drupal很多地方都使用的inner join(几乎每个模块都能看到)。当用户并发数越来越大,服务器最大的压力来源于数据库,这时,有些朋友就说了”负载均衡“啊。

没有那么简单,首先我们考虑基于重定向的负载均衡,多做几个后端服务器,使用RR或者简单随即抽取机制来轮流使用服务器,drupal和其他站点不同的一点小小特性就是唯一入口index.php,也就是说在这个文件我们可以写入一些代码,实现重定向的负载均衡,这点是比较合适的。或者您为了避免不是真正的压力平衡,可以使用DNS负载均衡,这样下来,稍微大点的数据量我们勉强顶得住了。

从水平划分的方面来看,首先最大的表应该是drupal的node表,nid字段是primary key,并且auto_increment的,这就很难进行分表存储。另外就算使用了一些别的算法,分N个表出来存储node,问题是如果使那些众多的node相关操作代码使用不会出问题?

另外一种做法就是使用ngnix的反向代理功能,很多java的开发者叫分布式。就算后端服务器性能差异,我们还是可以通过配置文件来决定权重,能者多得的方式,让每个机器发挥到极限。还可以考虑的方式就是使用apache加载我们定义的lua脚本,匹配select和insert,update,delete等字符串,用来区分属于何种sql查询,进一步实现读写分离。不过在机器之间的数据同步也是个麻烦的事情,我没有在运维方面有多少经验,最多就是使用过rsync。

分析种种情景,使用drupal的用户不要担心,只要我们想的到,可扩展的办法还是很多的。性能决定在你自己手里。

关键字:
5
十一/09
3

定制wordpress的文章发布

wordpress在发布文章的时候,已经集成了很多特性,比如tinyMCE这个可视化编辑器,文章标签(tags),别名(alias),以及分类(taxonomy)。但对于一个基于wordpress的项目,我们仍然需要对其高度定制,wordpress为我们提供了add_meta_box,来优雅的解决这个问题。

用起来比较简单,就6个参数,其中第三个参数为callback。我们可以在这个callback中设置一些输出信息,或者一个表单,最常用的还是后者。比如我们设置一个textarea的文本区域,用来保存一些用户输入的信息,这样用户发布这个post或者page的时候,这个信息就会保存到postmeta表里。其次,我们可以使用get_post_meta来获取这个数据。说到这里,有必要简单提下wordpress的表结构。

不像drupal那么复杂,wordpress主要的内容信息其实就两个表,一个post表,一个postmeta表,前者存放用户发布的基本内容,比如一篇blog,后者存放这个内容的一些附加信息,比如我们刚才定制的那个textarea。

最后,这里说下我碰到的一个问题以及自己的解决办法。在使用add_meta_box的时候,我们只是给post这个表单加入了一些输入控件,如果要处理文件的上传,或者使用curl等库来处理更高级的http操作,就出现问题了。因为form这个表单本身在wordpress中就定义好了,我们知道如果上传文件,form表单必须设置enctype = “multipart/form-data”属性,但默认的是没有的。google大叔告诉我很多人直接修改了wordpress的core,但我觉得这不是一个好的处理方式,我的解决办法是加入一段javascript来动态修改。
window.onload = function() {
var form = document.getElementById(”post”);
form.enctype = “multipart/form-data”;
};
这段javascript可以替换为更好的jquery代码,因为jquery等很多javascript类库已经集成到wordpress里面。目前能想到的就是这种方式,或许我还不够了解wordpress的机制?

关键字:
2
十一/09
0

初涉wordpress开发

近期涉及到wordpress-MU版本的开发工作,因为用户对其插件buddypress比较感兴趣。看了两天的文档,感慨wordpress文档的匮乏。。。

除了少的可怜的官方文档,基于codex系统,很多页面都没有书写外,自己down了一份plugin development的pdf,看完这个pdf才有点插件开发的感觉。写了4-5个小插件,熟悉了下wordpress的hook(wp中称作action和filter)。感觉还是不如drupal的模块优雅和灵活,但定制一个系统还是比较简单的,最大的痛苦就是wordpress的api函数太多,而很多都没有文档,不知道该如何选择,看了很多sample,用的还都不一样,版本之间留有差异性,不像drupal,5.x和6.x之间分别保持统一。

目前看来,一个buddypress新建一个用户,数据库中会多出8个表,这个恐怖的事实在网上已经有商业插件解决,不知道这个项目到底是怎么回事?
另外,视频方面采用了vimeo,开发和调试阶段颇为麻烦,因为国内的防火墙墙掉了很多应用,vimeo也不例外,使用vpn虽然解决了这个问题,但文档和wordpress一样少的可怜。

经过5天的google和编码,还算有点收获,过几天不忙了整理点文档共享给wordpress的插件开发者们。感慨:好的开源项目,如果文档不完善,依然是一件痛苦的事情。

关键字:
16
十/09
0

给drupal批量导入外部数据

很多时候,我们想给自己的drupal站点批量导入节点数据,其中包括很多方法,例如csv格式文件的导入,通过别的站点抓取到得信息,整合别的系统时,相互数据的迁移都要用到这些内容。我们建立一个简单的模型,只考虑节点基本数据,不考虑其他因素(比如节点图片,节点术语分类等等),将模型简单化有助于我们解决问题。

以拿抓取页面为例,我们使用正则表达式过滤出需要的信息后,将其存放在一个一维关联数组中,其中键对应数据库中的节点字段,比如title,body,name。。。然后我们手动调用node_submit方法,将一维数组传进去,这个方法会对我们的数组做一些存表之前的工作,我们直接可以在api.drupal.org查看这个方法的代码。

<?php
function node_submit($node) {
  global $user;

  // Convert the node to an object, if necessary.
  $node = (object)$node;

  // Auto-generate the teaser, but only if it hasn't been set (e.g. by a
  // module-provided 'teaser' form item).
  if (!isset($node->teaser)) {
    $node->teaser = isset($node->body) ? node_teaser($node->body, isset($node->format) ? $node->format : NULL) : '';
  }

  if (user_access('administer nodes')) {
    // Populate the "authored by" field.
    if ($account = user_load(array('name' => $node->name))) {
      $node->uid = $account->uid;
    }
    else {
      $node->uid = 0;
    }
  }

  $node->created = !empty($node->date) ? strtotime($node->date) : time();

  // Do node-type-specific validation checks.
  node_invoke($node, 'submit');
  node_invoke_nodeapi($node, 'submit');

  $node->validated = TRUE;

  return $node;
}
?>

除了一些数据的可用性检查外,该方法调用了所有实现submit和nodeapi中实现submit的函数,之后就简单了,再调用node_save即可。

关键字: