笨蛋的微软!

微软,M$,确实笨蛋,一个msn都搞不好,windows版的就不用说了,使用非常不爽,功能差劲,无怪乎公司里面用它作为IM使用,没有其它功能,不会“影响”员工工作。

手机版的,更差劲,连切换网络接入点都麻烦得让人崩溃:切换后,要重新启动,才能生效,每次刚启动手机版msn时,刚开始的几秒钟时间,都是要使用上一次的连接接入点,如果是grps的话,要这样浪费流量!

跟瘟98一个德性,要无数次的重启。

后来新一新的瘟到死好一点,但也不过而而。喂死它,已经成了M$的又一个永远无法抹去的耻辱,钱门大叔也因此背着一串骂名无颜引退,幸亏他老婆之前为它打的“狡免之窟”,改行做了慈善,以此冲淡一下背负的恶名。

瘟七在喂死它的炮灰掩护下,获得了一点自尊,但是......

一堆IE,尤其是最垃圾、却又最顽固的IE6,让无数做过网页的人咬牙切齿恨之入骨食肉寝皮。

M$ office,还在为M$挽回着一点点荣耀。

Linux系统内核代码特色

1。缩进

8个字符的长度设置为缩进的长度。这样使得你的代码更加容易阅读,并且提醒你不要nest得过深。

2。断开长的行以及长的字符串

要记住我们的代码会被屏幕只有24个字符长度的终端阅读。

3。放置大括号

这方面我们遵从C程序员的老祖宗——Kernighan and Ritchie的风格。

if (x is true) {

we do y

}

do {

body of do-loop

} while (condition);

if (x == y) {

..

} else if (x > y) {

...

} else {

....

}

定义函数时是个例外,我们这样写

int function(int x)

{

body of function

}

采用这种方式的另外一个好处是,节省空间。我们不需要为单个的括号而占用一行的空间,要知道有些人会使用很小屏幕的终端观看代码,比如PDA用户。

4。命名规则

全局的变量或函数采用描述性的名字,务尽其详。而局部函数采用缩略方式加以命名。

匈牙利命名法不被推荐。

5。函数

函数的一个推荐风格是写得短小精悍,不要超过160x24这样的长度。如果你的函数特别长,你要尽可能得断开它,使它的部分功能放置在别的函数里。如果对性能要求特别明显,那么可以把分出去的函数设置为inline。

6。宏,枚举

最好都为大写,但是宏函数例外。

7。不要滥用inline

inline函数的原则是这个函数不超过三行代码,其中的例外就是函数参数中有可以在编译时就确定的常数,而你知道因为这个常数,编译器能够加以优化从而减少函数的代码。

该规范在php程序编写时,可以借鉴,参看这里 从linux kernel coding style看php代码规范

从linux kernel coding style看php代码规范

linux内核的编码是一种极端情况。

需要清晰明朗以供全世界的开发者学习、修改,对代码的质量要求较高。

相信linus大神在长期接触各种各式代码后脾气会变得更暴躁,就比如前段时间在某论坛痛斥C++。。。

节选,去除不适合PHP程序员阅读的部分。

如果你开发PHP程序的核心代码,比如框架,尤其建议好好思考。

虽然,它和一些权威的代码规范比如discuz和zend的有所冲突,但是依然能从中受益。

linux kernel coding style (针对PHPer作了节选)

linux kernel coding style的中文译者:

中文版维护者: 张乐 Zhang Le

中文版翻译者: 张乐 Zhang Le

中文版校译者: 王聪 Wang Cong

wheelz

管旭东 Xudong Guan

Li Zefan

Wang Chen

第一章:缩进

制表符是8个字符,所以缩进也是8个字符。有些异端运动试图将缩进变为4(乃至2)个字符深,这几乎相当于尝试将圆周率的值定义为3。

理由:缩进的全部意义就在于清楚的定义一个控制块起止于何处。尤其是当你盯着你的屏幕连续看了20小时之后,你将会发现大一点的缩进会使你更容易分辨缩进。

现在,有些人会抱怨8个字符的缩进会使代码向右边移动的太远,在80个字符的终端屏幕上就很难读这样的代码。这个问题的答案是,如果你需要3级以上的缩进,不管用何种方式你的代码已经有问题了,应该修正你的程序。

