.htaccess实现URL的HTML静态化

PHP开发工具的优势
作为一种简单而高效的Server端嵌入语言,PHP已成为Internet上最流行的一种动态网站制作工具。它不但能够对多种数据库提供良好支持,而且与其它的Server端脚本语言如ASP相比,PHP免费开放源码并且提供跨平台的支持,这使它能够轻易适应当今网络中各种异质的网络环境;可让网页制作人员能够非常快捷、方便地制作出功能强大的动态Web页面。


动态网页的优势
随着计算机和互联网技术的飞速发展,由于静态网页没有数据库的支持,不但增加工作量,而且由于缺乏交互功能,当网站有大量信息及功能较多时,完全依靠静态网页是无法实现的,于是动态网页就成为网站维护的必然要求。动态网页具有良好的交互性、数据库查询、可与HTML以外的文件进行交互、缩短查询时间、提高浏览效率等静态网页所无法比拟的优点。


搜索引擎市场的潜力
据权威统计,全球约有80%的网络用户通过搜索引擎来查找资料或产品信息,此外据美国专业搜索引擎服务公司iProspect调研结果表明:逾60%的雅虎用户和72%的Google用户在进行查询时,都会点击自然搜索结果来寻找他们需要的讯息。显然,网站要想获得尽可能多的访问量,搜索引擎无疑是最理想、也是最直接的目标。


当动态网页遇上搜索引擎
虽然动态网页相比于静态页面拥有许多优势,但它在搜索引擎的检索上却碰了个大钉子。无论任何一家网站,尤其是那些以营销为目的的企业网站,没有谁会希望自己的网页无法被搜索引擎检索到。但事实上却是:动态网站设计的很多内容页面都无法得到搜索引擎的检索。


一般来说,搜索引擎会把动态网页地址中出现的“?”字符视做“停止标记”,在它之后的所有参数都会被忽略掉。例如对“index.php?action=show&id=x”的所有子页,搜索引擎最后检索到的URL只有一个,那就是index.php这一个页面。这样一来,动态网页就陷入了无法被搜索引擎发现和检索的尴尬境地,直接失去了被用户发现的机会和搜索引擎这样一个广阔的市场空间。


搜索引擎不支持动态网页的原因
动态网页是由数据库所驱动,这就使得搜索引擎将面对无数URL而被数据库套住陷入死循环的危险,这也就是我们所说的蜘蛛陷阱(Spider Traps)。而且一旦Spider被网站套住,那么它对数据库的重复访问请求也会造成网站服务器系统的彻底瘫痪。鉴于此,搜索引擎对于动态网页中URL里包含“?”之后的字符一概不予读取。


PHP转化为HTML静态页面
虽然不能保证把每个动态页面都转化为静态的HTML文件,但如果网站是驻留在Apache服务器上,则只需一个简单的小脚本就可以把大多数动态页面都转换成HTML文件。


1.确定需要转换成后缀为HTML的PHP文件
我们的目标是那些名下包含动态子页较多的网页。以“index.php?action=show&id=”为例,我们需要对“index.php”之后的动态子页进行转换。 例如,如果网站里有一个名为“Arts and Crafts”的子目录,URL为“index.php?action=show&id=1”,其它子目录和这个URL只在最后的变量上不同,因此我们需要修改当index.php之后跟随变量时服务器对它的打开方式。


2.通知服务器在接受一个HTML页面的调用请求后打开一个PHP文件
我们需要在服务器上index.php所在的目录下放置一个.htaccess文本文件。.htaccess文件是Apache服务器上的一个目录配置设置文件,它提供了针对目录改变配置的方法,即在一特定的文档目录中放置一个包含一个或多个指令的文件(.htaccess文件),来作用于此目录及其所有子目录。.htaccess的功能包括设置网页密码、设置发生错误时出现的文件、改变主页文件名、禁止读取文件名、重新导向文件、增加MIME类别、禁止列目录下的文件等。


在需要针对目录改变服务器的配置,而对服务器系统没有root权限时,应该使用.htaccess文件。如果服务器管理员不愿意频繁修改配置,则可以允许用户通过.htaccess文件自己修改配置,尤其是ISP在一台机器上提供多个用户站点,而又希望用户可以自己改变配置的情况下,一般会开放部分.htaccess的功能给使用者自行设置。对于Vdeck用户来说,可能需要先创建一个文本文件,然后在管理面板将其更名为.htaccess。现在我们需要在服务器端指定一些变量。比方说,我需要把“?action=show&id=x”这个变量改成“action-x.html”,这样就能消除动态页面无法被搜索引擎检索的问题。


