Author: qingbo

  • 关于CrucialWebHost

    Crucial Web Hosting实际上是我尝试的第一家也是迄今为止唯一一家国外空间商。当时本来想在dreamhost, hostgator之类的里面挑一个的,正好CrucialWebHost做推广,价格非常优惠,$7.95/mo,然后还有优惠券,最后似乎是花了700多买了两年。最重要的是带有独立IP,这在其它空间上那里得每月几美元。

    我不知道RatePoint是一家什么样的网站,不过上面关于CrucialWebHost的评论全部是溢美之词,这也迷惑了我好一阵子。在我使用该空间一年多的时间里,空间商两次更改IP而不通知客户,每次都是发现不能访问之后与之联系才得知IP更换。他们的理由是客户应该使用他们的DNS Server,然而其管理功能极弱,自己不能随意修改A/CNAME等记录,只能通过技术支持修改。虽然他们非常乐意为你效劳,但我相信没人愿意这么麻烦……

    2008年9月24日,我的网站在访问时出现错误:

    Table ‘xxx’ was created with a different version of MySQL and cannot be read

    赶紧与客服联系。答曰,正在升级服务器的MySQL. 真让人无语。

    后来又有一天,我有个使用mysqli的小程序出错了,mysqli无法加载,与客服交流后被告知:他们正在编译该模块。

    When Dependability is Crucial Depend on Crucial Web Hosting, Ltd.

    这句话出现在每个技术支持邮件的末尾,颇具讽刺意味。

    在我买了空间不久,价格便暴涨到$25/mo,当然,涨价是不能指责人家的,他们也要活命嘛,以后买不起搬走就是了。不过最近我发现原来许多的条款例如无限个域名绑定,无限子域名,无限FTP账户都改了,有图为证:

    quota

    你可以到他们网站看最新的参数,对比2007年12月31日的样子。感谢archive.org!

    另外该空间商跟Magento不知道是什么关系,几乎在倾力为Magento hosting打造空间,官方blog的大部分文章都是关于这个的。

    总之,感觉有点失望。什么split-shared,什么crucial,都是狗屁。

  • 转让国内1000M主机空间

    年前买了捌号主机的1000M PHP空间,本来想做个小网站玩玩的,不过事情不太顺利。您也知道,在我们文明的法治国家,做什么都得有个license,我的license就迟迟没有到手,相关部门的电话也是相当的热门,永远也打不通。每当想到这些,我脑海中都涌现出他们伟大的爷爷奶奶爸爸妈妈们,可是不知道从谁开始问候,就一切尽在不言中了。

    正好又赶上了深受广大网民拥护的整治互联网低俗风系列活动,我深怕我的内容不能摆脱低俗之风,毒害“生活在懵懂之中的青少年”,遮挡住“幸福的曙光”,于是下定决心,牺牲我一个,幸福千万家,为营造一个“窗明几净的网络空间”做贡献。

    现转让该PHP空间,08年12月20号买的,现在刚好还剩10个月,买的时候是398元,现在200元转让。空间的具体参数在捌号主机网站上可以查看

    最好通过淘宝交易:商品链接

    旺旺不在线时,可以发电子邮件:email
    本人开机即随时收邮件,反应速度足够快……

  • WordPress 2.7评论CSS解惑

    WordPress 2.7内置了threaded comment,评论的class name也变得非常繁杂。Betty给出了一张WordPress 2.7 评论结构一览图,但是我想许多人大概还不知道某些class name的规则是什么样的。

    这里只说每条评论上添加的class name,总结一下,有这么多:

    comment, trackback, pingback, 这三个不用多说,用来区分评论类型,方便用CSS样式来区分不同类型的。它们互相排斥,所以要想三个有统一的样式,就得这么写规则:

    [code lang=’css’]ol.commentlist li.comment, ol.commentlist li.pingback, ol.commentlist li.trackback {

    }[/code]

    byuser, comment-author-*, bypostauthor. 如果评论者是注册用户,会加上byuser和”comment-author-[nickname]“两个类,这样可以区分注册用户与非注册用户,甚至可以根据用户的不同呈现不同的样式。如果评论者是文章的作者,还会加上一个bypostauthor,这个最重要,很多blog用来突出显示文章作者的评论。

    odd, alt, even. 评论的交替样式。评论从0开始计数,奇数时是odd, alt,偶数时是even. 注意,odd和alt两个类必然同时存在。一般情况下,根据odd, even来写CSS,另一种方式是根据有无alt这个类来写,两种方式选择其一即可。还要注意计数的顺序是按照“前序遍历”,具体可参考文章“WordPress 2.7自定义单条评论结构”中的图片。因此你不能保证这个thread(顶级评论)是奇数,下一个thread就是偶数。

    thread-odd, thread-alt, thread-even. 和odd, alt, even类似,不过只计顶层评论。

    depth-[number]. 表示评论嵌套的深度,顶层评论的class是depth-1,向下递增。可以根据这个调整输入框大小,以我的为例:

    [code lang=’css’]#comment {
    width: 530px;
    border: 1px solid #C4EF95;
    font-size: 12px;
    }
    .depth-1 #comment {
    width: 470px;
    }
    .depth-2 #comment {
    width: 410px;
    }
    .depth-3 #comment {
    width: 350px;
    }[/code]

    parent, 有回复的评论会加上这个class.

    应该就是这些。

    最后我想说,要是再有两个depth-odd, depth-even就好了。我想实现的效果是顶层评论背景色交替,每个thread里面不同深度的嵌套回复背景色也要交替。没有这两个类,我就只好用depth-1, depth-2裸写,写到我限制的深度就行了。有兴趣的可以看看我的style.css.

    以上的逻辑查看wp-includes/comment-template.php即可得知,关键是get_comment_class函数。

  • JavaScript性能相关资源

    客户端应用程序的日益丰富越来越显示出JavaScript的性能劣势,由于这种语言太大的灵活性,大多数实现都是解释器类型,性能都不会太好,人们甚至怀疑基于JavaScript的重量级web应用是否还有前途。好消息是Google Chrome的JavaScript引擎是一个虚拟机叫做v8,Firefox 3.1将会把原来的SpiderMonkey替换为更强大的TraceMonkey,一个应用JIT技术的引擎。

    但是Chrome才刚刚出现,Firefox所占的市场份额也还不足够让人把它当作准绳。我们时时得考虑古老、陈旧、笨重的Internet Explorer,至少我们还没看见IE8的JavaScript实现有任何值得欢呼的线索。

    即使所有浏览器都有了高效的实现,注重代码本身的性能依旧是一个好的习惯。写出优质的代码,比把劣质的代码扔给编译器/解释器去优化好得多,即使编译器/解释器的优化很强大,因为起点不一样。

    下面是一些对了解JavaScript性能有帮助的一些资源:

    • IE Blog里关于JS性能的文章,我建议新手先不要看IE/JScript Blog里的东西,他们经常会拿出自家的一些私藏来招待你。是的,IE没有实现JavaScript,他们实现的是一个叫JScript的东西,看起来跟JavaScript有点像。

      IE + JavaScript Performance Recommendations – Part 1 变量使用的建议,你会看到,解释器不会做一丁点的优化,一些看似无用的多余代码可能会帮助你改善性能。
      Part 2: JavaScript Code Inefficiencies 关于字符串拼接,eval和switch.
      Part 3 提到一点内存泄漏问题。

    • jQuery的作者指出提高客户端性能的工作不仅存在于JavaScript本身。
      JavaScript Performance Stack
    • When innerHTML isn’t Fast Enough 我们知道如果有一大堆HTML要插入DOM,innerHTML方式要比document.createElement然后插入快得多。这篇文章给出一种比innerHTML更快的方式。
    • Comet Information Systems写的系列文章:

      String Manipulation 字符串拼接
      DOM Manipulation innerHTML, createElement, cloneNode.
      General Tips

    • 对于编译器来说,循环不变量外提是最基本的优化之一,然而你可不要认为JavaScript解释器也会为你做这个:
      JavaScript loop performance
    • 微软曾经针对IE推出一个自动更新,声称内存泄漏得到了解决,一时间开发者们欢欣鼓舞。但是马上人们就发现了问题,和他们在blog里的惯用手法一样,这只不过是掩人耳目,夸大其词。

      IE’s Memory Leak Fix Greatly Exaggerated

  • WordPress 2.7自定义单条评论结构

    WordPress 2.7内置了threaded comment之后,原来主题的comments.php文件中繁琐的评论循环简化成了一个函数调用:wp_list_comments.

    然而不加任何参数调用该函数的话,它输出的HTML结构是固定的。尽管它给每个元素都提供了丰富的class name供CSS样式使用,但是CSS并不足够灵活(除非使用一些我认为不是太好的方式,比如大量绝对定位),可以任意显示固定的DOM结构。某些情况下,我们还是希望能够自己来定义DOM结构。

    WordPress开发者当然考虑到了这一点,在Codex上的文档页就给出了一个例子。实际上就是wp_list_comments接收的数组参数中可以传入两个回调函数。一个是callback,负责输出一条评论的主体部分。另一个是end-callback,负责输出评论的结束部分。

    解释一下。threaded comments实际上在内部就是一个“森林”,每一条顶层评论和它的所有回复、回复的回复构成一棵树。wp_list_comments对每棵树做一次遍历,首先调用参数callback指定的函数,然后递归遍历其子节点(输出回复评论),完成之后再调用参数end-callback指定的函数。如果不指定这两个函数,WordPress就会输出默认的结构,实际上大家都是把默认输出复制到自己的回调函数中,然后修改一下结构。简单的说,就是callback输出一个块的开头加上该评论自己的内容,end-callback输出这个块的结尾,中间是子评论。如下图所示的遍历顺序,偏下的箭头表示调用callback,偏上的箭头表示调用end-callback.

    tree (by qingbo)

    以上提到的关键代码都在wp-includes/comment-template.php中。

  • HTML编辑器之选择-FCKEditor/TinyMCE/NicEdit

    这三个都是开源的HTML所见即所得(WYSIWYG)编辑器,下面简单地做一个比较。

    FCKEditorTinyMCE都是非常老牌的了,我接触web开发的时候它们看起来都已经非常成熟了。TinyMCE至今仍然是WordPress的默认可视化编辑器。

    但是老牌的不一定是好的,它们在长年累月的积累中,吸纳了各种各样的需求,最后形成一个大而全的系统,无所不能。于是它们庞大而笨重,分别看一下它们的demo页吧,它们可能是要决心与微软的Word软件竞争,而不是给开发者提供一个适合浏览器环境的编辑器。

    各种命令都带有一堆看似合理实际上毫无用处的选项,对于开发者要面对的用户,更是会让他们无所适从。例如要插入图片,弹出的窗口里,有”alternative text”, “vertical space”, “title”, “horizontal space”等参数,有些连熟悉web开发的人都感到陌生,更不用说普通用户了。

    当然了它们都号称customizable,然而我确定这是有限的。以我使用FCKeditor的经验,要想在插入图片窗口删除那些无用的参数,仅保留一个链接地址的输入,就必须在它的源代码中做修改,而不是配置文件。修改源代码必然造成升级的困难。

    庞大的代码蕴含着丰富的功能,而我们只用其一小部分,这对于带宽来说明显是个浪费。没有具体数过,根据我的印象,它们至少应该有数以百计的小文件吧,简直无法忍受。

    这两个大家伙早期的时候还更过分,按钮的图片都是一张一张的,打开页面时就看到它们像多米诺骨牌一样依次展开。以前它们都使用window.open打开一个新窗口显示文本对象的属性,在许多情况(大多是个别用户客户端的问题)下,弹出的窗口大小有问题而且用户无法调整,反馈给我们也束手无策。还好这两个问题现在都已经解决,CSS sprite被使用,选项窗口也使用div来模拟实现,这两点是值得肯定的进步。

    ————反衬结束,主角登场————

    上一个项目要选择编辑器的时候,我死活不想再用FCKeditor了。在网上做了许多搜索,刚好发现一个新出现的编辑器:NicEdit.

    What is NicEdit?

    NicEdit is a Lightweight, Cross Platform, Inline Content Editor to allow easy editing of web site content on the fly in the browser.

    NicEdit Javascript integrates into any site in seconds to make any element/div editable or convert standard textareas to rich text editing.

    轻量级是最大的优点。此外它还有许多优良的特性,比如输入框随文本自动拉高,良好的扩展性等。用它来实现了插入自定义表情的功能,非常简单、优美。

    不用多说了,把前面提到的那两个编辑器的缺点反过来,主语换成NicEdit放在这里就可以了。

    嗯,我就是要唱衰FCKEditor/TinyMCE,力挺NicEdit.

    也许FCKEditor/TinyMCE曾经也像NicEdit一样小巧玲珑?希望NicEdit能够守住贞操,不要被那些永无止境的Feature request给f*ck了。FCKEditor不会就是这样得名的吧?-joke.

    NicEdit现在还不是很完美,但是它在不断改进。如果你要用,建议先逛一下它的论坛,看看大家都遇到了什么问题,对你关键不关键。

  • 表单富文本输入,选择什么方式?

    现在几乎所有的网站开发都必须面对一个问题,用户怎么输入带格式的文本呢?最基本的功能包括链接、图片、文字加粗、字体大小颜色等。不同的网站有不同的考虑,有不同的实现。实现得越简单,给用户的门槛就越高。我就尝试从简到繁列一下一些常见的实现方式。

    1. textarea里写HTML代码

    适用于非常简单的文本,如链接、图片。

    例子豆瓣FacebookFlickr

    当然了,大部分这样的网站都不会要求你换行都用”<br />”来实现的,文本显示的时候,换行符会被自动转换成HTML的换行。有的网站还会给一些辅助,比如豆瓣的日记编辑器上方有几个按钮,可以帮助生成链接等HTML代码。WordPress的quick tag editor也是这样。

    对于开发者来说,几乎没有工作量,只需一个html textarea元素即可解决问题。

    然而对于用户的要求就比较高了,他们要想插入链接、图片就必须学一些简单的HTML语法。不过用户及时一点HTML都不懂也没关系,他仍然可以发布内容,只是没有链接、图片而已。像Flickr这样流行的服务,有无数的人为它开发帮助用户输入的浏览器扩展、Greasemonkey脚本等,更降低了输入HTML代码的难度。

    2. textarea里写自定义语法

    例子WikipediaGoogle Code,大部分论坛

    比较常见的语法有wiki markupMarkdown,以及各种论坛系统常用的BBCode等等。当然了,wiki markup语法的目的不仅仅是为了方便用户输入带格式的文本,它还方便了页面之间的互相链接,但是这里也把它归在这一类。在文本要在浏览器中显示的时候,系统将它翻译成HTML.

    用户不需要学习HTML了,但这些语法也需要学习,虽然看起来稍微简单点。和第一种方式一样,许多网站也提供辅助按钮。自定义语法的最大优点在于其安全性,稍后讨论。

    Flickr的评论里实际上除了支持一些基本的HTML代码,其实也有自定义输入链接的方式。

    3. WYSIWYG编辑器

    用户门槛很低,可以实现的效果很复杂。

    例子FCKeditorTinyMCENicEdit

    这是国内最常见的方式。国内网站大部分认为用户非常低端,而实际上的确如此。就拿已经够直观的FCKeditor来说,有些用户还是弄不明白插入图片时的一大堆属性都是什么东西,这是可以理解的,你自己使用以下就知道了。所以即使拿来现成的可视化编辑器,你还得好好简化简化。比如插入图片,就输入一个图片地址就够了。不过还真有用户连图片地址是什么都不知道的,那……实在不行就让他上传吧。

    使用这些编辑器的缺点是客户端需要启用JavaScript才可以正常使用。另外前两个编辑器非常庞大笨重,二位的目标是打败微软的Word产品,所以我们要考虑好用牛刀来杀鸡是不是合适。

    安全性考虑

    SQL注入的话题这里就不讨论了。

    允许用户提交HTML代码,就带来了潜在的危险。一方面是网站数据的安全,另一方面是页面显示的安全。前几天feelinglucky就披露了yupoo的一个漏洞,尽管这不是由于输入带格式文本造成的,但这是允许HTML代码提交的常见漏洞,危害到网站数据的安全。

    如果对用户提交的数据不加处理,还可能会造成显示错乱,比如数据中大量没有关门的标签。如果用户想恶作剧,还可以增加一个元素让它占据整个网页,隐藏所有内容。

    千万不要试图仅仅在客户端过滤代码,这就好像敌人要来进攻,你去人家门口堵着一样,敌人很容易绕过这道防线,从后门出来就可以了。服务器端的过滤是绝对必要的。

    自定义语法大都不使用尖括号,这给安全性带来了帮助。在服务器端,所有的尖括号均转换成HTML entity表示,然后做语法翻译,这是最简单的方式。

    上述一、三方式都是提交HTML代码,服务器端就必须至少过滤JavaScript代码,不能让它在客户端执行。另外还要分析代码的标签是否完整,某些标签是否允许,等等。

  • WordPress Feed添加自定义内容的正确方法

    前段时间,Smashing Magazine的文章“10 Useful RSS-Tricks and Hacks For WordPress”第三条讲怎么在RSS Feed中插入任意内容。实际上该hack出自wprecipes,但是很遗憾,它已身在高墙外了。

    这种方法就是添加两个filter,分别在the_excerpt_rss和the_content_rss. 貌似合理,但实际上呢?且看wp-includes/feed-rss2.php的关键部分:

    [code lang=’php’]
    ]]>

    ]]>
    post_content ) > 0 ) : ?>
    ]]>

    ]]>

    [/code]

    首先鄙视一下RSS中只输出摘要的blogger,这样我们就只需关心外层if判断的else块了。Feed中的每个item都有一个description标签,调用的是the_excerpt_rss函数。而最重要的是content:encoded这个标签,因为多数RSS阅读器都是根据这里的内容显示的。可以看到,如果文章内容不为空——该条件99.9%的情况下成立,content:encoded的内容就是调用the_content. 该文件输出的是RSS 2.0格式,大部分WordPress blog的默认feed.

    再看feed-rss.php, feed-rdf.php和feed-atom.php,只有feed-rss.php输出的RSS 0.92格式的feed没有使用the_content. 因此,按照Smashing Magazine的方法,绝大多数情况下我们添加的内容不会再RSS阅读器中显示。

    所以正确的做法是把’the_content’也加上filter:

    [code lang=’php’]function process_feed($content) {
    if (is_feed()) { // 只在feed输出时处理,不影响站内内容显示
    $content = …;
    }
    return $content;
    }

    add_filter(‘the_content’, ‘process_feed’);[/code]

    最后看一下the_excerpt_rss这个函数到底都干了些什么。它定义在wp-includes/feed.php中,首先调用get_the_excerpt函数,然后应用hook到’the_excerpt_rss’的filter. get_the_excerpt定义在wp-includes/post-template.php中,取得文章的post_excerpt,然后应用hook到’get_the_excerpt’的filter,默认是wp-includes/formatting.php中的wp_trim_excerpt函数。它的作用是当post_excerpt为空的时候(该条件绝大多数情况下成立,我还没见过谁去写那个excerpt——默认在WP文章编辑器下方),取得文章内容,然后应用’the_content’的filter,再做一些去除tag的工作。总结:the_excerpt_rss就是取得the_content的输出,然后去除HTML标签。

    我们hook了’the_content’,所添加的内容,自然会进入the_excerpt_rss的输出(只是html tag被抹掉了),所以不要再hook ‘the_excerpt_rss’了,以免造成内容重复!当然对于那些有精力写excerpt的牛人另当别论。

    我目前的做法就是将处理函数hook到’the_content’和’the_content_rss’这两个上面。

    WordPress这部分现在似乎有点乱,不知道我有没有写错什么。如有错误,请指正,呵呵。

  • Get Recent Comments插件中文乱码问题

    前几天启用了Get Recent Comments这个插件,开始的时候一切正常,后来发现有时候中文会出现乱码。

    看了一下插件的源代码,发现它用wordwrap这个函数来把很长的单词切分开来。wordwrap函数没有multi-byte的版本,所以它就按字节来数,到了指定的地方就给野蛮地断开了。

    在以中文内容为主的blog里,我们基本不需要这个功能。那些超长的url可能会破坏布局,这时只需给外面的容器加上宽度并且overflow:hidden就可以了。无需修改插件源代码,最简单的做法是在该插件的选项页面把Wrap long words at这个选项设置成非常大的整数比如1000.

    写下文章标题的时候才去搜索,发现已经有人做了个“中文改良版”,呵呵。

  • Google Reader 可以实时更新feed

    大部分在线RSS阅读器都支持XML-RPC ping,不过国内的抓虾、鲜果似乎实际上都不管用。鲜果在feed上右键-反馈,点击马上更新,它才会真正地去抓取。网上有些人说ping了Google blog search,Google reader就随之更新,我没有找到确切的证据。

    不过Google Reader的阅读区上方有一个“Refresh”按钮,点击它之后,Google就会马上抓取最新的feed过来,不像鲜果这样的是放入一个队列,可能几分钟之后才能抓回来,这点从侧面反映了Google服务器阵容的强大。

    看了一下点击Refresh之后发送的Ajax请求,主要的url就是:

    https://www.google.com/reader/api/0/stream/contents/feed/http%3A%2F%2Fqingbo.org%2Ffeed?refresh=true

    即blog有新文章之后,在浏览器中访问该链接即可使Google Reader更新你的feed,在Google reader里订阅该feed的读者也就看到最新的了,不用等待Google Reader的默认更新周期。其实可以自动化一点,发布文章的时候让wordpress自动去请求该url,或者……不知道放在自动ping的列表里有没有作用,鉴于Google Reader更新的频率已经够快,我就懒得尝试了。

    在发布后修改文章的时候,刷新一下Google reader比较好,这样可以让它马上获取更新后的版本。