在switch语句中消除多级缩进的首选的方式是让“switch”和从属于它的“case”标签对齐于同一列,而不要“两次缩进”“case”标签。比如:

C++代码

switch (suffix) {

case 'G':

case 'g':

mem <<= 30;

break;

case 'M':

case 'm':

mem <<= 20;

break;

case 'K':

case 'k':

mem <<= 10;

/* fall through */

default:

break;

}
  不要把多个语句放在一行里,除非你有什么东西要隐藏:

  C++代码

  if (condition) do_this;

  do_something_everytime;

  也不要在一行里放多个赋值语句。内核代码风格超级简单。就是避免可能导致别人误读的表达式。

  除了注释、文档和Kconfig之外,不要使用空格来缩进,前面的例子是例外,是有意为之。

  选用一个好的编辑器,不要在行尾留空格。

  第二章:把长的行和字符串打散

  代码风格的意义就在于使用平常使用的工具来维持代码的可读性和可维护性。

  每一行的长度的限制是80列,我们强烈建议您遵守这个惯例。

  长于80列的语句要打散成有意义的片段。每个片段要明显短于原来的语句,而且放置的位置也明显的靠右。同样的规则也适用于有很长参数列表的函数头。长字符串也要打散成较短的字符串。唯一的例外是超过80列可以大幅度提高可读性并且不会隐藏信息的情况。

  C++代码

  void fun(int a, int b, int c)

  {

  if (condition)

  printk(KERN_WARNING "Warning this is a long "

  "3 parameters a: %u b: %u "

  "c: %u \n", a, b, c);

  else

  next_statement;

  }

  第三章:大括号和空格的放置

  C语言风格中另外一个常见问题是大括号的放置。和缩进大小不同,选择或弃用某种放置策略并没有多少技术上的原因,不过首选的方式,就像Kernighan和Ritchie展示给我们的,是把起始大括号放在行尾,而把结束大括号放在行首,所以:

  C++代码

  if (x is true) {

  we do y

  }

  这适用于所有的非函数语句块(if、switch、for、while、do)。比如:

  C++代码

  switch (action) {

  case KOBJ_ADD:

  return "add";

  case KOBJ_REMOVE:

  return "remove";

  case KOBJ_CHANGE:

  return "change";

  default:

  return NULL;

  }

  不过,有一个例外,那就是函数:函数的起始大括号放置于下一行的开头,所以:

  C++代码

  int function(int x)

  {

  body of function

  }

  全世界的异端可能会抱怨这个不一致性是……呃……不一致的,不过所有思维健全的人都知道(a)K&R是_正确的_,并且(b)K&R是正确的。此外,不管怎样函数都是特殊的(在C语言中,函数是不能嵌套的)。

  注意结束大括号独自占据一行,除非它后面跟着同一个语句的剩余部分,也就是do语句中的“while”或者if语句中的“else”,像这样:

  C++代码

  do {

  body of do-loop

  } while (condition);

  和

  C++代码

  if (x == y) {

  ..

  } else if (x > y) {

  ...

  } else {

  ....

  }

  理由:K&R。

  也请注意这种大括号的放置方式也能使空(或者差不多空的)行的数量最小化,同时不失可读性。因此,由于你的屏幕上的新行是不可再生资源(想想25行的终端屏幕),你将会有更多的空行来放置注释。

  当只有一个单独的语句的时候,不用加不必要的大括号。

  C++代码

  if (condition)

  action();

  这点不适用于本身为某个条件语句的一个分支的单独语句。这时需要在两个分支里都使用大括号。

  C++代码

  if (condition) {

  do_this();

  do_that();

  } else {

  otherwise();

  }

  3.1:空格

  Linux内核的空格使用方式(主要)取决于它是用于函数还是关键字。(大多数)关键字后要加一个空格。值得注意的例外是sizeof、typeof、alignof和__attribute__,这些关键字某些程度上看起来更像函数(它们在Linux里也常常伴随小括号而使用,尽管在C语言里这样的小括号不是必需的,就像“struct fileinfo info”声明过后的“sizeof info”)。

  所以在这些关键字之后放一个空格:

  if, switch, case, for, do, while

  但是不要在sizeof、typeof、alignof或者__attribute__这些关键字之后放空格。例如,

  C++代码

  s = sizeof(struct file);

  不要在小括号里的表达式两侧加空格。这是一个反例:

  C++代码

  s = sizeof( struct file );

  当声明指针类型或者返回指针类型的函数时,“*”的首选使用方式是使之靠近变量名或者函

  数名,而不是靠近类型名。例子:

  C++代码

  char *linux_banner;

  unsigned long long memparse(char *ptr, char **retptr);

  char *match_strdup(substring_t *s);

  在大多数二元和三元操作符两侧使用一个空格,例如下面所有这些操作符:

  C++代码

  = + - < > * / % | & ^ <= >= == != ? :

  但是一元操作符后不要加空格:

  C++代码

  & * + - ~ ! sizeof typeof alignof __attribute__ defined

  后缀自加和自减一元操作符前不加空格:

  ++ --

  前缀自加和自减一元操作符后不加空格:

  ++ --

  “.”和“->”结构体成员操作符前后不加空格。

  不要在行尾留空白。有些可以自动缩进的编辑器会在新行的行首加入适量的空白,然后你就可以直接在那一行输入代码。不过假如你最后没有在那一行输入代码,有些编辑器就不会移除已经加入的空白,就像你故意留下一个只有空白的行。包含行尾空白的行就这样产生了。

  当git发现补丁包含了行尾空白的时候会警告你,并且可以应你的要求去掉行尾空白;不过如果你是正在打一系列补丁,这样做会导致后面的补丁失败,因为你改变了补丁的上下文。

  第四章:命名

  C是一个简朴的语言,你的命名也应该这样。和Modula-2和Pascal程序员不同,C程序员不使用类似 ThisVariableIsATemporaryCounter 这样华丽的名字。C程序员会称那个变量为“tmp”,这样写起来会更容易,而且至少不会令其难于理解。

  不过,虽然混用大小写的名字是不提倡使用的,但是全局变量还是需要一个具描述性的名字。称一个全局函数为“foo”是一个难以饶恕的错误。

  全局变量(只有当你真正需要它们的时候再用它)需要有一个具描述性的名字,就像全局函数。如果你有一个可以计算活动用户数量的函数,你应该叫它“count_active_users()”或者类似的名字,你不应该叫它“cntuser()”。

  在函数名中包含函数类型(所谓的匈牙利命名法)是脑子出了问题——编译器知道那些类型而且能够检查那些类型,这样做只能把程序员弄糊涂了。难怪微软总是制造出有问题的程序。

  本地变量名应该简短,而且能够表达相关的含义。如果你有一些随机的整数型的循环计数器,它应该被称为“i”。叫它“loop_counter”并无益处,如果它没有被误解的可能的话。类似的,“tmp”可以用来称呼任意类型的临时变量。

  如果你怕混淆了你的本地变量名,你就遇到另一个问题了,叫做函数增长荷尔蒙失衡综合症。请看第六章(函数)。

  第六章:函数

  函数应该简短而漂亮,并且只完成一件事情。函数应该可以一屏或者两屏显示完(我们都知道ISO/ANSI屏幕大小是80x24),只做一件事情,而且把它做好。

  一个函数的最大长度是和该函数的复杂度和缩进级数成反比的。所以,如果你有一个理论上很简单的只有一个很长(但是简单)的case语句的函数,而且你需要在每个case里做很多很小的事情,这样的函数尽管很长,但也是可以的。

  不过,如果你有一个复杂的函数,而且你怀疑一个天分不是很高的高中一年级学生可能甚至搞不清楚这个函数的目的,你应该严格的遵守前面提到的长度限制。使用辅助函数,并为之取个具描述性的名字。

  函数的另外一个衡量标准是本地变量的数量。此数量不应超过5-10个,否则你的函数就有问题了。重新考虑一下你的函数,把它分拆成更小的函数。人的大脑一般可以轻松的同时跟踪7个不同的事物,如果再增多的话,就会糊涂了。即便你聪颖过人,你也可能会记不清你2个星期前做过的事情。

  在源文件里,使用空行隔开不同的函数。

  第八章:注释

  注释是好的,不过有过度注释的危险。永远不要在注释里解释你的代码是如何运作的:更好

  的做法是让别人一看你的代码就可以明白,解释写的很差的代码是浪费时间。

  一般的,你想要你的注释告诉别人你的代码做了什么,而不是怎么做的。也请你不要把注释

  放在一个函数体内部:如果函数复杂到你需要独立的注释其中的一部分,你很可能需要回到

  第六章看一看。你可以做一些小注释来注明或警告某些很聪明(或者槽糕)的做法,但不要

  加太多。你应该做的,是把注释放在函数的头部,告诉人们它做了什么,也可以加上它做这

  些事情的原因。

  当注释内核API函数时,请使用kernel-doc格式。请看

  Documentation/kernel-doc-nano-HOWTO.txt 和 scripts/kernel-doc 以获得详细信息。

  Linux的注释风格是C89“/* ... */”风格。不要使用C99风格“// ...”注释。

  长(多行)的首选注释风格是:

  C++代码

  /*

  * This is the preferred style for multi-line

  * comments in the Linux kernel source code.

  * Please use it consistently.

  *

  * Description: A column of asterisks on the left side,

  * with beginning and ending almost-blank lines.

  */

  注释数据也是很重要的,不管是基本类型还是衍生类型。为了方便实现这一点,每一行应只

  声明一个数据(不要使用逗号来一次声明多个数据)。这样你就有空间来为每个数据写一段

  小注释来解释它们的用途了。

  对于PHPER来讲,最好遵循PHPDOC风格的注释。

  第九章:你已经把事情弄糟了

  这没什么,我们都是这样。可能你的使用了很长时间Unix的朋友已经告诉你“GNU emacs”能

  自动帮你格式化C源代码,而且你也注意到了,确实是这样,不过它所使用的默认值和我们

  想要的相去甚远(实际上,甚至比随机打的还要差——无数个猴子在GNU emacs里打字永远不

  会创造出一个好程序)(译注:请参考Infinite Monkey Theorem)(对于PHPer,可能就是zend studio、eclipse之类的自动格式化工具)

  所以你要么放弃GNU emacs,要么改变它让它使用更合理的设定。

  第十二章:宏,枚举和RTL

  用于定义常量的宏的名字及枚举里的标签需要大写。

  C++代码

  #define CONSTANT 0x12345

  宏的名字请用大写字母,不过形如函数的宏的名字可以用小写字母。

  。。。

  第十三章:打印内核消息

  内核开发者应该是受过良好教育的。请一定注意内核信息的拼写,以给人以好的印象。不要

  用不规范的单词比如“dont”,而要用“do not”或者“don't”。保证这些信息简单、明了、无

  歧义。

  内核信息不必以句号(译注:英文句号,即点)结束。

  写出好的调试信息可以是一个很大的挑战;当你写出来之后,这些信息在远程除错的时候当DEBUG符号没有被定义的时候,这些信息不应该被编译进内核里

  就会成为极大的帮助。

  (也就是说,默认地,它们不应该被包含在内)。(对于PHPer也是同样)

  第十八章:编辑器模式行和其他需要罗嗦的事情

  有一些编辑器可以解释嵌入在源文件里的由一些特殊标记标明的配置信息。比如,emacs

  能够解释被标记成这样的行:

  -*- mode: c -*-

  或者这样的:

  /*

  Local Variables:

  compile-command: "gcc -DMAGIC_DEBUG_FLAG foo.c"

  End:

  */

  Vim能够解释这样的标记:

  /* vim:set sw=8 noet */

  这包括有关缩进和模式配置的标记。人们可以使用他们自己定制的模

  式,或者使用其他可以产生正确的缩进的巧妙方法。

  不要在源代码中包含任何这样的内容。每个人都有他自己的编辑器配置,你的源文件不应

  该覆盖别人的配置。

  简而言之,8个字符的缩进可以让代码更容易阅读,还有一个好处是当你的函数嵌套太深的

  时候可以给你警告。留心这个警告。