在开始创建服务器变量前,我们需要先在这个新建的.htaccess文件中创建一个Rewrite Engine (URL重写工具)。只需要在文件第一行写上
RewriteEngine On
这就等于告诉服务器我们要改变一些文件的处理方式。接下来的一行就要指定重写规则:
RewriteRule ^action-([0-9]+)\.html$ index.php?action=show&id=$1 [L,NC]


这个指令表明:只要接到URL中包含“action-0.html”到“action-9.html”的任意静态网页的页面调用请求,服务器将以“index.php?变量”地址返回给调用用户。

先别急着编辑下一条改写规则,我们有必要在更改实际的PHP页面之前先进行一下测试。我们可以对上面的"重写规则"进行测试。首先新开一个浏览器窗口,在地址栏中输入“action-1.html”,如果我们看到的页面显示为“index.php?action=show&id=1”就表明改写规则工作正常。


3.让搜索引擎看到我们的静态化页面
现在,我们需要让搜索引擎能够看到我们经过“改头换面”的新的网页地址。那么,是不是需要赶紧把网站再向搜索引擎提交一遍呢? 不用这么费劲,我们只需打开PHP文件编辑一下就行了。不过在此之前,应记得将要修改的每个脚本都做个备份,将其存放在硬盘上。然后需要确定创建更改链接地址的程序的不同地方。最好在前端而不要在后台进行更改。PHP文件将会从.htaccess文件中得到形如“index.php?action=show&id=x”之类的信息。我们需要把这些动态生成的网页地址更改一下,并以静态化页面地址显示给用户和搜索引擎。即将所有URL中包含“index.php?action=show&id=”的部分替换为“action-”,并加上.html后缀。


一旦发现待修改的区域,在更改后要随时检查有无错误。如果在脚本中有错误而没有发现,纠正起来是相当棘手的,尤其在对PHP编码不熟悉的情况下。

javascript 获取页面高度(多种浏览器)



在我本地测试当中:
在IE、FireFox、Opera下都可以使用


document.body.clientWidth
document.body.clientHeight


即可获得,很简单,很方便。



而在公司项目当中:
Opera仍然使用


document.body.clientWidth
document.body.clientHeight


可是IE和FireFox则使用


document.documentElement.clientWidth
document.documentElement.clientHeight


原来是W3C的标准在作怪啊。


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
如果在页面中添加这行标记的话


在IE中:


document.body.clientWidth ==> BODY对象宽度
document.body.clientHeight ==> BODY对象高度
document.documentElement.clientWidth ==> 可见区域宽度
document.documentElement.clientHeight ==> 可见区域高度


在FireFox中:


document.body.clientWidth ==> BODY对象宽度
document.body.clientHeight ==> BODY对象高度
document.documentElement.clientWidth ==> 可见区域宽度
document.documentElement.clientHeight ==> 可见区域高度



在Opera中:


document.body.clientWidth ==> 可见区域宽度
document.body.clientHeight ==> 可见区域高度
document.documentElement.clientWidth ==> 页面对象宽度(即BODY对象宽度加上Margin宽)
document.documentElement.clientHeight ==> 页面对象高度(即BODY对象高度加上Margin高)



而如果没有定义W3C的标准,则
IE为:


document.documentElement.clientWidth ==> 0
document.documentElement.clientHeight ==> 0
FireFox为:
document.documentElement.clientWidth ==> 页面对象宽度(即BODY对象宽度加上Margin宽)document.documentElement.clientHeight ==> 页面对象高度(即BODY对象高度加上Margin高)
Opera为:
document.documentElement.clientWidth ==> 页面对象宽度(即BODY对象宽度加上Margin宽)document.documentElement.clientHeight ==> 页面对象高度(即BODY对象高度加上Margin高)


真是一件麻烦事情,其实就开发来看,宁可少一些对象和方法,不使用最新的标准要方便许多啊。

DOCTYPE定义引起javascript失效的问题

今天写一个小脚本,后来发现HTML头有<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 定义就不能运行。


后来找到原因是document.body改为document.documentElement即可。


