解决Flash的黑框问题

Flash 是目前十分普及随处可见的网页动画格式,但不知从何时开始,Flash 在IE中出现了恼人的大问题,当你想要按下Flash选单中的按钮或广告时,按第一下没反应,再按一次才会有效果。这是这个Flash动画制作者不留心的 Bug 吗?No No No…,快回去检查你以前做过的 Flash 网页,是不是也会如此。

这是什么怪问题?

首先用 IE 来浏览一个很久以前制作、包含 Flash 的页面,当你用鼠标滑过某个 Flash 动画上面,Flash 动画的四周会出现一圈黑色斜线的外框,咦…以前并没有这样,而且这是很难看又丑陋的,尤其是当你的 Flash 动画需要和网页背景融合为一的时候。接着,鼠标旁边马上就出现一串类似这样的提示文字:点按已启用并使用这个控件。
然后当你用鼠标滑过 Flash 中的按钮或选单,按钮不会有任何 Roll Over 的效果,选单也不会出现,只会出现那段黄底黑字的小提示,真是糟糕啊!你必须要先在Flash动画上面用鼠标点一下,代表启用了这个 Flash 控件,按钮和选单才会开始有作用。

为什么会这样?

现在是床边故事的时间…缘起于1999年的时候,Eolas Technologies公司指控,微软使用了Eolas的专利Web浏览器技术让IE浏览器得以加入add-on与applet软件,也就是所谓的外挂(plug-in)。Eolas声称该技术使得微软的IE浏览器得以Netscape和浏览器一较高下,并且逼得Netscape在90年代末期终于被微软击败。Eolas曾经为此起诉微软支付12亿美元。
2003年8月,美国芝加哥法院在认定微软在IE浏览器中侵犯plug-in技术,并判决微软必需向Eolas公司及加州大学赔偿5.21亿美元。(其中加州大学是该专利拥有人但于1994年将该技术授权给Eolas公司。)尽管Eolas公司只建议微软向他们给付相关技术的授权费用,但微软决定继续上诉的同时顺便修改浏览器。
于是在2004年的年初,微软发布了ActiveX相关的更新,让这些使用plug-in技术而内嵌(embedded)到网页里面的内容与媒体,无法主动与浏览者互动,包括了鼠标滑过、按下等等的互动效果都被阻挡住了,浏览者必须先点一下内嵌的内容来启动它,才能够与之互动。不只有Flash,所有内嵌在网页里面媒体内容都被这个更新影响,也包括了Quick Time、Real以及Media Player。但请特别注意一点,这些内嵌的内容媒体仍旧会自动播放;网页中的Flash动画、视讯影片仍然看得见而且会跑,只是无法立即和浏览者互动,也就是说在没有启用它之前,是不会有任何鼠标互动效果的。

※资料来源 cnet.com

该如何解决?

微软所发布的这个ActiveX更新的确让许多浏览者觉得很困扰,对于Flash的网页提供者更是影响甚巨。不过上有政策下有对策,Flash开发厂商Adobe(以前叫Macromedia)就提供十分简单而且良好的解决方案,如果你使用的是最新版的工具软件(Flash 8 或Dremaweaver 8),可能在你还搞不清楚状况前就已经会自动解决掉了这个问题。
要解决这个问题可以说是非常简单,也可以说有点复杂。简单的部份是,既然这个ActiveX更新的限制是针对”内嵌”媒体,那么只要让媒体内容不是内嵌在网页中,而是外部的档案,就不会受到这样的限制啦!是不是很简单啊!
不过…Flash动画都是在网页里面播放,和其它文字图片排列在一起的,该如何不内嵌在网页里面而又能够在网页中播放呢?解决方法就是由JavaScript程序(使用document.write或innerHTML)来输出Flash动画相关的HTML标签(<object>与<embed>),而且重点是:这段JavaScript程序必须是外部独立分离的档案,不能直接写在网页里面,例如使用<script src=”xxxxx.js”>的方式将外部的JavaScript程序加载进来。如此一来这段JavaScript程序就不是内嵌的东西,而由JavaScript程序所输出的Flash卷标当然也就不算是内嵌的东西,自然不会受到IE浏览器新的限制啦!
聪明的你可以能会问说:如果浏览器不支持JavaScript或把JavaScript关闭了怎么办?这是个好问题!(没想到这个问题的人并不代表你不聪明哦…)如果没法使用JavaScript输出Flash的HTML标签,那么就…不要用JavaScript输出啊!使用最原始的方法,让Flash动画保持为原有的内嵌对象就好了,Flash动画仍旧可以播放,只是需要浏览者多点一下鼠标来启用而已,但有总比没有好吧!