User-agent 字串史(客户端操作系统浏览器识别)

较古的浏览器
1993年,NCSA 发布了首款 web 浏览器 Mosaic。它的 user-agent 字串非常简洁:

Mosaic/0.9
虽然当时由于它对操作系统和平台的依赖性,但是基本格式还是很简单明了。在文本中,斜杠前面是产品名称(可能会显示为 NCSA Mosaic 或是其他类似的字),斜杠后面是产品版本号。

Netscape Communications 开发了 web 浏览器 Mozilla(当时号称“Mosaic 杀手”)。他们首款公开发行版本: Netscape Navigator 2 的user-agent 字串具有如下格式:

Mozilla/Version [Language] (Platform; Encryption)
Netscape 按之前的做法在 user-agent 字串的前半部分使用了产品名称和产品版本,但在后面增加了下列信息:

Language - 表示应用程序用的是哪个语言
Platform - 表示应用程序是在什么操作系统和/或平台中运行
Encryption - 表示应用程序包含了什么安全加密类型。其中的值可能是U(128位加密)、I(40位加密)、N(没加密)。
Netscape Navigator 2 的 user-agent 字串的示例:

Mozilla/2.02 [fr] (WinNT; I)
上面的字串指: Netscape Navigator 2.02 、法语 、Windows NT 、40位加密。在当时,通过 user-agent 字串中的产品名称,可以正确判断使用的是哪个 web 浏览器。