原来HTML里是document.body
XHTML里是document.documentElement
都指的是<body>节点(OR元素)


可以这样兼容:


function getBodyObj()
{
return (document.documentElement) ? document.documentElement : document.body ;
}


在DHTML文档中对documentElement的说明是:Object that receives the reference to the document element,The root node of a typical HTML document is the html object.

body

Microsoft® Internet Explorer 6 的新增内容
当你使用 !DOCTYPE 声明指定标准兼容模式的时候,此对象将不再代表文档内容所渲染的整个表面。该对象当然可从其内容中获得其大小,但你也可以像 div 对象那样精确设置其大小。
 

PS:

对于document.compatMode,很多朋友可能都根我一样很少接触,知道他的存在却不清楚他的用途。今天在ext中看到 document.compatMode的使用,感觉这个对于我们开发兼容性的web页面还是很有帮助,我们都知道,IE对盒模型的渲染在 Standards Mode和Quirks Mode是有很大差别的,在Standards Mode下对于盒模型的解释和其他的标准浏览器是一样,但在Quirks Mode模式下则有很大差别,而在不声明Doctype的情况下,IE默认又是Quirks Mode。所以为兼容性考虑,我们可能需要获取当前的文档渲染方式。


document.compatMode正好派上用场,它有两种可能的返回值:BackCompat和CSS1Compat,对其解释如下:


BackCompat Standards-compliant mode is not switched on. (Quirks Mode)
CSS1Compat Standards-compliant mode is switched on. (Standards Mode)

在实际的项目中,我们还需要在获取浏览是否IE,这样就可以得到IE的渲染模式了。在Ext中的代码:

 

isBorderBox=isIE&&!isStrict。



当文档有了标准声明时, document.compatMode 的值就等于 "CSS1compat", 因此, 我们可以根据 document.compatMode 的值来判断文档是否加了标准声明

var height = document.compatMode=="CSS1Compat" ? document.documentElement.clientHeight : document.body.clientHeight;

firefox 下获取鼠标坐标

在IE下很简单,通过event.clintX,Y获得即可,而在firefox下则不行,原因是firefox的event默认值是空的,必须先赋予event值,问题就在这里,如何才能将将鼠标的event给firefox?




在FIREFOX下,如果不觸發鼠標事件,就別想得到clientX 和 clientY。

firefox下设置style的top和left

在IE下,可以这样写


linkDiv.style.left=getPosition(obj).x;
linkDiv.style.top=getPosition(obj).y+obj.offsetHeight;

PS:getPosition()是得到一个HTML控件的绝对位置

但是这样在firefox下就不能正常显示

在firefox下应该这样写


linkDiv.style.left=getPosition(obj).x +"px";
linkDiv.style.top=getPosition(obj).y+obj.offsetHeight +"px";

貌似是因为firefox下是没有加单位的,需要自己主动去附加单位。

PHP使用zlib扩展实现页面GZIP压缩输出

GZIP(GNU-ZIP)是一种压缩技术。经过GZIP压缩后页面大小可以变为原来的30%甚至更小。这样用户浏览的时候就会感觉很爽很愉快!
要实现GZIP压缩页面需要浏览器和服务器共同支持,实际上就是服务器压缩,传到浏览器后浏览器解压并解析。浏览器那边不需要我们担心,因为现在绝大多数浏览器都支持解析GZIP过的页面。我们只要把页面在服务器端压缩再输出到浏览器就行了。

有点罗嗦,下面说正事:

正如要制作压缩饼干,先要拿到原料,要压缩一个页面,首先要获得要输出的内容。PHP中的ob_start()(ob => output buffer)函数可以实现这个功能,它可以把程序里准备输出的内容先放到一个叫做“缓冲区”的地方,当然,你可以理解为制作压缩饼干的暂时放原料的工作台。
这个函数一定要在页面输出之前使用,所以一般把它放在代码的最顶端。因为它就像是一个工作台,所以你要在原料到来之前就要准备好它,否则原料来了没地方放,会出问题的。用ob_start()得到要压缩的页面之后,我们就可以制作压缩饼干了,不对,应该是可以压缩页面了!不过好像还缺少一台压缩机, EZ,我们用PHP带的zlib扩展做一台:




压缩机做好了之后,我们把压缩机放到工作台上,于是原来的ob_start()变成

