SUBJ: 开发XIUGAI.COM的过程
===== ===== ===== =====
点下面的连接来XIUGAI
-----------------------
===== ===== ===== =====
*** 欢迎转载 不可修改 ***
联系作者
========
liudieyu AT umbrella D0T name
liudieyuinchina AT yahoo.com D0T cn
序
==
本文记叙了XIUGAI.COM(一个在自己喜欢的网页上做笔记的应用)的开发过程 - 从刚开始的一个想法, 到现在的一个成熟产品; 并记录了以下技术问题:
负载与分流
支持多种语言
为什么不用fopen下载网页
MOZILLA系列(包括NETSCAPE NAVIGATOR)和MSIE的编辑功能有差异
MOZILLA系列中编辑功能需在网页装载完成后用
WEB服务器返回的HTTP HEADER中定义的CHARSET V.S. HTML代码中定义的CHARSET
PHP4程序在PHP5上跑不起来
EMAIL功能的考虑: PHP发出的邮件被认为是垃圾邮件
EMAIL功能的考虑: CAPTCHA防止机器滥用服务器发邮件
ISP的错误: 需要考虑对垃圾邮件的忍受能力
FREEBSD服务器上安装APACHE和PHP(GD, FREETYPE, ZEND OPTIMIZER)
想法
====
国外的新闻网站报道WWW上到处都是利用IE漏洞的小偷, 我疲惫地靠在了电脑椅子的靠背上, 想着: 除了发现漏洞和公开漏洞的记忆, 还有那不断加长的联系人EMAIL名单, 我到底有什么 ... 也许现在该做些有意思的东西了, 换换口味 - 可是自己除了浏览器什么都不了解 ... 突然, 就想到:
做个浏览器中做笔记的应用: 任何时间, 任何地点, 任何操作系统, 任何浏览器都能安全地在任何网页上做笔记. 工程的英文名字叫"EDITIVE", 中文名字叫"XIUGAI" - 于是立刻注册了: EDITIVE.COM, EDITIVE.NET, EDITIVE.ORG, XIUGAI.COM ,XIUGAI.NET和 XIUGAI.ORG.
服务的稳定性
============
如何在没有规律的访问高峰到来时保持服务仍然在线?
首先是, 在有访问量高峰来临时, 能及时加配服务器, 满足访问请求;
然后, 在访问量高峰过后, 能及时取消加配的服务器, 节省开支.
看到 DELL.COM.CN 等许多网站的做法是用CGI层的负载均衡: 主要域名(如 DELL.COM.CN)上的服务器只有重定向的功能, 它们把浏览器重定向到有效的分服务器. 这种方法灵活而经济, 缺点是浏览器地址栏可就不好看了. EDITIVE作为一个实用工具, 这缺点还是可以忍受.
支持多种语言
============
首先, 我们开发团队之间用英文; 然后我作为中国人用汉语, 而其他开发者有自己的母语; 大家都想EDITIVE能说自己的语言, 于是对多国语言的支持是继稳定性后第二考虑的. 我们采用的方法是: 一个短语做为一个文件, 每种语言的文件放在一个目录里 - 这样便于管理. 先看用户是否自己设定过语言; 如果没有, 就从浏览器的"$_SERVER["HTTP_ACCEPT_LANGUAGE"]"变量中选语言.
下载网页
========
大体想法是: 在EDITIVE服务器上放些网页, 这些网页中的SCRIPT来操作目标网页, 以完成编辑功能 - 划记成黄底黑字, 改成大号字, 等等.
但是, 来自不同域名的网页不允许互动:
About Cross-Frame Scripting and Security
http://msdn.microsoft.com/workshop/author/om/xframe_scripting_security.asp
那怎样才能让EDITIVE.COM的SCRIPT去编辑EXAMPLE.COM上的网页呢? 于是想到需要EDITIVE服务器下载EXAMPLE.COM上的网页, 然后在把内容返回给用户 - 这样这些内容来自于EDITIVE服务器, 自然EDITIVE服务器上网页中的SCRIPT可以操作.
开始是用FOPEN下载网页, 但是后来发现用FOPEN去控制下载非常不灵活, 于是改用了FSOCKOPEN去打开80端口, 然后用HTTP/1.1去把网页抓下来. "PHP Manual"(PHP.NET有下载)中"FSOCKOPEN"函数参考中"Jack at soinsincere dot com"写的范例可以完成此任务.
开始编辑
========
首先, 如果你需要个"所见所得"的网页编辑脚本, 推荐:
http://www.interactivetools.com/products/htmlarea/index.html#demo
EDITIVE是专门为做笔记设计的, 所以它只含有很精简的几个编辑命令. 要做个"所见所得"的编辑器, 只要看看:
Command Identifiers (Internet Explorer - DHTML)
http://msdn.microsoft.com/workshop/author/dhtml/reference/commandids.asp
和
Rich Text Editing Specification
http://www.mozilla.org/editor/midas-spec.html
, 尤其注意
1. MOZILLA中没有"CreateLink"和"InsertImage"命令.
2. IE中的"backcolor"命令, 在MOZILLA中是"hilitecolor".
另外, MOZILLA的文档中没说但又十分重要的一点:
MOZILLA只有当网页完全装载完成(即BODY的ONLOAD事件被呼叫后), 才能起用编辑模式 - 过早起用此模式将导致网页变成空白.
用哪个CHARSET(编码方式)
=======================
这是个细节问题:
WEB服务器返回的HTTP HEADER中定义的CHARSET 和 HTML代码中定义的CHARSET 不相同时, 到底采用哪个CHARSET?
IE会采用HTTP HEADER中的CHARSET, 也就是说: 当且仅当HTTP HEADER中没有定义CHARSET时, HTML代码中的CHARSET被启用.
MOZILLA会采用HTML中定义的CHARSET.
我个人也倾向于HTML中定义的CHARSET会好过HTTP HEADER中的, 因为:
HTML代码中的CHARSET是网页制作人自己设定的, 还有谁比网页制作人更了解自己网页的编码?
所以, EDITIVE决定:
当HTML中含有CHARSET信息时, 采用它; 如果不存在, 采用HTTP HEADER中的CHARSET信息.
(感谢HAN LEI指出第二条的必要性.)
放上服务器, 不能用!
===================
在笔记本上用APACHE1.3+PHP4开发完后, 就放到服务器上(PHP5), 结果发现不能用. 难道是PHP4和PHP5的语言差异?
于是上
http://www.php.net/ChangeLog-5.php#5.0.2
看了看 - CHANGELOG这么多条, 看来还是自己找吧. 最后发现:
PHP4: 在包含关系的两个PHP中, 包含与被包含这两个PHP公用一个$GLOBALS[], 而PHP5不是(PHP5是每个PHP文件各有一个$GLOBALS[]).
EMAIL功能考虑的细节
===================
如何防止自己PHP发出的EMAIL被判断为垃圾邮件?
只有一个办法: 通过多个SMTP服务器发EMAIL. 于是, 对于需要发送大量EMAIL的应用而言, PHP自己的MAIL函数就不够用了.
防止机器滥用服务器发邮件 - CAPTCHA - 也就你注册HOTMAIL和YAHOO帐号时看到的那种歪歪的字母.
BTW, 说来不怕笑话, 我在MS RESEARCH ASIA学过一阵图象处理和识别(自学, 和MS各个成名大师没任何关系). 网上有许多PHP的CAPTCHA例子, 设计XIUGAI的CAPTCHA时, 我注意: 把前景色和背景色范围色调成很接近 - 于是识别中的基础: 二值化(THRESHOLDING)难以进行.
ISP的错误
=========
选择ISP, 我说点可能大家没听说的:
在国外选ISP运行发送大量EMAIL的应用, 要小心. 很多ISP对垃圾邮件是非常敏感的, 而这样的应用一天出1000来封不受欢迎邮件也很平常: 所以除了看ISP的设备外, 要看ISP对垃圾邮件的规程 - 如果过于苛刻则不选.
XIUGAI在安家的时候就吃了这个亏 - 最后导致要换ISP重新来.
FREEBSD上安装APACHE加PHP(GD, FREETYPE, ZEND OPTIMIZER)
======================================================
已经有不少资料介绍了. 推荐个:
http://www.gbunix.com/bbs/ftopic478.html&sid=4e9f68cdb40c8fa3adc66f2f144cd956
但有个小问题大部分资料都没说:
如果你升级APACHE, 你先把APACHE整个目录全删除了, 包括PID文件; 这时候APACHECTL仍然在运行, 80端口还是老的APACHE占用, 你装了新的APACHE后, 用APACHECTRL STOP是停不住那个老APACHE的进程的(因为PID文件没有指向它) - 有个办法可以杀死老APACHE的进程:
ps -x
找到PID, 再KILL.