前些日子一篇N久之前的老文忽然成了被阅读的热点,检查之后才发现自己使用那段代码来做pr查询的页面已经不能正常得到URL的Page Rank值了,取而代之的是一大段“In your email, please send us the entire code displayed below”之类的Google terms_of_service错误提示信息。看来是原先的接口已经失效了。
但我装在Firefox工具栏的扩展插件SearchStatus仍然能够正常解析出每个受访页的PR值,找到 SearchStatus 的插件包解开来看源码,果然是使用了不一样的验证码生成算法,在原先的 checksum 生成之后,还需要再进行一次计算,两次演算之后得到的才是正确的ch参数。
于是拿现成的js代码改造一番之后,新的PHP版本的 Google PageRank 查询接口方法就出来了。经过本地测试之后,谁想传到服务器之后又出现了该死的 terms_of_service 错误提示。把checksum的计算过程一步步打出来,发现经过了几次右位移之后本地和服务器上的数字就不一样了。这才想到服务器是64位机,32位系统下位移之后应该被cut掉的bit在那里就活得好好的。加了个 trunkbitForce32bit 方法,对所有算术运算之后的数值进行高位屏蔽,算是搞定了64位系统下的多余位问题。结果拿到32位Linux环境下跑又不兼容了,原因是PHP在进行算术处理出现溢出时,会自动尝试将int转为float。当发生的是负数溢出时,这一操作在Windows下能正确保留精度,但在Linux下就有问题了。
下面这段代码:
$a = -4294967295;
echo dechex($a)."<br />\n";
if ( $a < 0 ) $a += 4294967296;
echo dechex($a)."<br />\n";
第一个echo在Windows下能够正确输出该负数低32位的补码,而在32位Linux机上输出的则是int类型所能表示的最大负数0x80000000了。只有通过取巧的方式给这个溢出的大负数加上一个超出整数范围的大整数来抵消掉溢出的部分,才能复原低32位应该有的样子。
使用这些非常规手段,终于炮制出这个更新版的兼容Linux32/Linux64/Windows的Google PR值查询接口的PHP脚本实现(含完整代码)。
参考:
php异或运算的不可靠性
PHP vs. BIGINT vs. float conversion caveat
http://www.teamworksusa.com/RDS275/HydroWorks275/keygen.php
Reverse Geocoding ,也就是反向地理编码(逆地理编码),可以根据地图上某一点的经纬度值来查询该点附近的地理信息。比如要实现捕获用户鼠标事件判断用户点的是哪国哪省哪市哪条街道,就需要有相应的 reverse geocoding 服务支撑。
在当前版本的 Google Maps API 中对这项功能提供了有限支持。对于开放了 Geocoding (GClientGeocoder) 和 Driving Directions (GDirections) 接口的国家和地区,Nico Goeminne 写了个 GReverseGeocoder 类来完成反向地理编码解析(Google Pages 貌似这几天被 GFW 掉了,访问不到 Nico Goeminne 站点的朋友可以看我本地的镜像链接)。可惜的是目前谷歌中国的ditu.google.com还没有提供GDirections接口,不知道后续的版本会不会放出。下面是 Nico Goeminne 列出的 GReverseGeocoder 当前的国家支持情况(x=支持, n=不支持, p=理论上支持但未经过测试):
| Country | GClientGeocoder | GDirections | GReverseGeocoder |
|---|---|---|---|
| Austria | x | x | p |
| Australia | x | x | p |
| Belgium | x | x | x |
| Brazil | x | x | x |
| Canada | x | x | p |
| The Czech Republic | x | x | p |
| Denmark | x | x | p |
| Finland | x | x | p |
| France | x | x | x |
| Germany | x | x | x |
| Hong Kong | x | n | n |
| Hungary | x | x | p |
| India | x | n | n |
| Ireland | x | x | p |
| Italy | x | x | x |
| Japan | x | n | n |
| Luxembourg | x | x | x |
| The Netherlands | x | x | x |
| New Zealand | x | x | x |
| Norway | x | x | p |
| Poland | x | x | p |
| Portugal | x | x | p |
| Singapore | x | x | p |
| Spain | x | x | p |
| Sweden | x | x | p |
| Switzerland | x | x | x |
| Taiwan | x | n | n |
| Thailand | x | x | p |
| the United Kingdom | x | x | x |
| the United States | x | x | x |
实际上,在 Google Maps API 官方文档里面 GClientGeocoder 接口的 getLocations(address, callback) 方法里面虽然没有明确说明,却可以传递用逗号或空格分隔的经纬度值进去作为address参数,也能达到反向地理编码解析的目地。只是目前这样调用返回的Placemark对象精度只能到国家级别,并没有更进一步的所在地信息,还没有太多的实际价值。
一些非 Google Maps 提供的 geocoding / reverse geocoding 服务链接: http://groups.google.com/group/Google-Maps-API/web/resources-non-google-geocoders ,基本上可查询范围都是欧美国家,有偿服务居多。
中国区域的 reverse geocoding 服务方面, MapABC的搜索API中倒是有 reverseGeoCoding(msearchpointpara) 接口方法,美中不足的是其flash版本的地图跨浏览器兼容性又不是太好还有滚动广告条,文档的组织也够凌乱,所使用的经纬度坐标又不是标准的数字形式,极大的影响了使用体验;51ditu 的位置描述接口则直接作为收费接口有偿提供。看来想使用免费又称心的 reverse geocoding 还得耐心等谷歌地图开放相应的功能了。
标签 ( Tags ) : jquery,javascript,源代码
看到有人说用了Safari之后"已经开始不愿意去用firefox了",忍不住也试用了一把,顺便看看最近几个应用在Safari下的兼容性。一打开浏览界面,果然很有苹果的酷炫风格,相当养眼。
然后就发现Safari的XMLHTTPRequest并没有如其他主流浏览器一样缺省使用utf-8编码来处理内容,必须在服务器端强制设定页面编码才不至于在Ajax处理中文时出现乱码(比如在脚本里面 header("Content-Type:text/html;charset=utf-8"); 或者在Apache的conf里面加上 AddDefaultCharset UTF-8 ,如果不幸服务器端的php.ini里面设置了不恰当的default_charset的话还必须在所有相关的php文件开头加上ini_set('default_charset','UTF-8'); 才行),也算相当有性格。
至于号称的 fastest browser in the world,没怎么感觉出来。IE6当然是没啥好比的;相较Firefox而言,去使用 Gmail 和自己的几个应用项目,速度上最多也就半斤八两各有快慢。或许因为是Mac移植版的缘故?没用过Mac版的,不得而知。
标签 ( Tags ) : 浏览器
很常见的一个图片轮播Flash,使用之后发现在IE下按F5刷新之后Flash区域就变成一大块背景色,内容轮播出不来了。有趣的是右键点击Flash选择"关于Adobe Flash Player 9 ..."打开 Adobe 的官网之后再按F5刷新,内容又可以正常显示了。
一点点去掉代码发现是 <param name="scale" value="exactfit"> 这个参数作怪。在 Flash 的脚本里面强制指定了 Stage.scaleMode = "noScale"; 而我的 Flash 代码生成 js 里面缺省把 scale 设成了exactfit 。 似乎这两者之间发生了某些冲突,导致IE下出现这种奇怪的刷新之后就白屏的现象。Firefox下倒是没问题。把参数改成 <param name="scale" value="noScale"> 之后恢复正常。
本来拿 PHP Standalone OpenID Server 的代码改装出来的 Zeal OpenID Server 纯属好玩,最近发现对 OpenID 感兴趣的朋友日渐增多,发信留言询问相关的东西。所以干脆把整个汉化修改之后的 Zeal OpenID Server 整站源码打了个包,喜欢研究的朋友自己 down 一个下来瞧瞧吧。
如果使用过程中有什么问题,最好自己去搞定,俺不负责技术解答,嘿嘿 :)
gz 压缩包:
openid.zeali.net.tar.gz zip 压缩包:
openid.zeali.net.zip
Just Copy the whole folder to your server .
create a database ,
import tables information of file zeal_openid_server.sql
change config.php to fit your requirements.
default settings in config.php:
administrator user : admin
administrator pass : 123456
db host : localhost
db name : zeal_openid_server
db user : openuser
db pass : 123456
照例,每次的版本更新都会大幅提升 selector 的速度。不过这次的版本更新作为 1.1.x 的最后一个版本,为了给九月份的 1.2 版做铺垫,去掉了一些老版本中的方法。因此在使用之前最好确认一下原有代码的兼容性。
比如在 Validation 插件的 showLabel 方法中,作者采用 label = jQuery("<" + this.settings.errorElement + ">") 的方式来新建一个 dom 对象,在 1.1.4 中必须改为 label = jQuery("<" + this.settings.errorElement + "></" + this.settings.errorElement + ">") 才能被正常创建。否则在进行form输入字段验证的时候在IE下永远不会看到任何的提示信息显示出来。
具体 1.1.4 中 Deprecated 掉的内容包括:
- $("div//p") , $("div/p") , $("p/../div") , $("div[p]") , $("a[@href]") 这几种 selector 写法
- 带参数的 $("div").clone(false) 方法 ( 改而使用 .clone().empty() )
- $("div").eq() , $("div").lt() , $("div").gt() 均由新增加的 slice 方法来实现等价功能
- $("#elem").loadIfModified("some.php") , $.getIfModified("some.php") 均由调用底层的 $.ajax 方法来实现等价功能
- $.ajaxTimeout(3000) 需要改而使用 $.ajaxSetup({timeout: 3000}) 来实现
- $(…).evalScripts()
标签 ( Tags ) : javascript,jquery
- 内存泄漏。像 Circular References / Closures / Cross-Page Leaks / Pseudo-Leaks 这些引起 IE 内存泄漏的因素已经被无数人分析讨论过(1 , 2)。据说 IE7 以及 IE6 的某个更新补丁能够解决 memory leak 的问题,但事实上即便在 IE7 下面还是一不小心就让你的脚本吃光内存。比如创建 DOM 对象的时候在加入节点之前就把事件处理函数绑定到该 DOM 对象,或者把 DOM 对象从节点中移除之后再进行事件的解绑。
- 以 DOM 方式频繁对 table 的整行(TR)进行 remove 和 append 。尤其是如果在 table 中使用了多个 tbody 并对这些 tbody 进行 remove / append 操作的话, IE 会直接出现非法操作框而退出。这个问题 IE7 倒表现良好,算是有点进步。
- 不同的事件/函数同时操作DOM的对象。由于 javascript 本身不提供同步机制(当然也不是完全没有办法),所以在 Ajax 这样的异步模式下容易产生对象操作冲突。
当在 window 的 resize 事件中包含某些页面内容处理或计算导致 resize 事件再次被触发的时候, IE 会随机陷入假死状态,而 Firefox 则能够很好的处理。要防止这样的假死,比较简单的处理方法是通过 setTimeout 延迟处理。以 jQuery 的时间绑定语法为例:
function dealWithSth() {
alert("resize event trigger");
};
var pResizeTimer = null;
$(window).bind(
'resize',
function() {
if(pResizeTimer) clearTimeout(pResizeTimer);
pResizeTimer= setTimeout(dealWithSth, 50);
}
);
标签 ( Tags ) : javascript,jquery,浏览器,ie,error
ajaxError( callback ) 中关于 callback 函数的传入参数,并不像官方文档说明的那样依次是XMLHttpRequest / settings / exception object 。实际上在这三个参数之前的第一个参数是指向 callback 本身的一个引用对象,从第二个参数开始才是文档中所描述的参数。其它几个 ajaxComplete / ajaxSend / ajaxSuccess 估计也类似。
使用了 ifModified 参数之后(也就是在发送 http request 的时候添加 If-Modified-Since HEADER),在 IE6 下刷新页面经常出现 IE 崩溃退出, IE7 / Firefox 下则正常。怀疑是跟浏览器的一些外部加载项有关。
对于 flash 内容,如果设定宽度/高度为0, Firefox 不会真正载入这个 flash , IE 则似乎照常处理。
标签 ( Tags ) : javascript,jquery,firebug
通常利用 apache 的 mod_rewrite 对 URL 进行重写的时候, rewrite 规则会写在 .htaccess 文件里。但要使 apache 能够正常的读取 .htaccess 文件的内容,需要对 .htaccess 所在目录进行配置。从安全性考虑,根目录一般都配置成不允许任何 Override ,即
<Directory />
AllowOverride None
</Directory>
在 AllowOverride 设置为 None 时, .htaccess 文件将被完全忽略。当此指令设置为 All 时,所有具有 ".htaccess" 作用域的指令都允许出现在 .htaccess 文件中。
AllowOverride 可用的指令如下:
- AuthConfig
- 允许使用与认证授权相关的指令(AuthDBMGroupFile, AuthDBMUserFile, AuthGroupFile, AuthName, AuthType, AuthUserFile, Require, 等)。
- FileInfo
- 允许使用控制文档类型的指令(DefaultType, ErrorDocument, ForceType, LanguagePriority, SetHandler, SetInputFilter, SetOutputFilter,
mod_mime中的 Add* 和 Remove* 指令等等)、控制文档元数据的指令(Header, RequestHeader, SetEnvIf, SetEnvIfNoCase, BrowserMatch, CookieExpires, CookieDomain, CookieStyle, CookieTracking, CookieName)、mod_rewrite中的指令(RewriteEngine, RewriteOptions, RewriteBase, RewriteCond, RewriteRule)和mod_actions中的Action指令。 - Indexes
- 允许使用控制目录索引的指令(AddDescription, AddIcon, AddIconByEncoding, AddIconByType, DefaultIcon, DirectoryIndex, FancyIndexing, HeaderName, IndexIgnore, IndexOptions, ReadmeName, 等)。
- Limit
- 允许使用控制主机访问的指令(Allow, Deny, Order)。
- Options[=Option,...]
- 允许使用控制指定目录功能的指令(Options和XBitHack)。可以在等号后面附加一个逗号分隔的(无空格的)Options选项列表,用来控制允许Options指令使用哪些选项。
所以对于 URL rewrite 来说,至少需要把目录设置为
<Directory /myblogroot/>
AllowOverride FileInfo
</Directory>
标签 ( Tags ) : apache,mod_rewrite
IE6下默认的字体尺寸大致在 12 - 14px 之间,当你试图定义一个高度小于这个默认值的 div 的时候, IE 会固执的认为这个层的高度不应该小于字体的行高。所以即使你用 height: 6px; 来定义了一个 div 的高度,实际在 IE 下显示的仍然是一个 12 px 左右高度的层。
要解决这个问题,可以强制定义该 div 的字体尺寸,或者定义 overflow 属性来限制 div 高度的自动调整。比如 <div style="height: 6px; font: 0px Arial;"></div> 或者 <div style="height: 6px; overflow: hidden;"></div> 都可以阻止 IE 的自作聪明。
该问题在 IE7 / Firefox /Opera 下均不存在。
不知道什么时候开始每次进入 Google Reader 的 Manage subscriptions 界面之后,无论点选哪一个 Tab 链接页面都会一闪之后自动跳回 Reader 的主页去。但我明明那时候是通过这里的 Import/Export 把 feeds 导进去的,结果现在想在到这里把 feeds 导出来做备份就死活进不去了。
原先我以为是 Google 的开发人员在对这些功能进行修改,暂时作了跳转屏蔽。反正 feeds 放在这里应该也不会出什么大问题,便没太在意。
但今天看到说SPA开始提供多国语言界面就想去试下。结果到了 snap 的定制页面 想选择 Bubble Language 为简体中文的时候,发现一点国旗页面就自动跳转掉了;状况跟 GReader 如出一辙。
查看了两者的源代码,都是使用了类似 <a href="" onclick="{return confirm('Clicked');}">Click Test</a> 的写法。正常来说当点击这样的 URL 链接后, onclick 先被触发,如果触发的处理脚本最终返回 true 的话, href 中的内容会被浏览器打开;如果返回 false 的话,不进行后续处理。
这才想起我前阵子做测试已经把浏览器升级到 IE7 了;赶紧跑到 IE6 和 Firefox 下试了一把,果然 GReader 和 Snap 都恢复了正常反应。
看来 IE7 不论 onclick 的返回是 true 还是 false ,对于 href 的内容是照处理不误( 1 , 2 )。如果不希望 href 坏了 onclick 的好事的话,最保险还是在 href 里面加上 javascript:void(0) 为好。
Snap Preview Anywhere™ 预览服务和最初相比,已经相继增加了不少个性化的界面定制功能。今天又从 dimlau 的日志上看到 SPA 已经推出了包括中文简体在内的9种语言界面。试用了一下,感觉中文界面看上去总是没有英文那样舒服。另外现在还提供了两个尺寸的预览窗口选择,觉得原来的预览图太小的话可以选择 large 模式。 进行这两项设置,只需要在原来的代码参数后面增加 &size=large&lang=zh-cn 这两个参数即可。
对于 block-level 的页面元素(比如 DIV )来说,要让他相对于父级元素居中显示的话,标准的做法是为该元素定义的样式中包含 margin: auto; 属性。虽然在 IE 下我们使用 text-align: center; 就可得到居中的效果,但如果要考虑到不同浏览器之间的兼容,还是使用标准的方式比较好( text-align 理论上应该只是用来指定 block-level 元素里面所包含的每一行 inline-level 元素 -- 比如 SPAN -- 的对齐方式)。
For block-level elements with horizontal flow in a containing block also with horizontal flow, the computed values of the 'width' and margins must satisfy this constraint:
(width of containing block) =
margin-left + border-left + padding-left + width + padding-right + border-right + margin-right
The following cases can occur:
- None of width, margin-left and margin-right are specified as 'auto' and the values satisfy the constraint.
- None of width, margin-left or margin-right was specified as 'auto' and the equation is not satisfied. There are two sub-cases: (1) if the 'direction' of the element is 'ltr', the specified value of 'margin-right' is ignored and 'margin-right' is set to the value that makes the equation true; (2) if 'direction' is 'rtl', it is 'margin-left' that is ignored and computed from the equation.
- If exactly one of width, margin-left or margin-right is 'auto', its value is computed from the equation.
- If width and one or both margins are 'auto', the margins that are 'auto' are set to 0 and the equation is solved for width.
- If both margin-left and margin-right are 'auto', the equation is solved under the extra constraint that margin-left = margin-right.
If, after solving the equation, width has a value that is smaller than 'min-width', the computed value of 'width' is set to the computed value of 'min-width' and the constraint is evaluated again as if width had been specified with this value.
If, after solving the equation, width has a value that is larger than both 'max-width' and 'min-width', the computed value of 'width' is set to the larger of 'max-width' and 'min-width' and the constraint is evaluated again as if 'width' had been specified with this value.
Note: case 5 can be used to center block-level elements:
BLOCKQUOTE {
width: 30em;
margin-left: auto;
margin-right: auto }
This is different from 'text-align: center', which centers each line inside the block, but not the block inside its parent.
Block-level elements with a vertical flow inside a containing block with a vertical flow are analogous, but with a constraint on height and margin-top/margin-bottom:
(height of containing block) =
margin-top + border-top + padding-top + height + padding-bottom + border-bottom + margin-bottom
标签 ( Tags ) : css
标签 ( Tags ) : innertext,javascript,html
标签 ( Tags ) : javascript,onkeydown,源代码
- 10 confusions with their solutions before you start using CakePHP
- "X" Things, to Understand about Ruby on Rails
- Cake PHP useful tips: 21 Things You Must Know About CakePHP
- How to Bridge PHP and Java for Powerful Web Solutions
- 累了吗?来BSOD一下吧!
著名的Windows系统蓝屏。这也能拿来当屏幕保护。。。 - MP3 Player Steals £200,000 From Cash Machines
ATM看上去是越来越脆弱了。
- Censored Data via Amnesty International API
The Amnesty International API provides access to their database of content and sites that have been censored by both governments and corporations.
从 OpenNet Initiative (ONI) 提供的这张 Flash地图 可以看到相当直观的全球互联网信息审查的区域性强度对比。在 GFW 的巨大贡献下,最最红色的地域归属自然是毫无悬念;即便是在这么小的一张缩略图上,那一大块深红还是如此的醒目。
John Musser 说 : "There is more censorship occurring online than you may be aware of." 但对我们来说 , Censorship is everywhere. - The Habits of Highly Effective Web 2.0 Sites
- 網頁瀏覽加速法 (原文 Optimizing Page Load Time)
“使用者端可以做的就是打開 HTTP pipelining,Firefox 使用者只要在 URL 列打 about:config 然後找出 network.http.pipelining,改成 true 即可。而在伺服器端,也有些有趣的設定可以做”。 - EGOPOLY: Things that bother me about Ruby
- [JS]遭遇IE内存泄露
引起IE内存泄露的主要情况为js对象实例跟dom对象的相互引用、“内部函数引用(Closures)”以及DOM插入顺序泄漏。 - Memcache的分布式应用
- 是时候了,前端架构师 (原文 The Time is Now for Front-End Architects
“当后端技术伴随.Net, Rails和Java之类的框架发展得越来越抽象和强大,前端技术的潜在发展也日益复杂。在束缚前端技术潜在好处的差劲实现之前, Web需要更多的前端架构师。” - 电脑桌前的姿势要点
- 交通习惯
这位老外说:“我父母虽然对这样的交通不习惯,但是他们也没有说不好,以至说很佩服中国的司机能在注意四方的多种事物的同时安全地驾驶。”
当自己开始真正每天开着车子穿梭于城市之后,才发现马路上那些骑着脚踏车助动车或者迈着两条腿在机动车道上晃悠的人是多么的不珍惜自己的生命。从飞驰的汽车驾驶座上看出去,他们就像随时都会被忽略掉的一张张树叶。 - 关于心理暗示
- 《越狱》被指剽窃一对兄弟亲身经历 - I eric
- PES6出现!
下载源码包 make && make install 之后, apache 并不会自动往 init.d 里面添加自己的 httpd service。需要手工把 apache 安装目录的 bin/apachectl 拷贝一份到 /etc/init.d/httpd 。如果想让 httpd service 能够在不同的运行级别下都能自动启动,还需要 vi /etc/init.d/httpd ,在 #!/bin/sh 下面增加几行 chkconfig 需要的内容:
# chkconfig: 2345 70 30
# description: Apache is a World Wide Web server. It is used to serve \
# HTML files and CGI.
# processname: httpd
关键是 chkconfig: 2345 70 30 这一行,第一个数字 2345 表示让 apache 在 2345 这四个级别都自动运行;第二个数字 70 表示进程启动的优先级;第三个数字 30 表示进程停止的优先级。修改保存之后执行 /sbin/chkconfig httpd reset ,chkconfig 就自动在各个级别的 rc*.d 中增加 httpd 的 link 。要查看 chkconfig 是否 reset 正确,通过命令 /sbin/chkconfig --list httpd 就可以查看当前 httpd service 被配置在哪几个运行级别自启动。
标签 ( Tags ) : apache
之前总结了下如何用 css 来实现 table 的 border + bordercolordark + bordercolorlight 的边框明暗效果,然后有网友问我为什么他写了一个类似的 css 样式,但只能在 Opera 下正常看到表格的边框效果, IE 下则什么也没有。
于是我跑去下了个 Opera9 一看,确实如此。原因倒也不复杂:因为在 IE 下( Firefox 似乎和 IE 一致)如果某个 td 的内容为空的话,即便你设置了高度和宽度,这个 cell 的边框样式也是不会被显示出来的; Opera 则不管是否有内容与否,一概应用样式来渲染。这个问题刚毕业那会就碰到了,当时部门的科长来问我,后来我跟他说:给每个空的 td 加上 就行了。以后每次碰到这个问题,我就统统采用这个简单粗暴有效的方式来解决了。
但今天卯足了劲研究了几下,从 Jiarry 那知道原来 css 语法是允许我们对这些缺省行为进行改变的:使用 border-collapse:collapse; 和 empty-cells:show; 就可以让消失的边框显现出来。
class="test1": 加 border-collapse:collapse;
.test1{
border:1px solid #999999;
border-collapse:collapse;
width:60%
}
.test1 td{
border-bottom:1px solid #999999;
height:28px;
padding-left:6px;
}
| class1 | 这儿有内容 | |||
| 这儿有内容 |
class="test2": 加 border-collapse:collapse; 和 empty-cells:show;
.test2{
border:1px solid black;
border-collapse:collapse;
width:60%
}
.test2 td{
border-bottom:1px solid black;
height:28px;
padding-left:6px;
empty-cells:show;
}
| class2 | 这儿有内容 | |||
| 这儿有内容 |
class="test3": 不加 border-collapse:collapse; 和 empty-cells:show; 的情况下
.test3{
border:1px solid #999999;
width:60%
}
.test3 td{
border-bottom:1px solid #999999;
height:28px;
padding-left:6px;
}
| class3 | 这儿有内容 | |||
| 这儿有内容 |
标签 ( Tags ) : javascript,浮动层,源代码
标签 ( Tags ) : javascript,系统优化
RewriteEngine On
RewriteRule ^entry/([0-9]+)$ blog/entry.php?id=$1&avoidrepeat=1 [L]
RewriteCond %{QUERY_STRING} ^id=([^&]+)$
RewriteRule ^blog/entry\.php$ /entry/%1? [R=301,N]
由于一开始的时候主机并不支持 mod_rewrite ,所以日志的 url 都是带 ? 参数的动态 url 。这次决定把该 SEO 的都给 SEO 起来,于是在根目录下加了这个 .htaccess 文件。
但想要让原来已经被 Search Engine 收录的动态 url 自动转到新的静态化的 url 上来却颇费功夫。本来以为直接加一条 R=301 的 RewriteRule 就行了,可实际上 RewriteEngine 对于 rewrite 之后的最终url与初始url完全一样的逻辑会直接给 Ignore 掉,所以必须加上一个无意义的 &avoidrepeat=1 参数来让 RewriteEngine 认为这是两个不同的请求。另外对于 ? 后面的参数字符串必须在 RewriteCond 里面来匹配而不是直接在 RewriteRule 匹配。
经过这样的处理之后,无论是通过老式的 entry.php?id=XXX 方式还是经过静态化的 /entry/XXX 方式来访问,最终都会定位到 /entry/XXX 这个静态化的 url 上,对于 Search Engine 来说应该可以更快的根据 R=301 的状态码来更新它的索引库。
标签 ( Tags ) : mod_rewrite
现象:在 VirtualHost 配置块中启用 RewriteEngine ,进行 url rewrite ,结果发现重写到某一个目录下的url总是报错,说是 url 不存在。但通过实际的动态url去访问一切正常。
httpd-vhost.cnf相关配置如下:
<VirtualHost *:80>
ServerAdmin noname@gmail.com
DocumentRoot /www/html/scripts
ServerName scripts.zeali.net
ErrorLog /logs/scripts.zeali.net-error_log
CustomLog /logs/scripts.zeali.net-access_log common
<IfModule rewrite_module>
RewriteEngine On
RewriteRule /entry/([0-9]+)\.html /live/entry.php?id=$1
</IfModule>
</VirtualHost>
反复测试,发现如果把 /www/html/scripts 下的 live 目录重命名成其他的名字, url rewrite 就完全正常。难道说 live 是 mod_rewrite 的关键字?不太可能。继续检查,发现在操作系统的根目录下存在一个同名的 live 目录。把这个目录删除之后, rewrite 恢复正常。
结论: mod_rewrite 在执行 RewriteRule 的时候首先寻找的是操作系统的目录层次,而不是 DocumentRoot 下的相对目录层次;因此如果不幸在 DocumentRoot 目录下存在与操作系统根目录下一样的目录, mod_rewrite 将不会正确的找到 rewrite 的目标 url 。Updated 2006-07-18 14:40 -- 如果使用 .htaccess 文件设置 RewriteRule 的话,因为使用的是相对目录形式,就不会存在这个问题。
目前暂时找不到明确的文档来印证这个问题,或者说我对 mod_rewrite 的理解太浅。希望能看到更准确的说法来诠释这个现象。在此之前,只能认为这是 mod_rewrite 设计上的问题,注意不要让需要加入 RewriteRule 的文档地址与操作系统的目录结构发生冲突。
标签 ( Tags ) : apache,mod_rewrite
- EasyEclipse
Eclipse之所以势头如此强劲,甚至于搞到 Borland 都心灰意冷宣布出售整个 IDE 产品线 (虽然没有明显证据可以表明两者之间的因果关系),其开放性大概占了主导因素。
抛开开源免费的特性不谈,作为一个 SDK 而不是单纯的 IDE 面目出现,使得 Eclipse 具有了强大的生命力。只要是跟开发相关的功能需求,都可以作为扩展插件集成到这个统一的平台中去,最大限度的吸引了使用各种不同语言开发者的注意力( Firefox 打的也正是这一手牌)。
但在带来无比自由的同时,往往也会让初用者感到迷茫。如果你不知道该为你的 Eclipse 配些什么兵器的话,不妨到 EasyEclipse 逛逛。 - Google Answers: Understanding ulimit output
Pivot 自带的 wysiwyg 编辑器功能比较少,扩展起来也不方便,虽然 1.3 版本引入了 TinyMCE ,但都不合自己的习惯。好在可供选择的 wysiwyg 在线编辑器多得数不过来, Genii Software 甚至专门对这些编辑器做了详细对比。最终 我选择了 "excellent and easy to use" 的 Xinha 。不过再好的东西也会有 bug (尽管有时候 javascript 的脚本所谓 bug 往往是拜浏览标准的混乱所赐)。
最近发现用 Xinha 切换到 HTML Source 模式添加了图片 Map 区域之后( <AREA title="点击查看大图" shape="RECT" target="_blank" coords="0,0,81,150" href="http://www.zeali.net/images/lina/lina1.jpg"> ),切换回 wysiwyg 模式再切回来,AREA Tag 的 shape 和 coords 属性就消失了。一路跟踪下来,发现 Xinha 在 Toggle HTML Source 的过程中,使用了 HTMLArea.getHTMLWrapper 方法对整个内容进行了格式化处理,这其中用到了 attribute.specified 属性进行判断:
if (!a.specified && !(root.tagName.toLowerCase().match(/input|option/) && a.nodeName == 'value')) {
continue;
}
而让人想不通的是,对于 shape 和 coords 这两个属性来说,无论是否在 HTML 里面进行了设置, specified 的值都是 false ,而不是像 msdn 文档里面所描述的那样 “An attribute is specified if it is set through HTML or script”,只有像 title , target, href 这种比较常规的属性才能通过 specified 的值来判断是否已经做了设置。也正因为如此, Xinha 在对 HTML 代码进行重新格式化的时候, shape 和 coords 这两个属性的相关内容就被直接 continue 给忽略掉了。
有意思的是从 Xinha 上面的那段代码来看,已经对 input 和 option 这两个 Tag 的 value 属性进行了排除,可见 value 属性遭受的“不公平”待遇类似于 shape 和 coords 。可惜 Xinha 好事没做到底,msdn 貌似也没有明确的指出哪些 Tag 的哪些属性无法通过 specified 的值来判断存在与否,所以也只能是发现一例例外就在原来的语句基础上增加一个过滤语句了:
... &&
!(root.tagName.toLowerCase() == 'area' && a.nodeName.toLowerCase().match(/shape|coords/))
搞定,收工。
标签 ( Tags ) : xinha,javascript,wysiwyg,error
今天偶然发现在 Firefox 下点击我 Blog 页面头部的
图标并不像在 IE 下那样可以正常的跳转到 RSS feed XML 页面。难怪之前好像有朋友问我说我的 Blog 上的 RSS 订阅哪里去了?
原因:因为我用的是 window.navigate("URL") 而不是 location.href='URL' 来做跳转;不幸的是 Firefox 并不支持 navigate 方法。所以以后任何地方要做跳转,忘了 navigate 吧!
RSS feed 图标可以正常点进去了,又发现 RSS feed XML 的内容显示似乎有点异样。仔细一看原来是正文的内容没有被正确的转化回 html 格式化内容。
原因:因为我为这个 xml 文件加了 xsl 定义文件,并对于每篇日志的正文部分使用了 disable-output-escaping='yes' 属性来通知浏览器的 xml parser 不要把这部分 html 代码转义。同样的,这个属性为 MSXML 所支持,但 Transformiix 引擎就不支持了。 Firefox 等浏览器使用的 XSLT Processor 恰恰是 Transformiix 。所以,对于 Transformiix 系的浏览器,只能采用“曲线救国”的方法了,利用 javascript 代码找到所有没有被浏览器自动转义回来的内容并进行正确的转义, BunnyQ 在日志中详细描述了解决方案(包括其他几个需要注意的 XSL 兼容性问题)。我最终使用了比较简便的方式:
在原先的代码
<div class="list_introduce" id="content">
<xsl:value-of select='description' disable-output-escaping='yes' />
</div>
后面增加一段专门针对Transformiix的处理代码
<xsl:if test="system-property('xsl:vendor')='Transformiix'">
<script language="javascript">
var el = document.getElementById("content");
el.innerHTML = el.textContent;
</script>
</xsl:if>
标签 ( Tags ) : firefox,javascript,error,xsl
css里面漏写一个分号,在本地浏览居然还能显示正常的效果,通过域名访问css的效果就不见了;
while($val=array_shift($arr))死活shift不出东西来,改成foreach($arr as $val)才正常;
但想通过测试代码来重现这两个现象,居然重现不了,css漏写分号就是显示错误,array_shift也能正常shift。郁闷ing。
刘润说:“不要搞封建活动。”再离奇的表象都可以找到合理的技术性解释。只不过在我们发现真相之前,往往被表象指引到一个错误的方向去思考问题了。
标签 ( Tags ) : css,array_shift,error
同一段代码在不同的机器上执行结果却莫名其妙的不同,这是最让人郁闷的事情。这两天用 DHTML 的 insertCell 方法来通过 javascript 脚本动态增加表格内容。在自己的本本上一切正常,等到让别人用的时候发现 insert 进去的 td 顺序正好倒了过来,本来应该是第一列的变成了最后一列。折腾半天,发现调用 inertCell 方法的时候可以不填写 index 的值,默认情况下自动添加td到当前行的末尾 oTD = TR.insertCell( [iIndex]) 。于是把所有的 index 参数去掉,问题消失。
等到后来想写段测试代码来重现这个问题,居然死活重现不了。
猜测:只有当 insertCell 遇上 XXX 之后才会出现插入顺序错误的问题,并且只有在WinXP sp2的 IE 上才会出现(我的本本是sp1,甚至我在 Firefox下看到的都是正常的)。
标签 ( Tags ) : insertcell,dhtml,javascript
- 让文字自动适应Table宽度
关键样式:
table-layout:fixed 固定布局的算法,则表格被呈递的默认宽度为 100% (For IE,Mozilla)
text-overflow:ellipsis 当对象内文本溢出时显示省略标记(...) (For IE)
overflow:hidden 不显示超过对象尺寸的内容 (For IE,Mozilla)
white-space: nowrap 强制在同一行内显示所有文本,直到文本结束或者遭遇 br 对象 (For IE,Mozilla)
对Table设置第一个样式,对Table里面的tr或td设置后三个属性。这样可以实现表格不会换行,过长文字在IE下自动显示为... - 还是选择使用Leadbbs做论坛
- 用vsftp建立个人ftp站点
- 3 Ways to Read Like a Professional Smart Person
- 分析百度的中文分词结果
标签 ( Tags ) : css
- CSS Caching Hack
为了防止页面被浏览器给Cache住而导致用户看不到更新了的内容,我们通常会在URL后面添加一个随机变化的参数,比如 http://.../myarticle/10022.xml?e234kk23s8234 。不过我们往往会忽视 CSS 样式文件被Cache的后果。事实上现在的页面内容和表现日渐分离,整体观感完全依赖于 CSS 文件,一旦你对服务器上的 CSS 文件做了些关键性的修改(比如增加了样式定义)并且在你的 html 文件里面使用了这些新的样式定义,用户再来浏览你的页面可能会发现页面忽然变得极其丑陋,必须按Ctrl-F5强制刷新所有内容才能看到正常的页面表现。这是因为在你的html页面得到更新的时候,css样式文件并没有被浏览器同步更新。因此,我们应该为引用的css样式文件也添加这样一个可以变化的参数来根据实际情况要求浏览器真正重新抓取一遍,比如:<link rel="stylesheet" xhref="http://www.zeali.net/css/zeal.css?version=1" type="text/css" /> - Google Related Links
类似 Google AdSense ,在你的页面上放置一段代码,Google自动把相关的新闻、链接显示出来。当然理论上来说这些相关内容是真正与你的页面相关,而非别人通过付费购买的 AdWords ,你也并非通过放置这段代码来赚取广告费,纯粹为了提高页面内容的丰富性。这样一个缺少明显驱动力的东西愿意去使用的人大概也就不多,何况据说目前这个服务对中文的支持度还有待提高。。 - How to quit your software job and become a millionaire instead
我在之前的日志里面提到:“当这种冗余的数据传输变得相当频繁的时候(比如我之前所做的即时比分系统为了让浏览器第一时间得到最新的比分变化XML数据必须以2、3秒一次的频率不停的刷新这个XML地址,或者类似的一些即时证券股票交易系统),由此所造成的网络带宽的无畏消耗会变得相当惊人。”
对于这个问题,临时性的解决方法是采取各种手段(压缩XML数据、采用YAML格式、优化 Http Header)减少数据传输量。但从根本上来说,只有让数据按需传输,才会使流量最小化。本来计划设计实现基于 server-push + Ajax 版本的即时数据分发系统,因为种种原因完全搁置了起来。现在 Alex 给它取了个名字叫 Comet ,并详细的描述了这个名词所代表的内容。
意料之中的,不少人对这个新名词嗤之以鼻。但在我看来,即便这个 Comet 是一个卫浴清洁剂品牌,至少是对现有技术的归纳总结,跟别人介绍的时候也免得大费口舌。就像 Ajax 一样,虽然只是几样老技术的综合体,之前也有不少人已经在用着这些技术;但只有在 Ajax 这个名词流行起来之后,才真正得到了大规模的应用,各种基于 Ajax 的 frameworks 才争相出炉。对于后进的开发者来说,有了 Ajax 这么一面大旗指路,就意味着少走一大段别人走过的路。
所以,不管这个架构最终会以什么外貌风行,姑且就叫做 Comet 。 Comet 实际上就是在传统的(这个词对于 Ajax 不知道是否合适) timely client-side pulling Ajax 基础上引入 server-side push 机制,在客户端(通常是 Browser )与服务器之间建立 long-lived 连接, server根据需要把数据主动的 push 到客户端。要做到这一点最简单的可以利用 HTTP 协议的 Keep-Alive 头,但如果要能很好的支持大并发量、方便的实现业务逻辑扩展,就不太可能基于传统的 Web server 来实现服务端的程序,只有重新设计 server 。
正如 Ajax 风行之前已经有许多开发者在利用 XMLHttpRequest 来实现着自己的应用一样,有着 Comet 概念的产品目前也并不算少:Lightstream、ICEfaces这样的商业化产品;Pushlets这样的开源项目。相信在一段时间的技术沉淀之后, push style Ajax 会像当初的 Ajax 一样得到个响当当的头衔。
- ActionScript 3 Language Specification draft released
ActionScript 3.0 语言规范草案发布。AS3运行于重写的AVM2执行虚拟机之上,之前的AVM1为很多人所诟病的运行效率将得到大幅的提升。同时AS3语言在设计上引入了更多OO的概念,在带给开发人员便利的同时也使得AS3.0在向下兼容的时候不得不有所舍弃。不论如何,AS3的推出足可以见Adobe对于Flash富客户端应用发展的野心。或许哪一天,当你所有的Web应用都可以包容在Flash之中轻松实现的时候,这个平台逐渐演变成为独立于浏览器之外的客户端平台也说不定。。目前要想体验AS3,你需要先安装 Flex Builder 2 Beta。 - JavaScript Style Attributes
CSS样式属性与JavaScript的属性变量之间的对应表。很实用的东东。 - 迟到的模仿:JDBC 3.0 RowSet,类似于ADO的编程方式
Rowset对比于ResultSet,除了不用保持Connecton外,更重要特点是能够类似于ADO的编程方式,直接对Row赋值来进行Insert与Update, 而不用写SQL语句。 - Don’t Use Frames
- Which PHP framework holds a promise for the future?
- 8 Ways to Extend Wireless Network Range
- Bloglines 新的 Feeds 管理介面
- 最短最酷后缀的1G邮箱,@x.cn
标签 ( Tags ) : actionscript,flash,css
- Using prototype.js v1.4.0
prototype的非官方使用指南,有多国翻译版本(包括中文)。 - Seven ways to toggle an element with JavaScript
- PHP upload progress
显示文件上传进度 - 10 Things a Web Developer should do for the Client
- 9 tips for running more productive meetings
- Seven Deadly Web Analytics Sins
Far too often, the purpose of web analytics is to produce a graph that goes up and to the right. But, good, meaningful web analytics is a deductive process; not just an effort to produce a chart. - 揭穿理发店9大骗人谎言
看来以后到发廊最好就是单剪,别的啥也甭弄。
标签 ( Tags ) : prototype
一直以来想把这个Blog从GB2312改到UTF-8编码,但因为pivot采用的文本数据库使用PHP的serialize存档方式,数据结构依赖于字符串长度,一旦从GB2312改到UTF-8,非英文字符串的长度就发生了变化,原有的日志读取将发生错误。日志一天天增多,编码切换可能的潜在危险就让我越来越不敢去做这件事情了。
昨天终于咬咬牙,决心彻底搞定这个问题,算是给自己新年带来的第一个新气象吧。写GB2UTF8的批量日志文件编码转换脚本、更新语言文件/模板文件、增加新的UTF-8相关的字符串处理函数,一切在本地机器上测试相当顺利。没想到覆盖到服务器上的时候居然出现莫名其妙的问题,页面没法正常重新生成。用ftp维护上传文件是件痛苦的事情,经过几个小时的折腾,终于是“暮然回首”,在pivot站点上发现了db repair的工具可以轻松的解决问题,修复升级之后被局部破坏的数据文件。
总算大功告成,两点教训:
- 覆盖之前一定要在服务器上备份目录,而不是只在本地备份!不同环境下的备份即便只是简单的copy,也可能存在差异性。没有服务器Shell登录的权限,也可以想办法用PHP的passthru之类的系统命令调用来曲线执行Shell命令。
- 碰到问题最好先到官方站点找找答案。看似简单的问题可能会越变越复杂,不如在自己给自己设套之前看看是不是有更简单现成的解决方法。