动动手吧!

我不会JavaScript怎么办?先别恐慌!先前有提过,如果你已经在使用新版本(8.0)以上的Flash或Dreamweaver,就已经自动解决了这个问题,如果你有旧的网页需要更新,使用Dreamweaver也很简单。如果你没有Dreamweaver,可以将JavaScript程序代码copy过去,做简单的修改便能使用。

使用Dreamweaver(8.0.2版以上)

1. 启动Dreamweaver,请务必将版本更新到8.0.2以上。到Adobe的网站即可下载免费的Update。
2. 开启新的HTML檔,插入Flash内容(SWF档案),这时Dreamweaver就会自动帮你产生所需的JavaScript与HTML Code,而且这段Code是已经修正过ActiveX的限制。
※关于在页面中插入Flash内容的方法,应该不用再提了吧!
3. 如果是既有的旧页面,其中包含Flash内容的,用Dreamweaver开启时会询问您是否要自动转换标签,以避免ActiveX的限制(如右图),这时只要按下「是」,万事就搞定了。
4. 这时Dreamweaver会在网站根目录下自动产生一个叫做 Scripts 的数据夹,里面有一个 JavaScript 档案 AC_RunActiveContent.js。这就是解决 Flash 问题所需要的档案,发布网站时请记得一定要将这个数据夹和档案一起上传到服务器上去哦!
自行套用Javascript – 使用 document.write 或 DOM
如果你会JavaScript,也可以直不用需要加载Adobe所提供的AC_RunActiveContent.js档案,自己写一个外部的JavaScript档案来使用,比较有弹性。原理很简单,只要在外部的JavaScript中使用document.write或DOM的innerHTML来输出Flah所需的HTML code即可!
1. 例如在JavaScript档案中写:
var flash_code = ‘‘;
document.write(flash_code);

※请特别注意的是,显示出Flash的HTML code必须在同一列之中,不可以断行。
2. 将这个JavaScript档案存盘(例如檔名叫做show_flash.js),然后加载到要显示Flash的网页里面,例如在HTML页面中这样写:

3. 当然也可以加上<noscript>的部份,让无法使用JavaScript的浏览器一样可以看到Flash:

聪明的你会发现,用来显示Flash内容的HTML code完全都是一模一样的,都是<object>和<embed>,不同的地方只是在于,要把这段HTML code写在哪里而已。

单元测试

有些道理,大家都明白的,但真正要做的时候,却很少有人能落到实处。

在学软件工程的时候,第一次听到了单元测试和测试用例这些词,印象很深刻 。

书上讲的都是软件开发这个行业几十年来总结的经验,很有道理,也很有说服力,我也十分认同书上的做法。

我也感觉自己是一个喜欢追求完美的人,看到书上说的那些测试的方法,比如边缘测试之类的,在感叹前人总结的方法很优秀的同时,自己也暗下决心,以后我写的程序,也要有规范的接口,有明确的输入输出,要有完备的测试用例,把每一个细节都测试到,让自己的程序表现完美。

然而,在现实中,总是事与愿违。

大学期间写的程序就不说了,我到现在正式工作已经两年半了,写的代码少说也就几万行。Bug是难免的,但总是被别人发现。

我一直没有做过规范的单元测试。

原因是多方面的,但主要在自己。

懒惰,是程序员最大的敌人!

当需求明确时,我会立即投入编码,把脑子里那些自认为不错的逻辑,用程序代码实现出来,这个过程是十分开心的。程序完成后,输入预定的参数,得到预想的结果,那种成就感,难以用语言形容。

我想问一句,这个时候,这个程序算是开发完毕了吗?