Netscape Navigator 3 、Internet Explorer 3
1996年,Netscape Navigator 3 发布,它远远超过 Mosaic 成为当时最流行的 web 浏览器。而 user-agent 字串只有些小的变化:去掉了语言部分,多了个放操作系统或CPU的可选信息。格式如下:

Mozilla/Version (Platform; Encryption [; OS-or-CPU description])
在 Windows 系统中 Netscape Navigator 3 的 user-agent 字串的示例:

Mozilla/3.0 (Win95; U)
上面的字串指:Netscape Navigator 3 、Windows 95 、128 位加密。在 Windows 系统中,字串里面不会显示 OS 或 CPU 的信息。

Netscape Navigator 3 发布不久,微软公布了它的首款 web 浏览器: IE 3 1,但是 Netscape 是当时首选浏览器,大多数服务器在加载页面前都会检查 user-agent 是否为该款浏览器。IE 如果不兼容Netscape user-agent 字串,使用 IE 的用户就根本打不开这些页面,于是造就了如下格式:

Mozilla/2.0 (compatible; MSIE Version; Operating System)
在 Windows 95 中 IE 3.02 的 user-agent 字串的示例:

Mozilla/2.0 (compatible; MSIE 3.02; Windows 95)
由于当时的浏览器嗅探只查 user-agent 字串中的产品名称部分,结果 IE 摇身一变被识别成了 Mozilla,伪装成 Netscape Navigator。这个做法引发了对浏览器识别的争论。从此以后,浏览器真正的版本埋没在了字串的中间。