ob_start('ob_gzip'); //没错,就是给ob_start()加一个参数,参数名就是我们刚才做的“压缩机”的函数名。这样当内容进入缓冲区后PHP就会调用ob_gzip函数把它压缩了。

好了,所有的工作已完成,最后交货:

ob_end_flush(); //结束缓冲区,输出内容。当然,不用这个函数也行,因为程序执行到最后会自动将缓冲区内容输出。

完整的示例如下:




经过实际测试,上面代码中如果不用GZIP,是4.69KB=4802.56B,启用GZIP后缩小为104B ,呃……我数学可能不好,自己算下压缩到了原来的百分之多少吧。。

另外,下面是用FlashGet获取的日志信息,可以看到我们程序里加的header信息:

Fri Jan 25 17:53:10 2008 HTTP/1.1 200 OK
Fri Jan 25 17:53:10 2008 Server: Microsoft-IIS/5.1
Fri Jan 25 17:53:10 2008 Date: Fri, 25 Jan 2008 09:53:10 GMT
Fri Jan 25 17:53:10 2008 Connection: close
Fri Jan 25 17:53:10 2008 X-Powered-By: PHP/5.2.5
Fri Jan 25 17:53:10 2008 Content-Encoding: gzip
Fri Jan 25 17:53:10 2008 Vary: Accept-Encoding
Fri Jan 25 17:53:10 2008 Content-Length: 104
Fri Jan 25 17:53:10 2008 Content-type: text/html

register_shutdown _function使用以及注意事项

register_shutdown_function
(PHP 3 >= 3.0.4, PHP 4, PHP 5)

 

register_shutdown_function -- Register a function for execution on shutdown


说明:
void register_shutdown_function ( callback function [, mixed parameter [, mixed ...]] )


Registers the function named by function to be executed when script processing is complete.

Multiple calls to register_shutdown_function() can be made, and each will be called in the same order as they were registered. If you call exit() within one registered shutdown function, processing will stop completely and no other registered shutdown functions will be called.

In PHP 4.0.6 and earlier under Apache, the registered shutdown functions are called after the request has been completed (including sending any output buffers), so it is not possible to send output to the browser using echo() or print(), or retrieve the contents of any output buffers using ob_get_contents(). Since PHP 4.1, the shutdown functions are called as the part of the request so that it's possible to send the output from them. There is currently no way to process the data with output buffering functions in the shutdown function. Shutdown function is called after closing all opened output buffers thus, for example, its output will not be compressed if zlib.output_compression is enabled.

As of PHP 4, it is possible to pass parameters to the shutdown function by passing additional parameters to register_shutdown_function().

 

参数:
function

parameter

...


返回值:

无返回值。

 

 

注释:
注意: Typically undefined functions cause fatal errors in PHP, but when the function called with register_shutdown_function() is undefined, an error of level E_WARNING is generated instead. Also, for reasons internal to PHP, this error will refer to Unknown at line #0.

 

注意:

Working directory of the script can change inside the shutdown function under some web servers, e.g. Apache.

在某些HTTP服务器中,特别是Apache,shutdown function中会改变工作目录,特别是在文件的读写中,改变工作目录后会造成函数调用失败,因此在回调函数中的路径应该采用绝对路径进行文件读写操作。

 

注意: Shutdown function is called during the script shutdown so headers are always already sent.

 

 

在程序没执行完,人为中断可以调用;自然执行完也可以调用。

 

register_shutdown_function 与 exit函数的关系:

 

若register_shutdown_function在exit之前则回调函数在PHP文件执行后回执行,反之则不会。

 

eg1:


结果输出:内容输出

 

eg2:


结果输出:内容输出回调函数输出

 

另:PHP手册中也说了If you call exit() within one registered shutdown function, processing will stop completely and no other registered shutdown functions will be called.

 

 

 

It's already been discussed on the zlib page(http://www.php.net/zlib), but hasn't been mention here...

When zlib compression is enabled, register_shutdown_function doesn't work properly. Anything output from your shutdown function will not be readable by the browser. Firefox just ignores it. IE6 will show you a blank page.

The workaround that worked for me is to add the following to the top of the script.
ini_set('zlib.output_compression', 0);

 

以上是PHP5手册中的一句话,是说如果对缓存采用压缩输出的话,register_shutdown_function会不能成功执行。