以前,我是这样认为的。我也坚信,国内绝大部分的程序员,都是这样认为的。

实际上,这就好像万里长征刚迈出第一步而已。虽然有些夸张,但事实如此。

你给你的程序写出测试用例了吗?你对程序的每一个模块,做了单元测试了吗?在输入数据的时候,是否输入了边界值?是否输入了非法值?有没有试过不给输入,看看程序输出什么?

当然,那些自认为做事严谨的人,多少是会做一些测试的,这也使得他们的程序,比一般人的更稳定一些。

我想说的是,自己写的程序,定势思维会很强的,你很难想象出一些匪夷所思的参数去测试你的程序。

程序就像你的孩子,你希望他健壮,也许你会让你的孩子参加一些艰苦的锻炼,但你绝对不会拿个大铁棍砸向孩子的胳膊以检验他的骨骼是否强壮。

开个玩笑地说,拿铁棍砸别人的孩子,大多数人还是做的出来的。

我曾经自认为考虑的十分周到的程序,被人一眼就挑出一个bug,自己回去改,这个bug好了,另一个bug也随之而来,最后搞的svn被我当成磁盘一样用,改个字母都会提交一次!

话题有些远了,这篇文章的出发点,就是今天彻彻底底的进行了一次单元测试,真的是感受良多。

在做这个项目的时候,伴随着开发,我也一直在写测试用例,也一直在反复测试。我很早就知道PHP的单元测试框架,也看过很多文章,里面的很多过程和逻辑我都很清楚。可能还是因为懒吧,我只是把所有的测试用例放在一起,每次循环跑一下程序,把输出打在屏幕上,测试的时候看一眼,没什么问题就过去了。

这样很不好,还是思维定势的问题,有时候出现问题,可能就在一些细节的地方,面对满屏的输出,你是无法准确判断每个输出是否完全正确的。

后来,试着按照标准的测试框架的方式,对每一个输入,认真地写出人工判断的期望输出,然后由程序自动执行,看看是否能全部通过。

结果当然不会出乎意料,有一半的测试没有通过。

再返回头去改程序,这时才发现以前考虑逻辑的时候想法有多么简单,有那么多遗漏的地方。

你也可以邀请你的同事,鼓励他们想出各种办法来搞垮你的程序,你需要做的,就是把他们每一个稀奇古怪的输入都认真地记下来,这才是你最宝贵的财富。

我听过以前的同事讨论程序,说他新做的模块,测试了上千万的数据,一个bug都没有,但一上线,就出大问题,而且每次都这样。
另一个同事对他说,合法的输入,测试多少都没有意义,只有那些非预期的,非法的和异常的输入,才是重要的测试资源,而且,这些case都应该好好保留,以后每次测试,就从这些bad case入手。

我对这番对话记忆深刻,从那时起,我也在逐渐应用这种方式去测试我的程序。

今天,终于切身地感受到这种开发方式的好处。

我在线下修改一个bug,就可以避免上万的用户在线上碰到bug。

作为互联网产品,线上服务的稳定性绝对是第一位的!

话题基本到这里,我想再引申出另一个问题,就是关于“落实”这两个字。

现代人类文明,大概有2000年了,我们的前辈,给我们总结出了大量的经验教训,希望我们能少走弯路。

我领悟出一个道理,世上绝大部分事,都很容易做,每一份事业,都很容易成功,因为很多是前人做过的,他们总结的经验,我们很容易就能得到。

可实际情况却是,大部分人都不能把事做好,都不能做出一份成功的事业。

是他们不懂道理,没听过经验教训吗?

我想不是,原因就在于,他们没有很好地落实每一项应该完成的事。

就拿上学来说,我们都经历过至少十几年的校园生活,大部分人的学习成绩应该都不是所在学校的No.1吧?

你回想一下,那个时候的年级第一,他比你聪明吗?不见得吧。

那个时候老师都说,要好好学习,课前要预习,上课要认真听讲,课后要按时完成作业,不懂就问。很简单的道理,不是吗?我的印象中,学校里学习好的人,平时都很贪玩的。他们不比我聪明,晚上熬夜也没我时间长,他们比我学习好,只有一个原因,他们听话。他们认真地做到了老师要求的每一件事,而且一点也不难,很容易就超过了别人。