Netscape Communicator 4 、Internet Explorer 4至8
1997年8月,Netscape Communicator 4 发布(发布的名称中 Navigator 换成了 Communicator),它的 user-agent 字串格式与 3 版本一致。Windows 98 中 4 版本的 user-agent 字串如下:

Mozilla/4.0 (Win98; I)
Netscape 浏览器在更新时,版本也相应增加。4.79 版本的 user-agent 字串如下:

Mozilla/4.79 (Win98; I)
微软发布 IE 4 时,user-agent 字串更新了版本,格式如下:

Mozilla/4.0 (compatible; MSIE Version; Operating System)
在 Windows 98 中 IE 4 的 user-agent 字串的示例:

Mozilla/4.0 (compatible; MSIE 4.0; Windows 98)
可以看出,Mozilla 的版本与 IE 实际的版本一致,这样就可以识别第4代浏览器了。但遗憾的是,不久 IE 4.5 马上就发布了(只在 Mac 平台),虽然 Mozilla 版本仍是 4,但是 IE 的版本改成如下:

Mozilla/4.0 (compatible; MSIE 4.5; Mac_PowerPC)
此后,IE 的版本一直到 7 都沿用了这个模式。

而 IE 8 的 user-agent 字串添加了呈现引擎(rendering engine)版本:

Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)
新增的呈现引擎非常重要!这样 IE8 以 MSIE 7.0 兼容模式运行时,Trident 版本保持不变,而原先 IE7 的 user-agent 字串不包括 Trident 版本。这样可以区分 IE7 与 IE8 运行的兼容模式。