经过我调试发现,这是由于回调函数中如果含有输出信息的话由于该输出信息没有经过压缩,则会发生以上所说的不能成功执行的现象。

gzencode的解码函数

gzencode压缩函数没有官方的解压函数,这里自定义一个:



控制PHP的输出缓存并压缩动态页面

mod_gzip是一个Apache模块,其功能是使用Gzip压缩静态的html页面,遵循IETF标准的浏览器可以接受gzip编码(IE, Netscape等)。mod_gzip可以将页面的下载时间提高4-5倍。我强烈建议你在你的web服务器上使用mod_gzip。然而,我们还必须用PHP建立我们自己的压缩引擎。在这篇文章里,我将要介绍如何使用PHP的输出控制函数来大幅加速页面载入速度。


介绍PHP的输出控制函数


PHP4中最令人满意的事是——你可以让PHP缓存所有由脚本生成的输出,在你决定把它们送出之前,浏览器方是不会收到任何内容的。在脚本程序中你能用这些函数来设置header、cookies,然而这只是强大的输出函数的一小部分功能。


void ob_start(void);
告诉PHP处理器把所有的输出重定向到一个内部的缓存(buffer)中。在调用ob_start之前,没有输出会被送到浏览器去。


string ob_get_contents(void);
该函数将“输出缓存”(output buffer)以字符串的形式返回。你可以调用该函数把积累下来的输出送到浏览器中。(仅在把buffering功能关闭之后!!)


int ob_get_length(void);
返回缓存中的字符串的长度。


void ob_end_clean(void);
清空输出缓存,并将输出缓存关闭。在缓存中的内容输出到浏览器之前,必须使用这个函数。


void 501([int flag])
用来打开/关闭隐含的flush动作开关(默认是关)。如果flush是开的,每次调用print/echo或是其它输出命令的时候,输出的内容会被立即送到浏览器端。

 


使用输出控制来压缩PHP输出
你必须使用PHP4里编译的Zlib扩展包来压缩输出。如果需要的话,可以查看PHP文档中有关Zlib包的安装指导。

 

首先,初始化输出缓存:
ob_start();
ob_implicit_flush(0);

之后,用print, echo, 或其他你喜欢的方法生成所有输出内容,例如:
print("Hey this is a compressed output!");

页面生成后,我们取回输出内容:
$contents = ob_get_contents();
ob_end_clean();

之后,必须检测浏览器是否支持压缩数据。如果支持,浏览器会发给服务器端一个ACCEPT-ENCODEING HTTP头。我们只需检查$HTTP_ACCEPT_ENCODING变量中是否有“gzip,deflate”字串。


if(ereg('gzip, deflate',$HTTP_ACCEPT_ENCODING)) {
// 在这里生成 Gzip 压缩的内容
} else {
echo $contents;
}

这种方法使用起来既简单又结构清晰。下面让我们看看如何生成压缩的输出:

 





//好了,你还可以按此方式附加上更多的压缩数据。

 


要想进行实际的测试,所有的脚本代码如下:

 






缓存PHP输出


当PHP4还没问世,我不得不使用PHP3的时候,我对开发一些缓存机制来减少数据库的载入、对文件系统的存取十分感兴趣。在PHP3中没有什么特别好的方法,但是有了输出缓存之后,在PHP4中一切变得容易多了。


这有一个简单的例子:






这是一个简单的例子,使用输出缓存,你可以建立一个复杂的内容生成系统,对不同的块或程序使用不同的缓存机制,等等……

 


结论
PHP输出控制函数对把脚本生成的输出重定向到缓存中十分有用。为支持gzip的浏览器输出压过的缓存数据可以减少载入时间。也可作为缓存机制来减少对数据源的存取(数据库或文件),这对使用XML意义重大。


如果我们用PHP建立一个引擎,缓存从数据源得到的数据(xml文档和数据库),并且动态的生成XML格式的内容(没有外观-presentation)我们可以得到这些XML的输出,并使用XSLT转换成任意一种我们想要的外观格式(html, wap, palm, pdf等)。使用PHP4的输出缓存和Sablotron XSLT扩展可以很好地完成这个任务。

软件版本Beta,RC,Demo,Build等含义总结