思维再跳跃一下,就说这开车吧。

不准酒后驾车,不准疲劳驾驶,交通路口要减速慢行,要与前车保持安全距离。

很简单的四条吧,大家看看新闻,哪次事故不是因为酒后驾车,超速行驶呢?出了事,轻则误事赔钱,重则车毁人亡,你说做到这几条有多难呢?还是难以落实。

再回到程序开发上,就像我遇到的问题,我们有很多开发经验,有软件工程,有测试框架,有编程习惯,有代码标准,可真正做到的有多少呢?有几项是我们真正落实的呢?

还有创业,我认为也一样。

很多成功的老总,都会总结他的经历。很多人都说,他之所以成功,就是因为坚持不懈,锲而不舍地做了一件事,把这件事认真地做好,他就成功了。

而现在的很多创业公司,拿着几千万美元的风险投资,就不知道该干嘛了,这也干,那也干,这么大的互联网,没有他不干的。讲起道理来,他比谁都能说,真正做起事来,前人总结的经验,就完全抛在脑后了。

还是一句话,落实很难。

还是收起浮躁的心,踏踏实实,脚踏实地,把最简单的事做好,每落实一件事,离成功就会更近一步,我坚信!

说点什么

现在是周五22:20,本来想玩会儿游戏,可想起blog已经好几天没写东西了,攒了好多想说的,再不说就忘了。

这周有点郁闷,但也比以前更充实一些。

上周给新部门的同事讲了一些PHP网站开发方面的经验,也聊了一些优化方面的东西。来的人不少,弄得我挺紧张的。

因为比较忙,在做一个紧急上线的新项目,没有做充分的准备,有些东西没有讲得很深入。后来还讲了一个IP查询算法,是我自己想的,讲出来才知道,原来大家都有过研究。

肯定让来参加讨论会的同学们有些失望,我也觉得很郁闷。

后来和同事聊了聊,我给人的感觉是知道的东西挺多,但都不深入。

我不希望自己是这样,可实事求是地讲我确实一直存在这样的缺点。

可是话又说回来,我所了解的东西,也没有完全讲出来,我有自己深入了解的东西,工作2年了,每天都很忙,积累了很多经验,恐怕不可能在2个小时内全都讲完吧。

从另一个角度看,我觉得自己被别人小看了,也许这才是我郁闷的真正原因。

每个人都有虚荣心,像我这样的开发人员,最希望得到的,恐怕就是得到别人对我技术的认可吧。

恰巧昨天看到公司内部的技术周刊,有人讲了很多Web开发方面的东西,主要是html、css和javascript的,写得很长,很深入,也很具体。

我做Web开发也2年多了,那篇文章里说的每一条,我都知道,而且有些方面比文章里写的有更深的研究,但,我唯一没有做到的,就是把这每一点都写下来,都积累成文字记录,传给大家看。

这个问题我前一段时间已经意识到了,通过这件事,也让我有了更深的体会。

因此,我建了这个blog。

我也要把我积累的点点滴滴,都写下来,为自己记录,也为别人分享。

互联网最大的魅力,就是信息传播不需要时间。但,中国的互联网环境,大多还是抄袭和模仿,真正写原创的很少。

不知道是因为中国传统的文化底蕴中略带一些保守的思想,还是其他什么的,我不知道。

以前我也是这样,自己学点东西,很怕让别人知道,殊不知学的这点东西,N年前就被人家研究透了。

我的好朋友Lqx,我都叫他星爷,曾经告诉我,计算机的知识,只有先知和后知,没有能知和不能知。这句话我一直记忆犹新。

我的很多经验,都是星爷教我的,他从来不保守,慢慢的我也变得乐意与人分享,最重要的是在与人分享的同时,也极大地提高了自己,也许保守的人永远也无法体会分享带来的乐趣。

前2天我更新了blog右下角about的内容,想告诉大家我很愿意为互联网创造更多的内容。

我也想带动屏幕前的你,利用各种方式,用互联网记录下你的事。