注意:别指望能从 Mozilla 版本中得到什么靠谱的信息。

Gecko
Gecko 是 Firefox 的呈现引擎。Gecko 首次开发是作为 Mozilla 浏览器 Netscape 6 的一部分。Netscape 6 的 user-agent 字串的结构是面向未来的,新版本反应出从 4.x 版本的简单变得较为复杂,它的格式如下:

Mozilla/MozillaVersion (Platform; Encryption; OS-or-CPU; Language; PrereleaseVersion)Gecko/GeckoVersion ApplicationProduct/ApplicationProductVersion
为了更好的理解上面的 Gecko user-agent 字串格式,下面来看看各种从基于 Gecko 浏览器中取得的字串。

在 Windows XP 中的 Netscape 6.21:

Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:0.9.4) Gecko/20011128 Netscape6/6.2.1
在 Linux 中的 SeaMonkey 1.1a:

Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1b2) Gecko/20060823 SeaMonkey/1.1a
在 Windows XP 中的 Firefox 2.0.0.11 :

Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.11) Gecko/20071127 Firefox/2.0.0.11
Mac OS X 中的 Camino 1.5.1:

Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en; rv:1.8.1.6) Gecko/20070809 Camino/1.5.1
上面都是基于 Gecko 的浏览器所取得的 user-agent 字串,区别只是版本有所不同。Mozilla 版本 5.0 是自从首款基于 Gecko 发布后就一直不变,而且以后有可能也不会变2。

WebKit
2003年,Apple 宣布发布首款他们自主开发的 web 浏览器:Safari。它的呈现引擎叫 WebKit。它是 Linux 中的 web 浏览器 Konqueror 呈现引擎 KHTML 的一个分支,几年后,WebKit 的开源吸引了呈现引擎的开发人员。

这款新浏览器和呈现引擎的开发人员也遇到了曾经 IE 3.0 类似的问题:怎样才能溶入主流而不被踢出局?答案是:在 user-agent 字串中放详尽的信息,以便骗取网站的信任使它与其它流行的浏览器兼容。user-agent 字串格式如下:

Mozilla/5.0 (Platform; Encryption; OS-or-CPU; Language) AppleWebKit/AppleWebKitVersion (KHTML, like Gecko) Safari/SafariVersion
下面是示例:

Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/124 (KHTML, like Gecko) Safari/125.1
这又是个挺长的 user-agent 字串,其中包括的信息既有 Apple WebKit 的版本,也有 Safari 的版本。凡是基于 WebKit 的浏览器都将自己伪装成了 Mozilla 5.0,与基于 Gecko 浏览器完全一样。但 Safari 的版本是浏览器的构建版本号(build number)。Safari 1.25 在 user-agent 字串中号为 125.1(如上所示)。Safari 版本 3 的 user-agent 字串包括了实际的 Safari 版本:

Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/522.15.5 (KHTML, like Gecko) Version/3.0.3 Safari/522.15.5
其中的“(KHTML, like Gecko)”在 Safari 1.0 预览版本中就有了,这字串部分是最耐人寻味又饱受诟病。Apple 的野心是为了让开发人员把 Safari 当成 Gecko,所以采取了当初微软 IE user-agent 的类似做法:Safari 是兼容 Mozilla 的,否则 Safari 用户会认为用的浏览器不受支持。

而其它基于 WebKit 的浏览器与 Safari 不同的是,没有上面说的这个情况,所以检测断定浏览器是否基于 WebKit 比看有没有明确标 Safari 更有用。

Konqueror
Konqueror 是款在 KDE Linux 桌面环境中的浏览器,基于 KHTML 开源呈现引擎。它只发布了在 Linux 的版本,但是拥有活跃的用户群。为了兼容性最大化,user-agent 字串的格式也紧跟 IE 的后尘:

Mozilla/5.0 (compatible; Konqueror/Version; OS-or-CPU)
Konqueror 3.2 为了与 WebKit user-agent 字串变化保持一致,它将 KHTML 作为它的标识:

Mozilla/5.0 (compatible; Konqueror/Version; OS-or-CPU) KHTML/KHTMLVersion (like Gecko)
如下所示:

Mozilla/5.0 (compatible; Konqueror/3.5; SunOS) KHTML/3.5.0 (like Gecko)
Konqueror 和 KHTML 的版本号比较一致,唯一的区别就是下点处不同,比如Konquerer 3.5、KHTML 3.5.1。

Chrome
Google Chrome 浏览器以 WebKit 作为呈现引擎,JavaScript 引擎却用了另一种。最初发布的版本是 0.2,它的 user-agent 字串格式是在 webKit 信息的基础上又增加了如下:

Mozilla/5.0 (Platform; Encryption; OS-or-CPU; Language) AppleWebKit/AppleWebKitVersion (KHTML, like Gecko) Chrome/ChromeVersion Safari/SafariVersion
Chrome 0.2 user-agent 信息的示例如下:

Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.13 (KHTML, like Gecko) Chrome/0.2.149.29 Safari/525.13
虽我不敢完全保证,但很可能 WebKit 版本和 Safari 版本总会保持同步。

Opera
Opera 浏览器默认 user-agent 字串是现代浏览器中最合理的--正确的标识了它自己及其版本。 在 Opera 8.0 前,它的 user-agent 字串格式如下:

Opera/Version (OS-or-CPU; Encryption) [Language]
在 Windows XP 中 Opera 7.54 user-agent 字串示例:

Opera/7.54 (Windows NT 5.1; U) [en]
Opera 8 user-agent 字串的语言部分移到了括号内。

Opera/Version (OS-or-CPU; Encryption; Language)
在 Windows XP 中 Opera 8 user-agent 字串示例:

Opera/8.0 (Windows NT 5.1; U; en)
当时 Opera 做为主流浏览器之一,它的 user-agent 字串是唯一使用产品名称和版本完全真实的标识了它自己。但是由于大量的浏览器嗅探代码在 Internet 上像蝗虫飞过般只吃标 Mozilla 产品名的 user-agent 字串,造成了 Opera 的 user-agent 字串发生了完全的改变。

Opera 9 user-agent 字串有两种修改的方式:一种方式是将自己标识为 Firefox 或 IE 浏览器。在这种方式下,user-agent 字串与 Firefox 或 IE 的几乎一样,只不过末尾附加了“Opera”及版本号。如下所示:

Mozilla/5.0 (Windows NT 5.1; U; en; rv:1.8.1) Gecko/20061208 Firefox/2.0.0 Opera 9.50
Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; en) Opera 9.50
前一字串将 Opera 9.5 标识为 Firefox 2。后一字串将 Opera 9.5 标识为 IE 6,在两个字串中都带有 Opera 版本信息。虽然这种方式是作为 Firefox 或 IE 打开的,但也能识别出 Opera。另一种方法则是浏览器 user-agent 字串标识伪装成 Firefox 或 IE,同时也找不到“Opera”字串及其版本信息。这样从字面上去区分 Opera 浏览器便成了“不可能完成的任务”。3

结论
user-agent 字串史可以说明曾对 user-agent 嗅探说不的原因:IE 想要将自己识别为 Netscape 4,Konqueror 和 WebKit 想要识别为 Firefox,Chrome 想要识别为 Safari。这样使得除 Opera 外所有浏览器的 user-agent 嗅探区别很小,想要从一堆茫茫浏览器海洋中找出有用的标识太少了。关于嗅探要记住:一款浏览器与其它浏览器是兼容的,这样造成了不能完全准确的断定是哪款浏览器。

比如说 Chrome ,它声称任何可以在 Safari 3 访问的网站 Chrome 也都可以访问,但是对检测 Chrome 没有一点用。为了浏览器的兼容--这便是这个声明的理由。

(完)

译注1:IE 3 不是微软首款浏览器,请参考 wiki 的 Timeline of web browsers。