版本号:
V(Version):即版本,通常用数字表示版本号。(如:EVEREST Ultimate v4.20.1188 Beta )
Build:用数字或日期标示版本号的一种方式。(如:VeryCD eMule v0.48a Build 071112)
SP:Service Pack,升级包。(如:Windows XP SP 2/Vista SP 1)

授权和功能划分:
Trial:试用版,通常都有时间限制,有些试用版软件还在功能上做了一定的限制。可注册或购买成为正式版
Unregistered:未注册版,通常没有时间限制,在功能上相对于正式版做了一定的限制。可注册或购买成为正式版。
Demo:演示版,仅仅集成了正式版中的几个功能,不能升级成正式版。
Lite:精简版。
Full version:完整版,属于正式版。

语言划分:
SC:Simplified Chinese简体中文版。
CN : 简体中文版
GBK:简体中文汉字内码扩展规范版。
TC:Traditional Chinese繁体中文版。
CHT : 繁体中文版
BIG5:繁体中文大五码版。
EN : 英文版
Multilanguage : 多语言版
UTF8:Unicode Transformation Format 8 bit,对现有的中文系统不是好的解决方案。



开发阶段划分:
α(Alpha)版:内测版,内部交流或者专业测试人员测试用。Bug较多,普通用户最好不要安装。
β(Beta)版:公测版,专业爱好者大规模测试用,存在一些缺陷,该版本也不适合一般用户安装。
γ(Gamma)版:相当成熟的测试版,与即将发行的正式版相差无几。
RC版:Release Candidate。
RC 版。是 Release Candidate 的缩写,意思是发布倒计时,候选版本,处于Gamma阶段,该版本已经完成全部功能并清除大部分的BUG。到了这个阶段只会除BUG,不会对软件做任何大的更改。从Alpha到Beta再到Gamma是改进的先后关系,但RC1、RC2往往是取舍关系。
Final:正式版。

其他版本
Enhance :增强版或者加强版 属于正式版1
Free :自由版
Release :发行版 有时间限制
Upgrade :升级版
Retail  :零售版
Cardware :属共享软件的一种,只要给作者回复一封电邮或明信片即可。(有的作者并由此提供注册码等),目前这种形式已不多见。/ S
Plus :属增强版,不过这种大部分是在程序界面及多媒体功能上增强。
Preview :预览版
Corporation & Enterprise :企业版
Standard :标准版
Mini :迷你版也叫精简版只有最基本的功能
Premium : 贵价版
Professional : 专业版
Express : 特别版
Deluxe : 豪华版
Regged : 已注册版

Rip :是指从原版文件(一般是指光盘或光盘镜像文件)直接将有用的内容(核心内容)分离出来,剔除无用的文档,例如PDF说明文件啊,视频演示啊之类的东西,也可以算做是精简版吧…但主要内容功能是一点也不能缺少的!另:DVDrip是指将视频和音频直接从DVD光盘里以文件方式分离出来。



RTM 版 :这基本就是最终的版本,英文是 Release To Manufactur,意思是发布到生产商。
Original Equipment Manufacturer (OEM) 
You may license products through an Original Equipment Manufacturer (OEM). These products, such as Windows operating systems, come installed when you purchase a new computer. 
OEM软件是给电脑生产厂的版本,无需多说。 

Full Packaged Product (FPP)/Retail 
Physical, shrink-wrapped boxes of licensed product that can be purchased in a local retail store or any local software retailer. 
FPP就是零售版(盒装软件),这种产品的光盘的卷标都带有"FPP"字样,比如英文WXP Pro的FPP版本的光盘卷标就是WXPFPP_EN,其中WX表示是Windows XP,P是Professional(H是Home),FPP表明是零售版本,EN是表明是英语。获得途径除了在商店购买之外,某些MSDN用户也可以得到。
Volume Licensing for Organizations (VLO) 
You may enjoy potentially significant savings by acquiring multiple product licenses. Depending on the size and type of your organization. 
团体批量许可证(大量采购授权合约),这是为团体购买而制定的一种优惠方式。这种产品的光盘的卷标都带有"VOL"字样,取"Volume"前3个字母,以表明是批量,比如英文WXP Pro的VOL版本的光盘卷标就是WXPVOL_EN,其中WX表示是Windows XP,P是Professional(VOL没有Home版本),VOL表明是团体批量许可证版本,EN是表明是英语。获得途径主要是集团购买,某些MSDN用户也可以得到。