前一段时间去过一次故宫,看到太和殿和乾清宫,感觉里面很破旧,我就想几百年前,康熙和乾隆在这里执政的时候到底是什么样呀?我站在大殿门外的御道上,联想几百年前的大臣,当年他们从这里走过的时候,在想些什么呢?他们会不会想到几百年后会有一个年轻人站在这里揣摩他的心思呢?

可惜的是,当时的科技水平有限,没法用影像去记录,以留给后人。

今天,我们有互联网,有完善的信息化记录设备,为什么不记录下一些东西,分享给今天的你,流传给我们的下一代呢?

就像本文的标题,“说点什么”。

我会经常来说点什么,你呢?

许三多 百度 首页人物

 Baidu

许三多,电视剧《士兵突击》的主人公。一个农村的土孩子,一个突然的因素,进入了最为需要聪颖灵巧年轻人的部队,也将许三多推入生命的绝境,从而开始了一个“孬兵”在绝境中成长,在失去中成熟的故事。这样的绝境,似曾相识。有多少人没有过这样的生命绝境呢?面对这样的绝境,我们能够做什么?……

详情请进:http://renwu.baidu.com/

GMail 安全隐患 Google 密码

尽管我下面要讲述的情景并不会经常出现,但后果却是很严重,希望引起Google的注意,同时也希望能提醒提供类似功能的其他公司!

我注册了Google的帐号,有了一个GMail邮箱,他很好用,而且我每天都要登录我的邮箱收发信件。

正是由于使用频繁,我在登录的时候,选中了“在此计算机上保存我的信息”,免去了每次登录都要输入密码的麻烦。

我在家,在公司,在我的笔记本上,三处地方,都应用了这种设置,所以我在这三台电脑上打开http://mail.google.com的时候,都是直接进入邮箱。

如果,我因为某事,不再继续为这家公司工作了,而我临走时忘记清空浏览器的cookie,那么,这个公司的网管,就可以登录我的系统,查看我遗留的各种文档。

当他再次打开http://mail.google.com的时候,直接进入了我的邮箱!!!

这是一个非常严重的问题。

我曾经想过补救,我认为这方法应该有效,但Google没有这样做:

我在家里的电脑上登录GMail,更改我的密码,然后退出登录,当我再次登录时,需要输入新的密码。这个过程没问题。

但我用我的笔记本,在浏览器上打开http://mail.google.com,依然可以访问。

这就是问题的根源!!!

这个时候,那家公司的网管,是可以访问我的邮箱的,因为Google没有对密码做数字签名!这是问题的关键!也是我这篇文章的核心内容!

在Web安全方面,Google应该有很深的经验了。

利用cookie记录登录状态,避免每次输入密码,是很好的设计,很人性化。

唯一的缺点,就是没有提供给用户一个既安全又方便的途径来取消这一遍历登录方式。

如果是我,我会进行如下改进:

1、用户登录的时候,对用户的密码做数字签名,比如,随机生成一个密钥 randKey
2、在服务端,以用户的密码 userPassword 和刚才这个密钥 randKey 作为输入参数,传给一个复杂一点的加密算法
3、加密算法算出一个密码签名 passSignature,这个值是单向的
4、把 randKey 和 passSignature 存到cookie里
5、Google 的服务端保存用户的密码(其实在你注册的时候,就已经保存了)
6、当用户登录的时候,服务端接收到 cookie 中的 randKey 和 passSignature,在服务端验证 passSinature 是否和 randKey + userPassword 加密过的字符串匹配,如果匹配,则正常登录
7、如果不匹配,要求用户重新输入密码,密码正确,说明用户身份正确,在重复第1步

说明,这样的好处是,如果用户在其他客户端上修改了密码,那这个用户再其他所有使用过的浏览器上 cookie 中保存的 passSignature 都将失效。

还有,在第5步,保存密码的环节,其实,userPassword 不必是密码的原文,经过单向加密过的密文也一样,可以用md5。

经过这么几步,用户帐户的安全性可以得到很大提升,对Google来说,这个计算过程很简单,对性能的影响微乎其微。

Google的PM和RD,你们能看到这篇文章吗?

z-index 层次 堆叠 style zIndex