译注2:这个是原作者的想法,译者不敢保证。

译注3:Opera 10 的 user-agent 字串大家自己去看吧。

博客访问日志尝试分析

下班了,突然想来看博客今天有哪些人访问,连上数据库,直接查看之前wordpress访客追踪插件的访问追踪记录表,今天的访问照样大多是来自google,然也有一些其它搜索引擎的,加起来也没有google的多。里面有几个“人”访问的,习惯性的查一下ip地址是哪里的。前两天查时,有几个使用win2003的用户访问,查看一些技术文章的,也有使用linux的,这次突然见有一个用fedora的linux用户:

Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.6) Gecko/20091216 Fedora/3.5.6-1.fc11 Firefox/3.5.6

访问来源是google搜索 (mysql procedure myisam )结果的第一页,前面有几条,都是mysql.com的结果,下面就是我的页面,从别处搜集来的信息,也没有进行修改加工,也没有进行优化,居然排名还能这么靠前!当然这样的关键词组合相当冷僻,很少人会这么搜索。

这个访问者是玩linux的,当然更要查一下是哪里的,ip138显示
<ul>
<li>本站主数据:北京市 电信</li>
<li>参考数据一:北京市 电信</li>
<li>参考数据二:北京市 理想国际大厦</li>
</ul>
理想国际大厦,查一下是什么单位,google结果,中关村的,好像还挺大的样子,其中一个结果页显示,该楼盘的信息

<span>http://data.dichan.com/OfficeDetails.aspx?OfficeID=&amp;Caption=%E7%90%86%E6%83%B3%E5%9B%BD%E9%99%85%E5%A4%A7%E5%8E%A6</span>
下面来有里面入驻的单位:新浪,17-20整层;华旗资讯,10-11整层;百度,12整层;还有其它几个。
看来百度也没有多大,才点了一层,又在里面查一层多大面积,2800m<sup>2</sup>;貌似这个页面里的信息比较老一点了。
对面积大小没有多少概念,问别的同事公司办公室有多大页面,感觉一个百度的办公区域大小。同事不解,为什么要问办公室面积,从博客的ip追踪说起,简要解释一下,然而他们是更不解,“根本不知道你在说什么”,看来差不多是袋鼠式的跳跃思维了。
又突然看到这个页面是新浪地产的页面,但域名根本不是sina.com.cn,进入该地址主页,自动跳转到新浪页面了,看来也是个老的站点,或者分站点,但新浪这些大网站一般不搞一大堆不同的域名的,都是单一域名+子域名的;估计这是并购别的网站了,而这是个老页面,只改了个网站logo,实际上是不是就不知道了,也没必要推究,又不是搞情报工作的。
至于这个访问者究竟是谁,大概很难知道了,ip地址,查这么专业的问题,而且看了两个页面“mysql 表种类 MyISAM,innodb详解”,“mysql 索引管理:SHOW INDEX语法 查看索引状态”,应该确实是在查找技术资料,而且使用linux,大概是一家搞网络的公司的员工,而且有可能是个当从事mysql相关技术不久的,不然不会查找这些比较浅显的东西,而且使用中文google搜索。
使用的可能是英文版搜索系统(语言环境),是fedora11,版本比较老一点,可能是公司行为,没有统一升级版本。
两次访问时间是中午2010-02-25 13:18:00, 2010-02-25 13:18:02访问时间非常积,看来这老兄的网速相当快,而且所看到页面信息不是自己所要的。

[user-agent并不可靠,但一般情况下,还是准确的,很少人去修改它,事实上好像也没有什么意思]

AJAX辅助调试利器:LiveHTTPHeaders

[20161011更新] 该扩展的原始版本长期没有维护、而不再支持最新的firefox;但有一个克隆分支在正常维护中 Live HTTP Headers (clone) . https://addons.mozilla.org/zh-Cn/firefox/addon/live-http-headers-clone/

----- 以下是原始文章 -----------------

LiveHTTPHeaders,一个firefox插件,非常强大的http请求抓取、重发、模拟工具,可有筛选的监测所关心的http请求。

官方网站:http://livehttpheaders.mozdev.org/