CSS可以处理高度、宽度、深度三个维度。在前面的课程中,我们已经了解了前两个维度。在本课中,我们将学习如何令不同元素具有层次。简言之,就是关于元素堆叠的次序问题。

为此,你可以为每个元素指定一个数字(

z-index

)。其原理是:数字较大的元素将叠加在数字较小的元素之上。

比方说,我们正在打扑克,并且拿了一手同花大顺。我们可以通过为各张牌设定一个

z-index

的方式来表示这手牌:

z-index

在这个例子中,我们采用了1-5五个连续的数字来表示堆叠次序,但是你也可以用五个不同的其他数字来取得同样的效果。这里的要点在于:用数字的大小次序反映希望的堆叠次序。

扑克牌这个例子的代码可以这样写:

#ten_of_diamonds {
position: absolute;
left: 100px;
bottom: 100px;
z-index: 1;
}

#jack_of_diamonds {
position: absolute;
left: 115px;
bottom: 115px;
z-index: 2;
}

#queen_of_diamonds {
position: absolute;
left: 130px;
bottom: 130px;
z-index: 3;
}

#king_of_diamonds {
position: absolute;
left: 145px;
bottom: 145px;
z-index: 4;
}

#ace_of_diamonds {
position: absolute;
left: 160px;
bottom: 160px;
z-index: 5;
}

该方法虽然简单,但却能应付许多情况。你可以将图片叠加到文本之上,也可以将文本叠加到文本之上等等。

层次可以应用于许多情况之下。例如,可以用z-index实现为标题(headline)增添效果(避免了采用图片的方式)。这样,一方面,装载文本的速度比图片要快;另一方面,采用文本可能更有利于提高网站的搜索引擎排名。

PHP 数组 递归 magic_quotes 回调函数

为了适应不同的服务器设置,首先判断是否打开了 magic_quotes,如果打开了,在开始的地方就全部过滤。
后面程序统一默认为 magic_quotes 已关闭,避免了多次转义的问题。
一行代码的函数,两点需要注意,一个是递归调用,另一个是传递回调函数的方法,可以引用一个类的静态方法。
实现过程,比较优雅,不是吗?

DNSPod Squid CDN

好几天没有写东西了,最近有点忙,一直在学东西。

今天看了看 用DNSPod和Squid打造自己的CDN ,是长篇教程,感觉还不错,我转载了一下。

在论坛里发的,在这里发实在是太占篇幅了。

另外,为了统一格式,做了一个小的javascript工具,地址是:

http://code.leakon.com/javascript/auto_format/

可以去掉连续换行,并加入首行缩进,而且支持正则替换,功能很单一,慢慢完善吧。

想看代码,可以去http://leakon.googlecode.com/svn/trunk/leakon/javascript/auto_format/,这是Google的SVN服务。

PHP header location 继续执行 exit

PHP的header可以输出http头部信息,前提是,在header之前不能输出任何内容,因为所有的内容都作为http的body输出给客户端了,一旦有body的内容,就不可能再添加任何head部分的信息。

header函数的一个常用的方式就是用来做转向,redirect。

比如,我需要转到某个地址,只要执行下述代码:

浏览器会收到一个302的http状态码,告诉他这个内容已经被转移了。

重要的是,php会在调用header函数后,继续执行后面的代码,你可以用我的代码亲自试验一下:

肯定会执行到fwrite函数的,打开header.txt文件,检查时间!

对此,解决的办法是,要在每一个header函数后面加上exit,保证当前页面停止执行,进而转向location指定的地址。

为了避免到处都是exit,可以写一个专门用作转向的函数,比如:

另,为了避免在header之前输出body的内容,许多php框架都采用了php页面尾部不写?>的方式,因为有些人总习惯在?>后面添加一个换行,这真的是个不好的习惯。

PHP 基础

这是很简单的一个问题,但是我做错了。
我在这里这么强调他的简单,你肯定会比较注意他的陷阱。
但是,在你的代码里,会不会也有类似的情况呢?你还会注意到这些细节上的问题吗?


一次性答对的,说明你的基础比较扎实了。
你慢慢看我写的其他文章吧,我回去补课了……