<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>影の域</title>
	<atom:link href="http://www.zfkun.com/blog/index.php/feed" rel="self" type="application/rss+xml" />
	<link>http://www.zfkun.com/blog</link>
	<description>时光真的如水...</description>
	<lastBuildDate>Thu, 29 Apr 2010 06:43:15 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.1</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>现在</title>
		<link>http://www.zfkun.com/blog/index.php/archives/145</link>
		<comments>http://www.zfkun.com/blog/index.php/archives/145#comments</comments>
		<pubDate>Thu, 29 Apr 2010 06:43:15 +0000</pubDate>
		<dc:creator>影之迷惑</dc:creator>
				<category><![CDATA[Life]]></category>

		<guid isPermaLink="false">http://www.zfkun.com/blog/?p=145</guid>
		<description><![CDATA[疲惫、累、烦。
]]></description>
			<content:encoded><![CDATA[<p>疲惫、累、烦。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.zfkun.com/blog/index.php/archives/145/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>IE6+和FF的CSS Hack</title>
		<link>http://www.zfkun.com/blog/index.php/archives/142</link>
		<comments>http://www.zfkun.com/blog/index.php/archives/142#comments</comments>
		<pubDate>Thu, 22 Apr 2010 16:59:21 +0000</pubDate>
		<dc:creator>影之迷惑</dc:creator>
				<category><![CDATA[Web]]></category>
		<category><![CDATA[css]]></category>
		<category><![CDATA[ff]]></category>
		<category><![CDATA[hack]]></category>
		<category><![CDATA[ie]]></category>

		<guid isPermaLink="false">http://www.zfkun.com/blog/?p=142</guid>
		<description><![CDATA[一、CSS HACK
以下两种方法几乎能解决现今所有HACK.
1, !important
随着IE7对!important的支持, !important 方法现在只针对IE6的HACK.(注意写法.记得该声明位置需要提前.)
&#60;style&#62;
#wrapper
{
width: 100px!important; /* IE7+FF */
width: 80px; /* IE6 */
}
&#60;/style&#62;
2, IE6/IE77对FireFox
*+html 与 *html 是IE特有的标签, firefox 暂不支持.而*+html 又为 IE7特有标签.
&#60;style&#62;
#wrapper
{
#wrapper { width: 120px; } /* FireFox */
*html #wrapper { width: 80px;} /* ie6 fixed */
*+html #wrapper { width: 60px;} /* ie7 fixed, 注意顺序 */
}
&#60;/style&#62;
注意:
*+html 对IE7的HACK 必须保证HTML顶部有如下声明：
&#60;!DOCTYPE HTML PUBLIC &#8220;-//W3C//DTD HTML 4.01 Transitional//EN&#8221;　&#8221;http://www.w3.org/TR/html4/loose.dtd&#8221;&#62;
二、万能 float 闭合(非常重要!)
关于 [...]]]></description>
			<content:encoded><![CDATA[<p>一、CSS HACK<br />
以下两种方法几乎能解决现今所有HACK.</p>
<p>1, !important</p>
<p>随着IE7对!important的支持, !important 方法现在只针对IE6的HACK.(注意写法.记得该声明位置需要提前.)<br />
&lt;style&gt;<br />
#wrapper<br />
{<br />
width: 100px!important; /* IE7+FF */<br />
width: 80px; /* IE6 */<br />
}<br />
&lt;/style&gt;</p>
<p>2, IE6/IE77对FireFox</p>
<p>*+html 与 *html 是IE特有的标签, firefox 暂不支持.而*+html 又为 IE7特有标签.<br />
&lt;style&gt;<br />
#wrapper<br />
{<br />
#wrapper { width: 120px; } /* FireFox */<br />
*html #wrapper { width: 80px;} /* ie6 fixed */<br />
*+html #wrapper { width: 60px;} /* ie7 fixed, 注意顺序 */<br />
}<br />
&lt;/style&gt;</p>
<p>注意:<br />
*+html 对IE7的HACK 必须保证HTML顶部有如下声明：<br />
&lt;!DOCTYPE HTML PUBLIC &#8220;-//W3C//DTD HTML 4.01 Transitional//EN&#8221;　&#8221;http://www.w3.org/TR/html4/loose.dtd&#8221;&gt;</p>
<p>二、万能 float 闭合(非常重要!)</p>
<p>关于 clear float 的原理可参见 [How To Clear Floats Without Structural Markup]<br />
将以下代码加入Global CSS 中,给需要闭合的div加上 即可,屡试不爽.<br />
&lt;style&gt;<br />
/* Clear Fix */</p>
<p>.clearfix:after<br />
{<br />
content:&#8221;.&#8221;;<br />
display:block;<br />
height:0;<br />
clear:both;<br />
visibility:hidden;<br />
}<br />
.clearfix<br />
{<br />
display:inline-block;<br />
}<br />
/* Hide from IE Mac */<br />
.clearfix {display:block;}<br />
/* End hide from IE Mac */<br />
/* end of clearfix */<br />
&lt;/style&gt;</p>
<p>三、其他兼容技巧(再次啰嗦)</p>
<p>1, FF下给 div 设置 padding 后会导致 width 和 height 增加, 但IE不会.(可用!important解决)<br />
2, 居中问题.<br />
1).垂直居中.将 line-height 设置为 当前 div 相同的高度, 再通过 vertical-align: middle.( 注意内容不要换行.)<br />
2).水平居中. margin: 0 auto;(当然不是万能)<br />
3, 若需给 a 标签内内容加上 样式, 需要设置 display: block;(常见于导航标签)<br />
4, FF 和 IE 对 BOX 理解的差异导致相差 2px 的还有设为 float的div在ie下 margin加倍等问题.<br />
5, ul 标签在 FF 下面默认有 list-style 和 padding . 最好事先声明, 以避免不必要的麻烦. (常见于导航标签和内容列表)<br />
6, 作为外部 wrapper 的 div 不要定死高度, 最好还加上 overflow: hidden.以达到高度自适应.<br />
7, 关于手形光标. cursor: pointer. 而hand 只适用于 IE.</p>
<p>1 针对firefox ie6 ie7的css样式<br />
现在大部分都是用!important来hack，对于ie6和firefox测试可以正常显示，<br />
但是ie7对!important可以正确解释，会导致页面没按要求显示！找到一个针<br />
对IE7不错的hack方式就是使用“*+html”，现在用IE7浏览一下，应该没有问题了。<br />
现在写一个CSS可以这样：</p>
<p>#1 { color: #333; } /* Moz */<br />
* html #1 { color: #666; } /* IE6 */<br />
*+html #1 { color: #999; } /* IE7 */<br />
那么在firefox下字体颜色显示为#333，IE6下字体颜色显示为#666，IE7下字体颜色显示为#999。</p>
<p>2 css布局中的居中问题<br />
主要的样式定义如下：</p>
<p>body {TEXT-ALIGN: center;}<br />
#center { MARGIN-RIGHT: auto; MARGIN-LEFT: auto; }<br />
说明：<br />
首先在父级元素定义TEXT-ALIGN: center;这个的意思就是在父级元素内的内容居中；对于IE这样设定就已经可以了。<br />
但在mozilla中不能居中。解决办法就是在子元素定义时候设定时再加上“MARGIN-RIGHT: auto;MARGIN-LEFT: auto; ”<br />
需要说明的是，如果你想用这个方法使整个页面要居中，建议不要套在一个DIV里，你可以依次拆出多个div，<br />
只要在每个拆出的div里定义MARGIN-RIGHT: auto;MARGIN-LEFT: auto; 就可以了。</p>
<p>3 盒模型不同解释.</p>
<p>#box{ width:600px; //for ie6.0- w\idth:500px; //for ff+ie6.0}<br />
#box{ width:600px!important //for ff width:600px; //for ff+ie6.0 width /**/:500px; //for ie6.0-}</p>
<p>4 浮动ie产生的双倍距离</p>
<p>#box{ float:left; width:100px; margin:0 0 0 100px; //这种情况之下IE会产生200px的距离 display:inline; //使浮动忽略}<br />
这里细说一下block,inline两个元素,Block元素的特点是:总是在新行上开始,高度,宽度,行高,边距都可以控制(块元素);Inline元素的特点是:和其他元素在同一行上,&#8230;不可控制(内嵌元素);</p>
<p>#box{ display:block; //可以为内嵌元素模拟为块元素 display:inline; //实现同一行排列的的效果 diplay:table;</p>
<p>5 IE与宽度和高度的问题</p>
<p>IE不认得min-这个定义，但实际上它把正常的width和height当作有min的情况来使。这样问题就大了，如果只用宽度和高度，<br />
正常的浏览器里这两个值就不会变，如果只用min-width和min-height的话，IE下面根本等于没有设置宽度和高度。<br />
比如要设置背景图片，这个宽度是比较重要的。要解决这个问题，可以这样：<br />
#box{ width: 80px; height: 35px;}html&gt;body #box{ width: auto; height: auto; min-width: 80px; min-height: 35px;}</p>
<p>6 页面的最小宽度</p>
<p>min-width是个非常方便的CSS命令，它可以指定元素最小也不能小于某个宽度，这样就能保证排版一直正确。但IE不认得这个，<br />
而它实际上把width当做最小宽度来使。为了让这一命令在IE上也能用，可以把一个&lt;div&gt; 放到 &lt;body&gt; 标签下，然后为div指定一个类：<br />
然后CSS这样设计：<br />
#container{ min-width: 600px; width:expression(document.body.clientWidth &lt; 600? &#8220;600px&#8221;: &#8220;auto&#8221; );}<br />
第一个min-width是正常的；但第2行的width使用了Javascript，这只有IE才认得，这也会让你的HTML文档不太正规。它实际上通过Javascript的判断来实现最小宽度。</p>
<p>7 清除浮动</p>
<p>.hackbox{ display:table; //将对象作为块元素级的表格显示}或者.hackbox{ clear:both;}<br />
或者加入:after（伪对象）,设置在对象后发生的内容，通常和content配合使用，IE不支持此伪对象，非Ie 浏览器支持，<br />
所以并不影响到IE/WIN浏览器。这种的最麻烦的&#8230;&#8230;#box:after{ content: &#8220;.&#8221;; display: block; height: 0; clear: both; visibility: hidden;}</p>
<p>8 DIV浮动IE文本产生3象素的bug</p>
<p>左边对象浮动，右边采用外补丁的左边距来定位，右边对象内的文本会离左边有3px的间距.</p>
<p>#box{ float:left; width:800px;}#left{ float:left; width:50%;}#right{ width:50%;}*html #left{ margin-right:-3px; //这句是关键}<br />
HTML代码&lt;div&gt; &lt;div&gt;&lt;/div&gt; &lt;div&gt;&lt;/div&gt;&lt;/div&gt;</p>
<p>9 属性选择器(这个不能算是兼容,是隐藏css的一个bug)</p>
<p>p[id]{}div[id]{}<br />
这个对于IE6.0和IE6.0以下的版本都隐藏,FF和OPera作用<br />
属性选择器和子选择器还是有区别的,子选择器的范围从形式来说缩小了,属性选择器的范围比较大,如p[id]中,所有p标签中有id的都是同样式的.</p>
<p>10 IE捉迷藏的问题</p>
<p>当div应用复杂的时候每个栏中又有一些链接，DIV等这个时候容易发生捉迷藏的问题。<br />
有些内容显示不出来，当鼠标选择这个区域是发现内容确实在页面。<br />
解决办法：对#layout使用line-height属性 或者给#layout使用固定高和宽。页面结构尽量简单。</p>
<p>11 高度不适应</p>
<p>高度不适应是当内层对象的高度发生变化时外层高度不能自动进行调节，特别是当内层对象使用<br />
margin 或paddign 时。<br />
例：<br />
&lt;div&gt;<br />
&lt;p&gt;p对象中的内容&lt;/p&gt;<br />
&lt;/div&gt;<br />
CSS：#box {background-color:#eee; }<br />
#box p {margin-top: 20px;margin-bottom: 20px; text-align:center; }<br />
解决方法：在P对象上下各加2个空的div对象CSS代码：.1{height:0px;overflow:hidden;}或者为DIV加上border属性。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.zfkun.com/blog/index.php/archives/142/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>JavaScript的valueOf和toString</title>
		<link>http://www.zfkun.com/blog/index.php/archives/140</link>
		<comments>http://www.zfkun.com/blog/index.php/archives/140#comments</comments>
		<pubDate>Thu, 22 Apr 2010 16:01:25 +0000</pubDate>
		<dc:creator>影之迷惑</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[js]]></category>
		<category><![CDATA[toString]]></category>
		<category><![CDATA[valueOf]]></category>

		<guid isPermaLink="false">http://www.zfkun.com/blog/?p=140</guid>
		<description><![CDATA[JavaScript中valueOf函数方法是返回指定对象的原始值。JavaScript中toString函数方法是返回对象的字符串表示]]></description>
			<content:encoded><![CDATA[<p>JavaScript中valueOf函数方法是返回指定对象的原始值。</p>
<p> 对象 返回值<br />
Array 数组的元素被转换为字符串，这些字符串由逗号分隔，连接在一起。其操作与 Array.toString 和 Array.join 方法相同。<br />
Boolean Boolean 值。<br />
Date 存储的时间是从 1970 年 1 月 1 日午夜开始计的毫秒数 UTC。<br />
Function 函数本身。<br />
Number 数字值。<br />
Object 对象本身。这是默认情况。<br />
String 字符串值。</p>
<p>JavaScript中toString函数方法是返回对象的字符串表示<br />
对象 操作<br />
Array 将 Array 的元素转换为字符串。结果字符串由逗号分隔，且连接起来。<br />
Boolean 如果 Boolean 值是 true，则返回 “true”。否则，返回 “false”。<br />
Date 返回日期的文字表示法。<br />
Error 返回一个包含相关错误消息的字符串。<br />
Function 返回如下格式的字符串，其中 functionname 是被调用 toString 方法函数的名称： function functionname( ) { [native code] }<br />
Number 返回数字的文字表示。<br />
String 返回 String 对象的值。<br />
默认 返回 “[object objectname]”，其中 objectname 是对象类型的名称。</p>
<p>假设在古代，一两黄金换20两白银，一两白银换25枚铜钱，构建描述货币的类:</p>
<pre name="code" class="js">
function Money(gold, silver, coin)
{
 this.gold = gold;
 this.silver = silver;
 this.coin = coin;
}

Money.parse = function(value)
{
 var coin = parseInt(value % 25);
 var silver = parseInt(value / 25 % 20);
 var gold = parseInt(value / 500);
 return new Money(gold, silver, coin);
}

Money.prototype.valueOf = function()
{
 return ((this.gold * 20) + this.silver) * 25 + this.coin;
}

Money.prototype.toString = function()
{
 return this.gold + "两黄金，" + this.silver + "两白银，" + this.coin + "文钱";
}

var money1 = new Money(5, 6, 1);
var money2 = new Money(2, 4, 6);

var money3 = Money.parse(money1 + money2);
alert(money3);
</pre>
<p>这里隐式调用了valueOf跟toString，二者并存的情况下，在数值运算中，优先调用了valueOf，字符串运算中，优先调用了toString。比如<br />
money1 + money2，调用的就是两者valueOf之后的值相加，而alert的时候，把money3先toString了一下。</p>
<p>这个例子其实是模仿js内置对象Date的，Date基本上也是这样处理问题的。</p>
<pre name="code" class="js">
function Money(n)
{
this.n = n;
}
Money.prototype.valueOf = function()
{
 return this.n * 2
}
Money.prototype.toString = function()
{
 return this.n * 3
}
var m1 = new Money(1);
var m2 = new Money(2);
m = m1 + m2
alert(m1);
alert(m2);
alert(m);
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.zfkun.com/blog/index.php/archives/140/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Data URI 和 MHTML</title>
		<link>http://www.zfkun.com/blog/index.php/archives/138</link>
		<comments>http://www.zfkun.com/blog/index.php/archives/138#comments</comments>
		<pubDate>Sat, 10 Apr 2010 03:32:45 +0000</pubDate>
		<dc:creator>影之迷惑</dc:creator>
				<category><![CDATA[Web]]></category>
		<category><![CDATA[base64]]></category>
		<category><![CDATA[datauri]]></category>
		<category><![CDATA[mhtml]]></category>

		<guid isPermaLink="false">http://www.zfkun.com/blog/?p=138</guid>
		<description><![CDATA[Data URI是由RFC 2397定义的一种把小文件直接嵌入文档的方案。通过如下语法就可以把小文件变成指定编码直接嵌入到页面中。
MHTML是MIME HTML (Multipurpose Internet Mail Extension HTML)的缩写，是由RFC 2557定义的把一个多媒体的页面所有内容都保存到同一个文档解决方案。这个方案是由微软提出从IE5.0开始支持，另外Opera9.0也开始支持，Safari可以把文件保存为.mht（MHTML文件的后缀）格式，但不支持显示它。]]></description>
			<content:encoded><![CDATA[<h3>Data URI</h3>
<p><a href="http://en.wikipedia.org/wiki/Data_URI_scheme">Data URI</a>是由<a href="http://tools.ietf.org/html/rfc2397">RFC 2397</a>定义的一种把小文件直接嵌入文档的方案。通过如下语法就可以把小文件变成指定编码直接嵌入到页面中：</p>
<pre><code>data:[&lt;MIME-type&gt;][;base64],&lt;data&gt;
</code></pre>
<ol>
<li>MIME-type：指定嵌入数据的<a href="http://zh.wikipedia.org/wiki/MIME">MIME</a>。其形式是<code>[type]/[subtype]; parameter</code>，比如png图片对应的MIME是image/png。parameter可以用來指定附加的信息，更多情況下是用于指定text/plain和text/htm等的文字编码方式的charset参数。默认是text/plain;charset=US-ASCII。</li>
<li>base64：声明后面的数据的编码是<a href="http://zh.wikipedia.org/wiki/Base64">base64</a>的，否则数据必须要用百分号编码（即对内容进行urlencode）。</li>
</ol>
<p> </p>
<p>在上个世纪<a href="http://www.w3.org/TR/1999/REC-html401-19991224/struct/objects.html#h-13.3.1">HTML4.01引入了Data URI方案</a>，到今天为止<a href="http://en.wikipedia.org/wiki/Data_URI_scheme#Web_browser_support">除了IE6和IE7之外，所有主流浏览器都支持</a>，但<a href="http://msdn.microsoft.com/en-us/library/cc848897%28VS.85%29.aspx">IE8对Data URI的支持还是有限制的</a>，只支持object（仅是图片时）、img、input type=image、link和CSS中的URL，且数据量不能大于32K。</p>
<h4>优点：</h4>
<ol>
<li><a href="http://developer.yahoo.com/performance/rules.html#num_http">减少HTTP请求数</a>，没有了TCP连接消耗和同一域名下浏览器的并发数限制。</li>
<li>对于小文件会降低带宽。虽然编码后数据量会增加，但是却减少了http头，当http头的数据量大于文件编码的增量，那么就会降低带宽。</li>
<li>对于HTTPS站点，HTTPS和HTTP混用会有安全提示，而HTTPS相对于HTTP来讲开销要大更多，所以Data URI在这方面的优势更明显。</li>
<li>可以把整个多媒体页面保存为一个文件。</li>
</ol>
<h4>缺点：</h4>
<ol>
<li>无法被重复利用，同一个文档应用多次同一个内容，则需要重复多次，数据量大量增加，增加了下载时间。</li>
<li>无法被独自缓存，所以其包含文档重新加载时，它也要重新加载。</li>
<li>客户端需要重新解码和显示，增加了点消耗。</li>
<li>不支持数据压缩，base64编码会增加1/3大小，而urlencode后数据量会增加更多。</li>
<li>不利于安全软件的过滤，同时也存在一定的安全隐患。</li>
</ol>
<h3>MHTML</h3>
<p>MHTML是<a href="http://en.wikipedia.org/wiki/MHTML">MIME HTML (Multipurpose Internet Mail Extension HTML)</a>的缩写，是由<a href="http://tools.ietf.org/html/rfc2557">RFC 2557</a>定义的把一个多媒体的页面所有内容都保存到同一个文档解决方案。这个方案是由微软提出从IE5.0开始支持，另外Opera9.0也开始支持，Safari可以把文件保存为.mht（MHTML文件的后缀）格式，但不支持显示它。</p>
<p>MHTML和Data URI还比较类似，有更强大的功能和更复杂的语法，并且没有Data URI中“无法被重复利用”的缺点，但MHTML使用起来不够灵活方便，比如对资源引用的URL在mht文件中可以是相对地址，否则必须是绝对地址。hedger在<a href="http://www.hedgerwow.com/360/dhtml/base64-image/demo.php">《Cross Browser Base64 Encoded Images Embedded in HTML》</a>针对IE的解决方案使用的是相对路径就是因为声明了<code>Content-type:message/rfc822</code>使IE按照MHTML来解析，如果不修改<code>Content-type</code>则需要使用MHTML协议，这个时候必须使用绝对路径，如<a href="http://www.phpied.com/mhtml-when-you-need-data-uris-in-ie7-and-under/">《MHTML – when you need data: URIs in IE7 and under》</a>。</p>
<h3>应用</h3>
<p>Data URI和MHTML两者的配合可以完整的解决所有的主流浏览器，它们由于无法被缓存和重复利用的缺陷，所以并不适合直接在页面中使用，但在CSS和JavaScript文件中对图片适当地使用有非常大的优越性：</p>
<ol>
<li>大大减少请求数，现在大型网站的CSS引用了大量的图片资源。</li>
<li>CSS和JavaScript都可以被缓存，间接的实现了数据的缓存。</li>
<li>利用CSS可以解决Data URI的重复利用问题</li>
<li>告别<a href="http://www.alistapart.com/articles/sprites">CSS Sprites</a>，CSS Sprites的出现是为了减少请求数，但它除了<a href="http://blog.vlad1.com/2009/06/22/to-sprite-or-not-to-sprite/">带来在不确定情况下的异常</a>外，CSS Sprites还需要人为的图片合并，即使有合并工具也依旧必须人为地在如何有效的拼图上耗费大量的时间，并带来维护的困难。当你遵循一定的设计原则后，你就可以完全抛弃CSS Sprites来编写CSS，最后使用工具在上传到服务器环节把图片转换成Data URI和MHTML，如<a href="http://bluehua.org/tag/data-uri">《利用data-uri合并样式表和图片》</a>中用python实现的工具，这可以节约大量的时间。</li>
<li>base64编码把图片文件增加了1/3，Data URI和MHTML同时使用相当于增加了2/3，但CSS和JavaScript可以使用<a href="http://developer.yahoo.com/performance/rules.html#gzip">gzip压缩</a>，其可以节省2/3的数据量，所以使用gzip压缩后的最终数据量是<code>(1 + 1/3) * 2 * (1/3) = 8/9</code>，所以最终流量是减少的。</li>
</ol>
<p>为了方便在CSS中实现Data URI和MHTML，我写了一个Data URI &amp; MHTML 生成器，你可以看利用其生成<a href="http://dancewithnet.com/lab/2009/data-uri-mhtml/create/1250345288.php">Data URI &amp; MHTML应用实例</a>。</p>
<p>其他DEMO：   <a href="http://phpied.com/files/mhtml/mhtml.html" target="_blank">demo1</a>      <a href="http://labs.aoao.org.cn/yep/test.html" target="_blank">demo2</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.zfkun.com/blog/index.php/archives/138/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>挑战 hax.tor.hu 申请带ssh的免费php+mysql空间</title>
		<link>http://www.zfkun.com/blog/index.php/archives/135</link>
		<comments>http://www.zfkun.com/blog/index.php/archives/135#comments</comments>
		<pubDate>Fri, 19 Mar 2010 02:39:25 +0000</pubDate>
		<dc:creator>影之迷惑</dc:creator>
				<category><![CDATA[Develop]]></category>
		<category><![CDATA[free]]></category>
		<category><![CDATA[hax]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[ssh]]></category>
		<category><![CDATA[tor.hu]]></category>

		<guid isPermaLink="false">http://www.zfkun.com/blog/?p=135</guid>
		<description><![CDATA[hax.tor.hu 是一家提供带ssh的免费php+mysql虚拟主机的空间服务商，而且它的SSH隧道是开通的,但是想获得这一免费午餐，却让我大伤脑筋，因为它要求通 过它的五道变态难题才行]]></description>
			<content:encoded><![CDATA[<p>hax.tor.hu  是一家提供带ssh的免费php+mysql虚拟主机的空间服务商，而且它的SSH隧道是开通的,但是想获得这一免费午餐，却让我大伤脑筋，因为它要求通 过它的五道变态难题才行。</p>
<p>打开 <a href="http://hax.tor.hu/warmup1/">http://hax.tor.hu/warmup1/</a> 开始猜解密码</p>
<p>1.这道题是用javascript设置的，提示“Password is in source.”说明密码就在网页之中，打开源码找到JS部分：</p>
<p>function a(){   thepw = ‘warmup1′;   thepw = thepw+’lol’;   thepw =  thepw + ‘copter’;<br />
if (document.lf.pw.value==thepw) {     document.location = ‘/’+thepw; }<br />
else { alert(‘That is not correct. Please try   again.’);   } }   看到了吧，密码是 “warmup1lolcopter”.</p>
<p>2.提示输入 <a href="http://www.fbi.gov/">www.fbi.gov</a> 的SSH标记，有几个了解这些的连接，然而，这些连接只是扰乱视听。SSH一般使用<br />
22 端口，所以使用 PUTTY 或者是 telnet 尝试。</p>
<p>telnet  <a href="http://www.fbi.gov/">www.fbi.gov</a> 22  之后，出现的字符  SSH-1.99-Server-VII 便是答案</p>
<p>3.提交 “Bacon” 的变量名称。<br />
这个简单，源码中的 select name=”chosen”&gt; 说明 name=”chosen” ，所以在当前的浏览器中输入 <a href="http://hax.tor.hu/warmup3/?chosen=Bacon">http://hax.tor.hu/warmup3/?chosen=Bacon</a> 回 车就到第四关。</p>
<p>4.提示 密码又在源码中，打开源码并没有找到任何密码，密码一定在网页的报头中，Telnet 看看</p>
<p>telnet hax.tor.hu 80</p>
<p>回车输入</p>
<p>GET /pwfor4/ HTTP/1.1</p>
<p>Host: hax.tor.hu</p>
<p>看到返回信息了。</p>
<p>HTTP/1.1 200 OK<br />
Transfer-Encoding: chunked 22 The password is: stickpick   DOS窗口自动关闭。密码提示为 stickdeath</p>
<p>5.最后的一道难题。提示是下面的字符串是被加密后的密码，意思是解密给出的数值就是密码68 228 94 125 67 210 82 19</p>
<p>胡乱输入一个字符回车后，晕倒：Hash ！！！也就说给出的那些数字是密码的 哈希 值，而 哈希 算法从来有名</p>
<p>尝试了几次之后，发现这也不是什么 哈希 目前是 site</p>
<p>破解方法： 两个数字的组合，代表一个字母，三个数字的组合标记位数，所以不用理睬三个数字的组合，也不用管最后两个数字的组合。</p>
<p>对应表单</p>
<p>a 77<br />
b 78<br />
c 79<br />
d 72<br />
e 73<br />
f 74<br />
g 75<br />
h 68<br />
i 69<br />
j 70<br />
k 71<br />
l 64<br />
m 65<br />
n 66<br />
o 67<br />
p 92<br />
r 94<br />
s 95<br />
t 88<br />
u 89<br />
w 91<br />
z 86</p>
<p>比如：68 228 94 125 67 210 82 19 就是 site</p>
<p><span style="color: #ff0000;">(由于官方的这个对应表会随机的变化，所以实际情况请自行测试出对应表填写即可)</span></p>
<p>===============================================<br />
过了这五道难关，就可以申请账号了。输入账号，Email 后就去收邮件，收到邮件就登陆。</p>
<p><a href="https://hax.tor.hu/login">https://hax.tor.hu/login</a> 刚一登陆，就面对的是 Challenges Level 1，就是输入一个符合其要求的URL<span style="color: #ff0000;">（其实很简单，也是混乱视听的）</span>。</p>
<p>不过别担心，不用理睬Challenges Level，点左栏的 [ Shell ]，申请 shell 账号，账号密码会邮件给你。</p>
<p>下来开始配置  VHOST ,<br />
配置空间大小，选 2000M 后点 “Update quota”,点 Web Setup 添加域名，在三个框中按照提示输入：</p>
<p><span style="color: #ff0000;">你的账号</span>.shell.tor.hu       www.<span style="color: #ff0000;">你的账号</span>.shell.tor.hu          /home/你的账号/www<span style="color: #ff0000;">（记得登陆空间后自行创建）</span></p>
<p>点 “Add vhost” 完成。</p>
<p>也可以输入自己的域名，但需要做CNAME 或者是 A 记录。这里是说明文件<a href="http://shell.tor.hu/doc/web.txt"> http://shell.tor.hu/doc/web.txt</a></p>
<p>终于完成了申请，开始传文件。</p>
<p>现在打开 http://你的账号.shell.tor.hu  就能访问你的主页了。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.zfkun.com/blog/index.php/archives/135/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>5 个简单实用的 CSS 属性</title>
		<link>http://www.zfkun.com/blog/index.php/archives/131</link>
		<comments>http://www.zfkun.com/blog/index.php/archives/131#comments</comments>
		<pubDate>Tue, 09 Mar 2010 01:57:06 +0000</pubDate>
		<dc:creator>影之迷惑</dc:creator>
				<category><![CDATA[Web]]></category>
		<category><![CDATA[clip]]></category>
		<category><![CDATA[css]]></category>
		<category><![CDATA[cursor]]></category>
		<category><![CDATA[display]]></category>
		<category><![CDATA[min-height]]></category>
		<category><![CDATA[white-space]]></category>

		<guid isPermaLink="false">http://www.zfkun.com/blog/?p=131</guid>
		<description><![CDATA[这篇文章介绍了 5 个实用的 CSS 属性。你应该很熟悉，但很可能很少会使用到。我并不是在谈论展望全新的 CSS3 属性，我指的是旧的 CSS2 中的属性，如：clip，min-height，white-space，curosr 和 display 等一些被所有浏览器广泛支持的属性。]]></description>
			<content:encoded><![CDATA[<p>这篇文章介绍了 5 个实用的 <strong>CSS</strong> 属性。你应该很熟悉，但很可能很少会使用到。我并不是在谈论展望全新的 CSS3 属性，我指的是旧的 CSS2 中的属性，如：clip，min-height，white-space，curosr 和 display 等一些被所有浏览器广泛支持的属性。因此，千万不要错过这篇文章，因为你可能发现它们竟有如此之大的用途。</p>
<p><strong>1、CSS Clip</strong></p>
<p>剪辑 (clip) 属性就像一个面具。它允许你使用矩形掩盖页面元素的内容。要剪辑一个元素：你必须指定其 position 属性为 absolute，然后指定相对于元素的 top，right，bottom，left 值。</p>
<p><img src="http://www.blueidea.com/articleimg/2010/03/7410/01.gif" border="0" alt="" width="470" height="349" /></p>
<p><strong>图片剪辑实例（<a href="http://www.webdesignerwall.com/wp-content/uploads/2009/11/css-clip.html" target="_blank">演示</a>）</strong></p>
<p>以下示例演示了如何使用 clip 属性掩盖一张图片。首先，指定 &lt;div&gt; 元素为 position:relative，然后指定 &lt;img&gt; 元素为 position:absolute，并且根据实际需要设定 rect 值。</p>
<p><img src="http://www.blueidea.com/articleimg/2010/03/7410/02.gif" border="0" alt="" width="470" height="219" /></p>
<pre name="code" class="css">
.clip {
  position: relative;
  height: 130px;
  width: 200px;
  border: solid 1px #ccc;
}
.clip img {
  position: absolute;
  clip: rect(30px 165px 100px 30px);
}
</pre>
<pre><strong>图像调整尺寸和剪辑（<a href="http://www.webdesignerwall.com/wp-content/uploads/2009/11/css-clip.html" target="_blank">演示</a>）</strong></pre>
<p>在这个示例中，我将展示如何调整图像尺寸和剪辑图片。素材图片是矩形的，我想将其削减至 50％ 的尺寸，用来创建一个正方形格式的缩略图。因此，我用宽度和高度属性来调整图像，并使用 clip 剪辑属性予以掩盖。然后用 left 属性将图片移开左侧 15px 的距离。</p>
<p><img src="http://www.blueidea.com/articleimg/2010/03/7410/03.gif" border="0" alt="" width="470" height="422" /></p>
<pre name="code" class="css">
.gallery li {
  float: left;
  margin: 0 10px 0 0;
  position: relative;
  width: 70px;
  height: 70px;
  border: solid 1px #000;
}
.gallery img {
  width: 100px;
  height: 70px;
  position: absolute;
  clip: rect(0 85px 70px 15px);
  left: -15px;
}
</pre>
<pre><strong>2、Min-height （<a href="http://www.webdesignerwall.com/wp-content/uploads/2009/11/min-height.html" target="_blank">演示</a>）</strong></pre>
<p>min-height 属性允许你指定元素的最小高度，适用于需要平衡布局的情况。我将它用于 <a href="http://jobs.webdesignerwall.com/" target="_blank">Job 面板</a>上，以确保内容区域高于侧边栏。</p>
<p><img src="http://www.blueidea.com/articleimg/2010/03/7410/04.gif" border="0" alt="" width="470" height="270" /></p>
<pre name="code" class="css">
.with_minheight {
  min-height: 550px;
}
</pre>
<p><strong>IE6 的 Min-height hack</strong></p>
<p>注：神奇的 IE6 原生不支持 min-height 属性，不过幸好有一个 <a href="http://www.dustindiaz.com/min-height-fast-hack/">min-height hack</a>。</p>
<pre name="code" class="css">
.with_minheight {
  min-height:550px;
  height:auto !important;
  height:550px;
}
</pre>
<pre><strong>3、White-space（<a href="http://www.webdesignerwall.com/wp-content/uploads/2009/11/white-space.html" target="_blank">演示</a>）</strong></pre>
<p>white-space 属性指定了元素中空白的处理方式。比如，指定 white-space:nowrap 会阻止文本自动换行。</p>
<p><img src="http://www.blueidea.com/articleimg/2010/03/7410/05.gif" border="0" alt="" width="470" height="258" /></p>
<pre name="code" class="css">
em {
  white-space: nowrap;
}
</pre>
<p><strong>4、Cursor（<a href="http://www.webdesignerwall.com/wp-content/uploads/2009/11/cursor.html" target="_blank">演示</a>）</strong></p>
<p>如果你改变了按钮的行为，其指针也应该随之改变。比如，当一个按钮不可用时，指针应该改变为默认的箭头，来表明它不可点击。因此，cursor 属性在开发 Web 应用程序时相当有用。</p>
<p><img src="http://www.blueidea.com/articleimg/2010/03/7410/06.gif" border="0" alt="" width="470" height="200" /></p>
<pre name="code" class="css">
.disabled {
  cursor: default;
}

.busy {
  cursor: wait;
}

.clickable:hover {
  cursor: pointer;
}
</pre>
<pre><strong>5、Display inline / block（<a href="http://www.webdesignerwall.com/wp-content/uploads/2009/11/display.html" target="_blank">演示</a>）</strong></pre>
<p>如果你不知道：块级元素是作为独立的一行来渲染的，而行内元素是在同一行被渲染的。&lt;div&gt;，&lt;h1&gt; 和 &lt;p&gt; 标签都是块级元素，&lt;em&gt;，&lt;span&gt;，&lt;strong&gt; 都是行内元素。通过 display:inline 或 block 的方式，你可以重设这些元素的 display 样式。</p>
<p><img src="http://www.blueidea.com/articleimg/2010/03/7410/07.gif" border="0" alt="" width="470" height="206" /></p>
<pre name="code" class="css">
.block em {
  display: block;
}

.inline h4, .inline p {
  display: inline;
}
</pre>
<pre>英文原稿：<a href="http://www.webdesignerwall.com/tutorials/5-simple-but-useful-css-properties" target="_blank">5 Simple, But Useful CSS Properties | WebDesignWall</a>
翻译整理：<a href="http://www.mangguo.org/5-simple-but-useful-css-properties" target="_blank">5 个简单实用的 CSS 属性 | 芒果</a></pre>
<p>本文链接：<a href="http://www.blueidea.com/tech/web/2010/7410.asp" target="_blank">http://www.blueidea.com/tech/web/2010/7410.asp</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.zfkun.com/blog/index.php/archives/131/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PureMVC Standard for JavaScript</title>
		<link>http://www.zfkun.com/blog/index.php/archives/127</link>
		<comments>http://www.zfkun.com/blog/index.php/archives/127#comments</comments>
		<pubDate>Mon, 08 Mar 2010 03:55:06 +0000</pubDate>
		<dc:creator>影之迷惑</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[framework]]></category>
		<category><![CDATA[js]]></category>
		<category><![CDATA[mvc]]></category>
		<category><![CDATA[puremvc]]></category>

		<guid isPermaLink="false">http://www.zfkun.com/blog/?p=127</guid>
		<description><![CDATA[PureMVC is a lightweight framework for creating applications based upon the classic  Model-View-Controller design meta-pattern. This is the specific implementation for the JavaScript language.]]></description>
			<content:encoded><![CDATA[<p><a title="PureMVC_JS" href="http://trac.puremvc.org/PureMVC_JS/" target="_blank">PureMVC</a> is a lightweight framework for creating applications based upon the classic  <a title="MVC" href="http://en.wikipedia.org/wiki/Model-view-controller" target="_blank">Model-View-Controller</a> design meta-pattern. This is the specific implementation for the JavaScript language.</p>
<h2 id="Note">Home</h2>
<p><a href="http://trac.puremvc.org/PureMVC_JS/">http://trac.puremvc.org/PureMVC_JS/</a></p>
<h2>Note</h2>
<p>Unlike the prior version which used  Objs, the current version uses  MooTools for simulation of class relationships.</p>
<h2 id="Status">Platforms</h2>
<ul>
<li>JavaScript 1.5</li>
<li><a title="Mootools" href="http://mootools.net" target="_blank">Mootools core</a></li>
</ul>
<h2 id="License">License</h2>
<p>Your reuse is governed by the  Creative Commons Attribution 3.0 license.</p>
<p>This implementation, like all other official PureMVC implementations, demos and utilities, is open-source and free to use in personal or commercial applications. If you include the source of PureMVC (modified or not), in another work (open-source or not), you must simply leave in the existing attribution and license information in the included source code.</p>
<h2 id="CurrentVersion">Current Version</h2>
<ul>
<li>2.0</li>
</ul>
<h2 id="SubversionRepository">Subversion Repository</h2>
<ul>
<li><strong>Location:</strong> <a href="http://svn.puremvc.org/PureMVC_JS" target="_blank">http://svn.puremvc.org/PureMVC_JS</a></li>
<li><strong>Latest Release:</strong> tags/2.0</li>
</ul>
<h2 id="Downloads">Downloads</h2>
<ul>
<li> <a href="http://puremvc.org/pages/downloads/JS/PureMVC_JS.zip" target="_blank">PureMVC Framework for JavaScript </a>(.zip archive)</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.zfkun.com/blog/index.php/archives/127/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>contains vs compareDocumentPosition</title>
		<link>http://www.zfkun.com/blog/index.php/archives/125</link>
		<comments>http://www.zfkun.com/blog/index.php/archives/125#comments</comments>
		<pubDate>Sun, 07 Mar 2010 11:04:34 +0000</pubDate>
		<dc:creator>影之迷惑</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[compareDocumentPosition]]></category>
		<category><![CDATA[contains]]></category>
		<category><![CDATA[dom]]></category>
		<category><![CDATA[js]]></category>

		<guid isPermaLink="false">http://www.zfkun.com/blog/?p=125</guid>
		<description><![CDATA[一个很棒的 blog 文章，是 PPK 两年前写的，文章中解释了 contains() 和 compareDocumentPosition() 方法运行在他们各自的浏览器上。从那起，我已经对这些方法做了大量的研究，并且已经在很多场合使用他们。在很多任务中，他们被证明是非常有用的（特别关于结构的抽象 DOM 选择器）]]></description>
			<content:encoded><![CDATA[<p>    一个很棒的 blog 文章，是 PPK 两年前写的，文章中解释了 contains() 和 compareDocumentPosition() 方法运行在他们各自的浏览器上。从那起，我已经对这些方法做了大量的研究，并且已经在很多场合使用他们。在很多任务中，他们被证明是非常有用的（特别关于结构的抽象 DOM 选择器）。</p>
<p>    1、DOMElement.contains(DOMNode)</p>
<p>    这个方法起先用在 IE ，用来确定 DOM Node 是否包含在另一个 DOM Element 中。</p>
<p>    当尝试优化 CSS 选择器遍历（像：“#id1 #id2”），这个方法很有用。你可以通过 getElementById 得到元素，然后使用 .contains() 确定 #id1 实际上是否包含 #id2。</p>
<p>    注意点：如果 DOM Node 和 DOM Element 相一致，.contains() 将返回 true ，虽然，一个元素不能包含自己。</p>
<p>    这里有一个简单的执行包装，可以运行在：Internet Explorer, Firefox, Opera, and Safari。</p>
<table border="1" cellspacing="1" cellpadding="1" width="80%" align="center">
<tbody>
<tr>
<td bgcolor="#c0c0c0"> function contains(a, b) {<br />
 return a.contains ? a != b &amp;&amp; a.contains(b) : !!(a.compareDocumentPosition(arg) &amp; 16);<br />
}</td>
</tr>
</tbody>
</table>
<p>    2、NodeA.compareDocumentPosition(NodeB)</p>
<p>    这个方法是 DOM Level 3 specification 的一部分，允许你确定 2 个 DOM Node 之间的相互位置。这个方法比 .contains() 强大。这个方法的一个可能应用是排序 DOM Node 成一个详细精确的顺序。</p>
<p>    使用这个方法你可以确定关于一个元素位置的一连串的信息。所有的这些信息将返回一个比特码（Bit，比特，亦称二进制位）。</p>
<p>    对于那些，人们知之甚少。比特码是将多重数据存储为一个简单的数字（译者注：0 或 1）。你最终打开 / 关闭个别数目（译者注：打开/关闭对应 0 /1），将给你一个最终的结果。</p>
<p>    这里是从 NodeA.compareDocumentPosition(NodeB) 返回的结果，包含你可以得到的信息。</p>
<table border="1" cellspacing="1" cellpadding="1" width="80%" align="center">
<tbody>
<tr>
<td bgcolor="#c0c0c0"> Bits          Number        Meaning<br />
000000         0              元素一致<br />
000001         1              节点在不同的文档（或者一个在文档之外）<br />
000010         2              节点 B 在节点 A 之前<br />
000100         4              节点 A 在节点 B 之前<br />
001000         8              节点 B 包含节点 A<br />
010000         16             节点 A 包含节点 B<br />
100000         32             浏览器的私有使用</td>
</tr>
</tbody>
</table>
<p>    现在，这意味着一个可能的结果类似于：</p>
<table border="1" cellspacing="1" cellpadding="1" width="80%" align="center">
<tbody>
<tr>
<td bgcolor="#c0c0c0"> &lt;div id=&#8221;a&#8221;&gt;<br />
 &lt;div id=&#8221;b&#8221;&gt;&lt;/div&gt;<br />
&lt;/div&gt;<br />
&lt;script&gt;<br />
 alert( document.getElementById(&#8220;a&#8221;).compareDocumentPosition(document.getElementById(&#8220;b&#8221;)) == 20);<br />
&lt;/script&gt;</td>
</tr>
</tbody>
</table>
<p>    一旦一个节点 A 包含另一个节点 B，包含 B（+16） 且在 B 之前（+4），则最后的结果是数字 20 。如果你查看比特发生的变化，将增加你的理解。</p>
<p>000100 (4) + 010000 (16) = 010100 (20)</p>
<p>    这个，毫无疑问，有助于理解单个最混乱的 DOM API 方法。当然，他的价值当之无愧的。</p>
<p>    现在，DOMNode.compareDocumentPosition 在 Firefox 和 Opera 中是可用的。然而，有一些技巧，我们可以用来在 IE 中执行他。</p>
<table border="1" cellspacing="1" cellpadding="1" width="80%" align="center">
<tbody>
<tr>
<td bgcolor="#c0c0c0"> // Compare Position &#8211; MIT Licensed, John Resig<br />
function comparePosition(a, b){<br />
 return a.compareDocumentPosition ?<br />
 a.compareDocumentPosition(b) :<br />
 a.contains ?<br />
  ( a != b &amp;&amp; a.contains(b) &amp;&amp; 16 ) +<br />
  ( a != b &amp;&amp; b.contains(a) &amp;&amp; 8 ) +<br />
  ( a.sourceIndex &gt;= 0 &amp;&amp; b.sourceIndex &gt;= 0 ?<br />
   (a.sourceIndex &lt; b.sourceIndex &amp;&amp; 4 ) +<br />
   (a.sourceIndex &gt; b.sourceIndex &amp;&amp; 2 ) :<br />
   1 ) :<br />
  0;<br />
}</td>
</tr>
</tbody>
</table>
<p>    IE 提供给我们一些可以使用的方法和属性。开始，使用 .contains() 方法（如我们前面所讨论的），以便给我们包含（+16）或者被包含（+8）的结果。IE 还有一个 .sourceIndex 属性在所有的 DOM Element 对应着元素在文档中的位置，例如：document.documentElement.sourceIndex == 0。因为我们有这个信息，我们可以完成两个 compareDocumentPosition 难题：在前面（+2）和在后面（+4）。另外，如果一个元素不在当前的文档，.sourceIndex 将等于 -1，这个给我们另外一个回答（+1）。最后，通过这个过程的推断，我们可以确定如果一个元素等于他本身，返回一个空的比特码（+0）。</p>
<p>    这个函数可以在 Internet Explorer、Firefox 和 Opera 中运行。但在 Safari 中却有残缺功能（因为他只有 contains() 方法，而没有 .sourceIndex 属性。我们只能得到包含（+16），被包含（+8），其他的所有结果都将返回（+1）代表一个断开）。</p>
<p>    PPK 提供了一个关于通过创建一个 getElementsByTagNames 方法使新功能可以被使用的很棒的例子。让我们改编他到我们的新方法中：</p>
<table border="1" cellspacing="1" cellpadding="1" width="80%" align="center">
<tbody>
<tr>
<td bgcolor="#c0c0c0">// Original by PPK quirksmode.org<br />
function getElementsByTagNames(list, elem) {<br />
        elem = elem || document;                 var tagNames = list.split(’,’), results = [];         </p>
<p>        for ( var i = 0; i &lt; tagNames.length; i++ ) {<br />
                var tags = elem.getElementsByTagName( tagNames[i] );<br />
                for ( var j = 0; j &lt; tags.length; j++ )<br />
                        results.push( tags[j] );<br />
        }         </p>
<p>        return results.sort(function(a, b){<br />
                return 3 &#8211; (comparePosition(a, b) &amp; 6);<br />
        });<br />
}</td>
</tr>
</tbody>
</table>
<p>    我们现在可以使用他来按次序构建一个站点的目录：</p>
<p>getElementsByTagNames(&#8220;h1, h2, h3&#8243;);</p>
<p>    虽然 Firefox 和 Opera 都采取了一些主动落实这一方法。我依然期待看到更多的浏览器进入，以帮助向前推动</p>
]]></content:encoded>
			<wfw:commentRss>http://www.zfkun.com/blog/index.php/archives/125/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>JS闭包之词法作用域</title>
		<link>http://www.zfkun.com/blog/index.php/archives/117</link>
		<comments>http://www.zfkun.com/blog/index.php/archives/117#comments</comments>
		<pubDate>Fri, 05 Mar 2010 05:34:43 +0000</pubDate>
		<dc:creator>影之迷惑</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[js]]></category>
		<category><![CDATA[scope]]></category>

		<guid isPermaLink="false">http://www.zfkun.com/blog/?p=117</guid>
		<description><![CDATA[var classA = function(){
    this.prop1 = 1;
}
classA.prototype.func1 = function(){
    var that = this,
        var1 = 2; 

    function a(){
        return function(){
            [...]]]></description>
			<content:encoded><![CDATA[<pre name="code" class="js">var classA = function(){
    this.prop1 = 1;
}
classA.prototype.func1 = function(){
    var that = this,
        var1 = 2; 

    function a(){
        return function(){
            alert(var1);
            alert(this.prop1);
        }.apply(that);
    };
    a();
}
var objA = new ClassA();
objA.func1();</pre>
<p>大家应该写过上面类似的代码吧，其实这里我想要表达的是有时候一个方法定义的地方和使用的地方会相隔十万八千里，那方法执行时，它能访问哪些变量，不能访问哪些变量，这个怎么判断呢？这个就是我们这次需要分析的问题—词法作用域</p>
<p><strong>词法作用域：</strong>变量的作用域是在定义时决定而不是执行时决定，也就是说词法作用域取决于源码，通过静态分析就能确定，因此词法作用域也叫做静态作用域。 with和eval除外，所以只能说JS的作用域机制非常接近词法作用域（Lexical scope）。</p>
<p>下面通过几个小小的案例，开始深入的了解对理解词法作用域和闭包必不可少的，JS执行时底层的一些概念和理论知识。</p>
<h3>经典案列重现</h3>
<h4>1、经典案例一</h4>
<pre name="code" class="js">/*全局（window）域下的一段代码*/
function a(i) {
    var i;
    alert(i);
};
a(10);</pre>
<p>疑问：上面的代码会输出什么呢？<br />
答案：没错，就是弹出10。具体执行过程应该是这样的</p>
<ol>
<li>a 函数有一个形参 i，调用 a 函数时传入实参 10，形参 i=10</li>
<li>接着定义一个同名的局部变量 i，未赋值</li>
<li>alert 输出 10</li>
<li>思考：局部变量 i 和形参 i 是同一个存储空间吗？</li>
</ol>
<h4>2、经典案例二</h4>
<pre name="code" class="js">/*全局（window）域下的一段代码*/
function a(i) {
    alert(i);
    alert(arguments[0]); //arguments[0]应该就是形参 i
    var i = 2;
    alert(i);
    alert(arguments[0]);
};
a(10);</pre>
<p>疑问：上面的代码又会输出什么呢？（（ 10,10,2,10 || 10,10,2,2 ））<br />
答案：在FireBug中的运行结果是第二个10,10,2,2，猜对了… ，下面简单说一下具体执行过程</p>
<ol>
<li>a 函数有一个形参i，调用 a 函数时传入实参 10，形参 i=10</li>
<li>第一个 alert 把形参 i 的值 10 输出</li>
<li>第二个 alert 把 arguments[0] 输出，应该也是 i</li>
<li>接着定义个局部变量 i 并赋值为2，这时候局部变量 i=2</li>
<li>第三个 alert 就把局部变量 i 的值 2 输出</li>
<li>第四个alert再次把 arguments[0] 输出</li>
<li>思考：这里能说明局部变量 i 和形参 i 的值相同吗？</li>
</ol>
<h4>3、经典案例三</h4>
<pre name="code" class="js">/*全局（window）域下的一段代码*/
function a(i) {
    alert(i);
    alert(arguments[0]); //arguments[0]应该就是形参 i
    var i = 2;
    alert(i);
    alert(arguments[0]);
};
a(10);</pre>
<p>疑问：上面的代码又又会输出什么呢？（（ undefined || 10 ））<br />
答案：在FireBug中的运行结果是 10，下面简单说一下具体执行过程</p>
<ol>
<li>第一句声明一个与形参 i 同名的局部变量 i，根据结果我们知道，后一个 i 是指向了</li>
<li>形参 i，所以这里就等于把形参 i 的值 10 赋了局部变量 i</li>
<li>第二个 alert 当然就输出 10</li>
<li>思考：结合案列二，这里基本能说明局部变量 i 和形参 i 指向了同一个存储地址！</li>
</ol>
<h4>4、经典案例四</h4>
<pre name="code" class="js">/*全局（window）域下的一段代码*/
var i=10;
function a() {
    alert(i);
    var i = 2;
    alert(i);
};
a();</pre>
<p>疑问：上面的代码又会输出什么呢？（小子，看这回整不死你！哇哈哈，就不给你选项）<br />
答案：在FireBug中的运行结果是 undefined, 2，下面简单说一下具体执行过程</p>
<ol>
<li>第一个alert输出undefined</li>
<li>第二个alert输出 2</li>
<li>思考：到底怎么回事儿？</li>
</ol>
<h4>5、经典案例五…………..N</h4>
<p>看到上面的几个例子，你可能会想，怎么可能，我写了几年的 js 了，怎么这么简单例子也会犹豫，结果可能还答错了。其实可能原因是：我们能很快的写出一个方法，但到底方法内部是怎么执行的呢？执行的细节又是怎么样的呢？你可能没有进行过深入的学习和了解。要了解这些细节，那就需要了解 JS 引擎的工作方式，所以下面我们就把 JS 引擎对一个方法的解析过程进行一个稍微深入一些的介绍</p>
<h4>解析过程</h4>
<p><strong>1、执行顺序</strong></p>
<ul>
<li>编译型语言，编译步骤分为：词法分析、语法分析、语义检查、代码优化和字节生成。</li>
<li>解释型语言，通过词法分析和语法分析得到语法分析树后，就可以开始解释执行了。这里是一个简单原始的关于解析过程的原理，仅作为参考，详细的解析过程（各种JS引擎还有不同）还需要更深一步的研究</li>
</ul>
<p>JavaScript执行过程，如果一个文档流中包含多个script代码段（用script标签分隔的js代码或引入的js文件），它们的运行顺序是：</p>
<ol>
<li>步骤1. 读入第一个代码段（js执行引擎并非一行一行地执行程序，而是一段一段地分析执行的）</li>
<li>步骤2. 做词法分析和语法分析，有错则报语法错误（比如括号不匹配等），并跳转到步骤5</li>
<li>步骤3. 对【var】变量和【function】定义做“预解析“（永远不会报错的，因为只解析正确的声明）</li>
<li>步骤4. 执行代码段，有错则报错（比如变量未定义）</li>
<li>步骤5. 如果还有下一个代码段，则读入下一个代码段，重复步骤2</li>
<li>步骤6. 结束</li>
</ol>
<p><strong>2、特殊说明</strong><br />
全局域（window）域下所有JS代码可以被看成是一个“匿名方法“，它会被自动执行，而此“匿名方法“内的其它方法则是在被显示调用的时候才被执行<br />
<strong>3、关键步骤</strong><br />
上面的过程，我们主要是分成两个阶段</p>
<ol>
<li>解析：就是通过语法分析和预解析构造合法的语法分析树。</li>
<li>执行：执行具体的某个function，JS引擎在执行每个函数实例时，都会创建一个执行环境（ExecutionContext）和活动对象（activeObject）（它们属于宿主对象，与函数实例的生命周期保持一致）</li>
</ol>
<p><strong>3、关键概念</strong><br />
到这里，我们再更强调以下一些概念，这些概念都会在下面用一个一个的实体来表示，便于大家理解</p>
<ul>
<li>语法分析树（SyntaxTree）可以直观地表示出这段代码的相关信息,具体的实现就是JS引擎创建了一些表，用来记录每个方法内的变量集（variables），方法集（functions）和作用域（scope）等</li>
<li>执行环境（ExecutionContext）可理解为一个记录当前执行的方法【外部描述信息】的对象,记录所执行方法的类型，名称，参数和活动对象（activeObject）</li>
<li>活动对象（activeObject）可理解为一个记录当前执行的方法【内部执行信息】的对象,记录内部变量集（variables）、内嵌函数集（functions）、实参（arguments）、作用域链（scopeChain）等执行所需信息，其中内部变量集（variables）、内嵌函数集（functions）是直接从第一步建立的语法分析树复制过来的</li>
<li>词法作用域：变量的作用域是在定义时决定而不是执行时决定，也就是说词法作用域取决于源码，通过静态分析就能确定，因此词法作用域也叫做静态作用域。 with和eval除外，所以只能说JS的作用域机制非常接近词法作用域（Lexical scope）</li>
<li>作用域链：词法作用域的实现机制就是作用域链（scopeChain）。作用域链是一套按名称查找（Name Lookup）的机制，首先在当前执行环境的 ActiveObject 中寻找，没找到，则顺着作用域链到父 ActiveObject 中寻找，一直找到全局调用对象（Global Object）</li>
</ul>
<p><strong>4、实体表示</strong><br />
<img src="http://ued.sohu.com/uploads/2009/11/%E6%8D%95%E8%8E%B7.JPG" alt="源码，语法分析树，执行环境和活动对象的引用关系" /></p>
<h3>解析模拟</h3>
<p>估计，看到这儿，大家还是很朦胧吧，什么是语法分析树，语法分析树到底长什么样子，作用域链又怎么实现的，活动对象又有什么内容等等，还是不是太清晰，下面我们就通过一段实际的代码来模拟整个解析过程，我们就把语法分析树，活动对象实实在在的创建出来，理解作用域，作用域链的到底是怎么实现的<br />
<strong>1、模拟代码</strong></p>
<pre name="code" class="js">/*全局（window）域下的一段代码*/
var i = 1,j = 2,k = 3;
function a(o,p,x,q){
    var x = 4;
        alert(i);
    function b(r,s) {
        var i = 11,y = 5;
            alert(i);
        function c(t){
          var z = 6;
                alert(i);
        };
            //函数表达式
        var d = function(){
                alert(y);
            };
            c(60);
            d();
    };
        b(40,50);
}
a(10,20,30);</pre>
<p><strong>2、语法分析树</strong><br />
上面的代码很简单，就是先定义了一些全局变量和全局方法，接着在方法内再定义局部变量和局部方法，现在JS解释器读入这段代码开始解析，前面提到 JS 引擎会先通过语法分析和预解析得到语法分析树，至于语法分析树长什么样儿，都有些什么信息，下面我们以一种简单的结构：一个 JS 对象(为了清晰表示个各种对象间的引用关系，这里的只是伪对象表示，可能无法运行)来描述语法分析树（这是我们比较熟悉的，实际结构我们不去深究，肯定复杂得多，这里是为了帮助理解解析过程而特意简化）</p>
<pre name="code" class="js">/**
* 模拟建立一棵语法分析树，存储function内的变量和方法
*/
var SyntaxTree = {
        // 全局对象在语法分析树中的表示
    window: {
        variables:{
            i:{ value:1},
            j:{ value:2},
            k:{ value:3}
        },
        functions:{
            a: this.a
        }
    }, 

    a:{
        variables:{
            x:'undefined'
        },
        functions:{
            b: this.b
        },
        scope: this.window
    }, 

    b:{
        variables:{
            y:'undefined'
        },
        functions:{
            c: this.c,
            d: this.d
        },
        scope: this.a
    }, 

    c:{
        variables:{
            z:'undefined'
        },
        functions:{},
        scope: this.b
    }, 

    d:{
        variables:{},
        functions:{},
        scope: {
           myname:d,
           scope: this.b
        }
    }
};</pre>
<p>上面就是关于语法分析树的一个简单表示，正如我们前面分析的，语法分析树主要记录了每个 function 中的变量集（variables），方法集（functions）和作用域（scope）<br />
语法分析树关键点</p>
<ul>
<li>1变量集（variables）中，只有变量定义，没有变量值，这时候的变量值全部为“undefined”</li>
<li>2作用域（scope），根据词法作用域的特点，这个时候每个变量的作用域就已经明确了，而不会随执行时的环境而改变。【什么意思呢？就是我们经常将一个方法 return 回去，然后在另外一个方法中去执行，执行时，方法中变量的作用域是按照方法定义时的作用域走。其实这里想表达的意思就是不管你在多么复杂，多么远的地方执行该方法，最终判断方法中变量能否被访问还是得回到方法定义时的地方查证】</li>
<li>3作用域（scope）建立规则</li>
<li>a对于函数声明和匿名函数表达式来说，[scope]就是它创建时的作用域</li>
<li>b对于有名字的函数表达式，[scope]顶端是一个新的JS对象（也就是继承了Object.prototype），这个对象有两个属性，第一个是自身的名称，第二个是定义的作用域，第一个函数名称是为了确保函数内部的代码可以无误地访问自己的函数名进行递归。</li>
</ul>
<p><strong>3、执行环境与活动对象</strong><br />
语法分析完成，开始执行代码。我们调用每一个方法的时候，JS 引擎都会自动为其建立一个执行环境和一个活动对象，它们和方法实例的生命周期保持一致，为方法执行提供必要的执行支持，针对上面的几个方法，我们这里统一为其建立了活动对象（按道理是在执行方法的时候才会生成活动对象，为了便于演示，这里一下子定义了所有方法的活动对象），具体如下：<br />
<strong>执行环境</strong></p>
<pre name="code" class="js">/**
* 执行环境:函数执行时创建的执行环境
*/
var ExecutionContext = {
    window: {
        type: 'global',
        name: 'global',
        body: ActiveObject.window
    }, 

    a:{
        type: 'function',
        name: 'a',
        body: ActiveObject.a,
        scopeChain: this.window.body
    }, 

    b:{
        type: 'function',
        name: 'b',
        body: ActiveObject.b,
        scopeChain: this.a.body
    }, 

    c:{
        type: 'function',
        name: 'c',
        body: ActiveObject.c,
        scopeChain: this.b.body
    }, 

    d:{
        type: 'function',
        name: 'd',
        body: ActiveObject.d,
        scopeChain: this.b.body
    }
}</pre>
<p>上面每一个方法的执行环境都存储了相应方法的类型（function）、方法名称（funcName）、活动对象（ActiveObject）、作用域链（scopeChain）等信息,其关键点如下：</p>
<ul>
<li>body属性，直接指向当前方法的活动对象</li>
<li>scopeChain属性，作用域链，它是一个链表结构，根据语法分析树中当前方法对应的scope属性，它指向scope对应的方法的活动对象（ActivceObject），变量查找就是跟着这条链条查找的</li>
</ul>
<p><strong>活动对象</strong></p>
<pre name="code" class="js">/**
* 活动对象：函数执行时创建的活动对象列表
*/
var ActiveObject = {
        window: {
        variables:{
            i: { value:1},
            j: { value:2},
            k: { value:3}
        },
        functions:{
            a: this.a
        }
    }, 

    a:{
        variables:{
            x: {value:4}
        },
        functions:{
            b: SyntaxTree.b
        },
        parameters:{
            o: {value: 10},
            p: {value: 20},
            x: this.variables.x,
            q: 'undefined'
        },
        arguments:[this.parameters.o,this.parameters.p,this.parameters.x]
    }, 

    b:{
        variables:{
            y:{ value:5}
        },
        functions:{
            c: SyntaxTree.c,
            d: SyntaxTree.d
        },
        parameters:{
            r:{value:40},
            s:{value:50}
        },
        arguments:[this.parameters.r,this.parameters.s]
    }, 

    c:{
        variables:{
            z:{ value:6}
        },
        functions:{},
        parameters:{
            u:{value:70}
        },
        arguments:[this.parameters.u]
    }, 

    d:{
        variables:{},
        functions:{},
        parameters:{},
        arguments:[]
    }
}</pre>
<p>上面每一个活动对象都存储了相应方法的内部变量集（variables）、内嵌函数集（functions）、形参（parameters）、实参（arguments）等执行所需信息，活动对象关键点</p>
<ul>
<li>创建活动对象，从语法分析树复制方法的内部变量集（variables）和内嵌函数集（functions）</li>
<li>方法开始执行，活动对象里的内部变量集全部被重置为 undefined</li>
<li>创建形参（parameters）和实参（arguments）对象，同名的实参，形参和变量之间是【引用】关系</li>
<li>执行方法内的赋值语句，这才会对变量集中的变量进行赋值处理</li>
<li>变量查找规则是首先在当前执行环境的 ActiveObject 中寻找，没找到，则顺着执行环境中属性 ScopeChain 指向的 ActiveObject 中寻找，一直到 Global Object（window）</li>
<li>方法执行完成后，内部变量值不会被重置，至于变量什么时候被销毁，请参考下面一条</li>
<li>方法内变量的生存周期取决于方法实例是否存在活动引用，如没有就销毁活动对象</li>
<li>6和7 是使闭包能访问到外部变量的根本原因</li>
</ul>
<h3>重释经典案例</h3>
<p>案列一二三</p>
<p>根据【在一个方法中，同名的实参，形参和变量之间是引用关系，也就是JS引擎的处理是同名变量和形参都引用同一个内存地址】，所以才会有二中的修改arguments会影响到局部变量的情况出现</p>
<p>案例四</p>
<p>根据【JS引擎变量查找规则，首先在当前执行环境的 ActiveObject 中寻找，没找到，则顺着执行环境中属性 ScopeChain 指向的 ActiveObject 中寻找，一直到 Global Object（window）】，所以在四中，因为在当前的ActiveObject中找到了有变量 i 的定义，只是值为 “undefined”，所以直接输出 “undefined” 了</p>
<h3>总结</h3>
<p>以上是我在学习和使用了JS一段时间后,为了更深入的了解它, 也为了更好的把握对它的应用, 从而在对闭包的学习过程中,自己对于词法作用域的一些理解和总结,中间可能有一些地方和真实的JS解释引擎有差异,因为我只是站在一个刚入门的前端开发人员而不是系统设计者的角度上去分析这个问题，希望能对JS开发者理解此法作用域带来一些帮助！</p>
<p>原文链接： <a href="http://ued.sohu.com/article/204">http://ued.sohu.com/article/204</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.zfkun.com/blog/index.php/archives/117/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Comet—“服务器推”技术</title>
		<link>http://www.zfkun.com/blog/index.php/archives/115</link>
		<comments>http://www.zfkun.com/blog/index.php/archives/115#comments</comments>
		<pubDate>Wed, 03 Mar 2010 06:02:46 +0000</pubDate>
		<dc:creator>影之迷惑</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[ajax]]></category>
		<category><![CDATA[comet]]></category>
		<category><![CDATA[js]]></category>
		<category><![CDATA[push]]></category>

		<guid isPermaLink="false">http://www.zfkun.com/blog/?p=115</guid>
		<description><![CDATA[Comet指的是一种Web应用程序架构。可以直接说，它不是一种技术，而是一种思想，只是这种思想采用了已有的技术去实现。在这种思想里，客户端（Client）不需要显式地向服务器端（Server）发出请求，Server会在其数据发生变化的时候主动将数据异步发送给Client，从而使Client能够及时更新数据并呈现给用户。它不同于传统的Web，也不同于当前流行的Ajax，这种思想非常架构思想非常适合event-driven(事件驱动)式的Web应用和对交互性及实时性要求很强的应用，比如股票交易，聊天室，Web IM，网游等。]]></description>
			<content:encoded><![CDATA[<h2>一、名称解释：</h2>
<p>Comet最早是由Alex Russell（Dojo Toolkit 项目主管和Dojo Foundation主席）在自己的博客中提出的术语，他是这样说的：”New services like Jot Live and Meebo are built with a style of data transmission that is neither traditional nor Ajax. Their brand of low-latency data transfer to the browser is unique, and it is becoming ever-more common. Lacking a better term, I’ve taken to calling this style of event-driven, server-push data streaming “Comet”.” “They all use long-lived HTTP connections to reduce the latency with which messages are passed to the server. In essence, they do not poll the server occasionally. Instead the server has an open line of communication with which it can push data to the client.”</p>
<p>Comet指的是一种Web应用程序架构。可以直接说，它不是一种技术，而是一种思想，只是这种思想采用了已有的技术去实现。在这种思想里，客户端（Client）不需要显式地向服务器端（Server）发出请求，Server会在其数据发生变化的时候主动将数据异步发送给Client，从而使Client能够及时更新数据并呈现给用户。它不同于传统的Web，也不同于当前流行的Ajax，这种思想非常架构思想非常适合event-driven(事件驱动)式的Web应用和对交互性及实时性要求很强的应用，比如股票交易，聊天室，Web IM，网游等。</p>
<h2>二、成功案例：</h2>
<ul>
<li><a href="http://mail.google.com/mail/help/chat.html" target="_blank">GMail’s GTalk integration</a></li>
<li><a href="http://jotlive.com/" target="_blank">Jot Live</a></li>
<li><a href="http://renkoo.com/" target="_blank">Renkoo</a></li>
<li><a href="http://meebo.com/" target="_blank">Meebo</a></li>
</ul>
<h2>三、实现方式：</h2>
<p>Comet使用Client和Server之前的HTTP长链接最为数据传输的通道。</p>
<p>实现Comet，最常见的有下面两种方式：</p>
<ol>
<li>Ajax的长轮询（long-polling）：Javascript在处理完服务器返回的信息后再次发出请求，重新建立连接。不同于一般的Ajax，Javascript请求Server，无数据时Server不中断请求，still loading，在一定时间内，获取到数据后，返回请求，又Javascript获取数据后再次发出请求，由此轮询。需要注意的是请求的间隔时间以及每次请求的最长Loading时间。<br />
优点：异步请求；无需浏览器任何插件支持；采用Ajax技术，兼容性强；<br />
缺点：会产生大量的通信量，只能通过增加轮询的时间间隔来减轻Server的压力；</li>
<li>Iframe结合Htmlfile流（streaming）：通过在页面上嵌入一个隐藏的Iframe，设置其src属性为一个长连接的请求，Server采用flush方式将数据作为前端Javascript函数的参数传递；<br />
优点：不会有很大的通信量，而且数据接收非常及时，并且无中断；<br />
缺点：会产生进度条的Loading状态并一直穿着，用户使用体验很不好，在Google Talk中，通过Htmlfile Active解决了IE下的进度条显示问题；保持长期链接也非常耗服务器资源；</li>
</ol>
<h2>四、临时采用方案：</h2>
<p>目前，白社会(bai.sohu.com)采用了第一种方式来实现实时消息的推送，这种方式还存在一个问题就是，在多个tab页下，如何保证没有相同域的长连接请求（IE在同域下只能同时支持两个长链接），于是采用了子域形式来区分多个域，以保证每个tab页下访问的地址都不在一个域名下，此时问题又出来了，出现了Ajax跨域名请求，不过这个问题比较常见，解决方案也很多，我们采用的是Iframe形式；由此，为了实现Comet，我们走了很长一条路，虽然路的确走完了，但是走得很长很艰难，这也是为什么称它为“临时解决方案”，因为它并不是一个完美的方案，但我也相信，以后会更加完美。</p>
<h2>五、现有可参考框架</h2>
<ol>
<li>Cometd：官方地址：<a href="http://www.cometd.org" target="_blank">www.cometd.org<br />
</a>可以参考<a href="http://www.blogjava.net/xmatthew/archive/2008/11/20/208911.html" target="_blank">http://www.blogjava.net/xmatthew/archive/2008/11/20/208911.html</a></li>
<li>Pushlet：官方地址：<a href="http://www.pushlets.com" target="_blank">www.pushlets.com</a><br />
pushlet 提供了基于 AJAX 的 JavaScript 库文件用于实现长轮询方式的”服务器推”；还提供了基于 iframe 的 JavaScript 库文件用于实现流方式的”服务器推”。<br />
可以参考<a href="http://http://www.javaeye.com/topic/89158" target="_blank">http://www.javaeye.com/topic/89158</a></li>
</ol>
<h2>六、文章参考</h2>
<ol>
<li><a href="http://www.ibm.com/developerworks/cn/web/wa-lo-comet/" target="_blank">Comet：基于 HTTP 长连接的”服务器推”技术</a></li>
<li><a href="http://www.ibm.com/developerworks/cn/web/wa-lo-w2fpak-comet/index.html" target="_blank">实战 Comet 应用程序开发</a></li>
<li><a href="http://en.wikipedia.org/wiki/Comet_(programming)" target="_blank">Comet on wikipedia</a></li>
</ol>
<p>最后，本人对Comet也未进行深入的研究，只是希望通过此文能给大家起一个抛砖引玉的作用，希望大家能够在客户端实时技术上能够起点帮助作用，能够越来越丰富我们前端技术。</p>
<p>原文地址： <a href="http://ued.sohu.com/article/118">http://ued.sohu.com/article/118</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.zfkun.com/blog/index.php/archives/115/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Javascript的变量与delete操作符</title>
		<link>http://www.zfkun.com/blog/index.php/archives/112</link>
		<comments>http://www.zfkun.com/blog/index.php/archives/112#comments</comments>
		<pubDate>Mon, 01 Mar 2010 05:19:40 +0000</pubDate>
		<dc:creator>影之迷惑</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[delete]]></category>
		<category><![CDATA[js]]></category>

		<guid isPermaLink="false">http://www.zfkun.com/blog/?p=112</guid>
		<description><![CDATA[Javascript中的delete操作虽然是一个小小的delete操作符，其行为却异常复杂]]></description>
			<content:encoded><![CDATA[<p><a href="http://nanto.asablo.jp/blog/2008/01/09/2552470">原文链接</a></p>
<p>虽然是一个小小的delete操作符，其行为却异常复杂。</p>
<p><!-- end Pukiwiki generated code--><!-- begin Pukiwiki generated code--><a id="contents_2"></a></p>
<ul>
<li><a href="#content_2_0">Javascript的变量</a></li>
<li><a href="#content_2_1">delete操作符删除的对象</a></li>
<li><a href="#content_2_2">对变量执行delete的情况</a></li>
<li><a href="#content_2_3">能删除的属性和不能删除的属性</a></li>
<li><a href="#content_2_4">能删除的变量和不能删除的变量</a></li>
<li><a href="#content_2_5">delete的返回值</a></li>
</ul>
<p> </p>
<h2 id="content_2_0">Javascript的变量</h2>
<p>实际上Javascript中，变量 = 对象属性，这是因为 Javascript 在执行脚本之前会创建一个Global对象，所有的全局变量都是这个Global对象的属性，执行函数时也会创建一个Activation对象，所有的局部变量都是这个Activation对象的属性。如下例：</p>
<pre name="code" class="js">var global = 42;
this.global;    // 42, 可以通过this来访问Global对象

this.global2 = 12;
global2;        // 12

function foo() {
  var local = 36;
  // 不过无法直接访问Activation，
  // 因此无法通过 foo.local 的方式来访问local变量
}</pre>
<h2 id="content_2_1">delete操作符删除的对象</h2>
<p>C++中也有delete操作符，它删除的是指针所指向的对象。例如：</p>
<pre name="code" class="c">// C++
class Object {
public:
  Object *x;
}

Object o;
o.x = new Object();
delete o.x;     // 上一行new的Object对象将被释放</pre>
<p>但Javascript的delete与C++不同，<strong>它不会删除o.x指向的对象，而是删除o.x属性本身</strong>。</p>
<pre>// Javascript
var o = {};
o.x = new Object();
delete o.x;     // 上一行new的Object对象依然存在
o.x;            // undefined，o的名为x的属性被删除了</pre>
<p>在实际的Javascript中，delete o.x之后，Object对象会由于失去了引用而被垃圾回收，所以delete o.x也就“相当于”删除了o.x所指向的对象，但这个动作并不是ECMAScript标准，也就是说，即使某个实现完全不删除Object对象，也不算是违反ECMAScript标准。</p>
<p>“删除属性而不是删除对象”这一点，可以通过以下的代码来确认。</p>
<pre name="code" class="js">var o = {};
var a = { x: 10 };
o.a = a;
delete o.a;    // o.a属性被删除
o.a;           // undefined
a.x;           // 10, 因为{ x: 10 } 对象依然被 a 引用，所以不会被回收</pre>
<p>另外，delete o.x 也可以写作 delete o["x"]，两者效果相同。</p>
<h2 id="content_2_2">对变量执行delete的情况</h2>
<p>由于变量也是 Global 或者是 Activation 对象的属性，所以对变量的delete操作也是同样的结果。</p>
<pre name="code" class="js">var global = 42;
delete global;     // 删除Global.global

function foo() {
  var local = 36;
  delete local;    // 删除Activation.local
}</pre>
<h2 id="content_2_3">能删除的属性和不能删除的属性</h2>
<p>并不是所有的属性都能被delete。例如，prototype中声明的属性就无法被delete：</p>
<pre name="code" class="js">function C() { this.x = 42; }
C.prototype.x = 12;

var o = new C();
o.x;     // 42, 构造函数中定义的o.x

delete o.x;
o.x;     // 12,  prototype中定义的o.x，即使再次执行delete o.x也不会被删除</pre>
<p>对象的预定义属性也无法删除。 可以认为这类属性带有DontDelete的特性。</p>
<pre name="code" class="js">var re = /abc/i;
delete re.ignoreCase;
re.ignoreCase; // true, ignoreCase无法删除</pre>
<h2 id="content_2_4">能删除的变量和不能删除的变量</h2>
<p>通过var声明的变量和通过function声明的函数拥有DontDelete特性，无法被删除。</p>
<pre>var x = 36;
delete x;
x;     // 36, x没有被删除

y = 12;
delete y;
y;     // undefined

function foo() { return 42; }
delete foo;
foo();  // 42</pre>
<p>但是有一点例外，就是通过 eval 执行的代码中，通过var声明的变量虽然与正常的var声明变量同属于Global对象，但它们不具有DontDelete特性，能被删除。</p>
<pre name="code" class="js">eval("var x = 36;");
x;     // 42
delete x;
x;     // undefined</pre>
<p>但是这也有一点例外，eval的代码中的函数内通过var定义的变量具有DontDelete，不能被删除。</p>
<pre name="code" class="js">eval("(function() { var x = 42; delete x; return x; })();");
// 返回 42</pre>
<h2 id="content_2_5">delete的返回值</h2>
<p>delete是普通运算符，会返回true或false。规则为：当被delete的对象的属性存在并且拥有DontDelete时返回false，否则返回true。这里的一个特点就是，对象属性不存在时也返回true，所以返回值并非完全等同于删除成功与否。</p>
<pre name="code" class="js">function C() { this.x = 42; }
C.prototype.y = 12;
var o = new C();

delete o.x; // true
o.x;        // undefined
"x" in o;   // false
// o.x存在并且没有DontDelete，返回true

delete o.y; // true
o.y;        // 12
// o自身没有o.y属性，所以返回true
// 从这里也可以看到prototype链的存在，对象自身属性和prototype属性是不同的

delete o;   // false
// Global.o拥有DontDelete特性所以返回false

delete undefinedProperty;  // true
// Global没有名为undefinedProperty的属性因此返回true

delete 42;  // true
// 42不是属性所以返回true。有的实现会抛出异常（违反ECMAScript标准）

var x = 24;
delete x++;  // true
x;           // 25
// 被删除的是x++的返回值(24)，不是属性，所以返回true</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.zfkun.com/blog/index.php/archives/112/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Understanding and Solving Internet Explorer Leak Patterns</title>
		<link>http://www.zfkun.com/blog/index.php/archives/109</link>
		<comments>http://www.zfkun.com/blog/index.php/archives/109#comments</comments>
		<pubDate>Sun, 28 Feb 2010 06:01:57 +0000</pubDate>
		<dc:creator>影之迷惑</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[closure]]></category>
		<category><![CDATA[dom]]></category>
		<category><![CDATA[gc]]></category>
		<category><![CDATA[ie]]></category>
		<category><![CDATA[js]]></category>
		<category><![CDATA[leak]]></category>
		<category><![CDATA[memory]]></category>
		<category><![CDATA[reference]]></category>

		<guid isPermaLink="false">http://www.zfkun.com/blog/?p=109</guid>
		<description><![CDATA[In the past, memory leaks haven't posed huge problems for Web developers. Pages were kept relatively simple and navigation between different locations within a site was a great way to clean up any loose memory. If there was a leak, it was most likely small enough to go unnoticed.

New Web applications live up to higher standards. A page might run for hours without being navigated and retrieve updated information dynamically through Web services. Language features are pushed to the breaking point by combining complex event schemes, object-oriented JScript, and closures to produce entire applications. With these and other changes, certain memory leak patterns are becoming more prominent, especially those previously hidden by navigation.

The good news is that memory leak patterns can be easily spotted if you know what to look for. Most of the troublesome patterns you might face have known workarounds requiring only a small amount of extra work on your behalf. While some pages might still fall prey to small memory leaks, the most noticeable ones can be easily removed.]]></description>
			<content:encoded><![CDATA[<h2><strong>Understanding and Solving Internet Explorer Leak Patterns</strong></h2>
<p><!--Content type: PSDK_3. Transform: webcollection2mtps.xslt.--><a id="ie_leakpattern"><!----></a></p>
<p>Justin Rogers<br />
Microsoft Corporation</p>
<p>June 2005</p>
<h2>The Evolution of the Web Developer</h2>
<p>In the past, memory leaks haven&#8217;t posed huge problems for Web developers. Pages were kept relatively simple and navigation between different locations within a site was a great way to clean up any loose memory. If there was a leak, it was most likely small enough to go unnoticed.</p>
<p>New Web applications live up to higher standards. A page might run for hours without being navigated and retrieve updated information dynamically through Web services. Language features are pushed to the breaking point by combining complex event schemes, object-oriented JScript, and closures to produce entire applications. With these and other changes, certain memory leak patterns are becoming more prominent, especially those previously hidden by navigation.</p>
<p>The good news is that memory leak patterns can be easily spotted if you know what to look for. Most of the troublesome patterns you might face have known workarounds requiring only a small amount of extra work on your behalf. While some pages might still fall prey to small memory leaks, the most noticeable ones can be easily removed.</p>
<h2>Leak Patterns</h2>
<p>The following sections will discuss patterns of memory leaks and point out some common examples of each pattern. One great example of a pattern is the closure feature of JScript, while another example is the use of closures in hooking events. If you&#8217;re familiar with the event hooking example, you might be able to find and fix many of your memory leaks, but other closure-related issues might go unnoticed.</p>
<p>Now, let&#8217;s look at the following patterns:</p>
<ol>
<li>Circular References—When mutual references are counted between Internet Explorer&#8217;s COM infrastructure and any scripting engine, objects can leak memory. This is the broadest pattern.</li>
<li>Closures—Closures are a specific form of circular reference that pose the largest pattern to existing Web application architectures. Closures are easy to spot because they rely on a specific language keyword and can be searched for generically.</li>
<li>Cross-Page Leaks—Cross-page leaks are often very small leaks of internal book-keeping objects as you move from site to site. We&#8217;ll examine the DOM Insertion Order issue, along with a workaround that shows how small changes to your code can prevent the creation of these book-keeping objects.</li>
<li>Pseudo-Leaks—These aren&#8217;t really leaks, but can be extremely annoying if you don&#8217;t understand where your memory is going. We&#8217;ll examine the script element rewriting and how it appears to leak quite a bit of memory, when it is really performing as required.</li>
</ol>
<h2>Circular References</h2>
<p>Circular references are the root of nearly every leak. Normally, script engines handle circular references through their garbage collectors, but certain unknowns can prevent their heuristics from working properly. The unknown in the case of IE would be the status of any DOM elements that a portion of script has access to. The basic principle would be as follows:</p>
<p><!--src=[ie_leak_patterns_fig01.gif]--><img src="http://i.msdn.microsoft.com/Bb250448.ie_leak_patterns_fig01(en-us,VS.85).gif" alt="Figure 1 Basic Circular Reference Pattern" /></p>
<p><strong>Figure 1. Basic Circular Reference Pattern</strong></p>
<p>The cause of the leak in this pattern is based on COM reference counting. The script engine objects will hold a reference to the DOM element and will be waiting for any outstanding references to be removed before cleaning up and releasing the DOM element pointer. In our case we have two references on the script engine object: the script engine scope, and the DOM element expando property. While terminating the script engine will release the first reference, the DOM element reference will never be released because it is waiting on the script engine object to release it! You might think it would be easy to detect this scenario and fix the problem, but in practice the basic case presented is only the tip of the iceberg. You could have circular references at the end of a 30 object chain and those would be much harder to detect.</p>
<p>If you are wondering what this pattern looks like in HTML, you can cause a leak by using a global script engine variable and a DOM element as shown.</p>
<pre><code>&lt;html&gt;
    &lt;head&gt;
        &lt;script language="JScript"&gt;

        var myGlobalObject;

        function SetupLeak()
        {
            // First set up the script scope to element reference
            myGlobalObject =
                document.getElementById("LeakedDiv");

            // Next set up the element to script scope reference
            document.getElementById("LeakedDiv").expandoProperty =
                myGlobalObject;
        }

        function BreakLeak()
        {
            document.getElementById("LeakedDiv").expandoProperty =
                null;
        }
        &lt;/script&gt;
    &lt;/head&gt;

    &lt;body onload="SetupLeak()" onunload="BreakLeak()"&gt;
        &lt;div id="LeakedDiv"&gt;&lt;/div&gt;
    &lt;/body&gt;
&lt;/html&gt;</code></pre>
<p>To break the leak pattern you can make use of explicit null assignments. By assigning null before the document unloads you are telling the script engine there is no longer an association between the element and the object inside the engine. It can now properly clean up references and will release the DOM element. In this case, you as the Web developer know more about the relationships between your objects than the script engine does.</p>
<p>While that is the basic pattern, it can be difficult to spot more complex scenarios. A common usage of object-oriented JScript is to extend DOM elements by encapsulating them inside of a JScript object. During the construction process, you generally pass in the DOM element you want to attach to and then store a reference to the DOM element on the newly constructed object while at the same time storing an instance of the newly constructed object on the DOM element. That way your application model always has access to everything it needs. The problem is this is a very explicit circular reference, but because it uses different language aspects it might go unnoticed. Breaking up this kind of pattern can become more complex, and you can use the same simple methods discussed earlier.</p>
<pre><code>&lt;html&gt;
    &lt;head&gt;
        &lt;script language="JScript"&gt;

        function Encapsulator(element)
        {
            // Set up our element
            this.elementReference = element;

            // Make our circular reference
            element.expandoProperty = this;
        }

        function SetupLeak()
        {
            // The leak happens all at once
            new Encapsulator(document.getElementById("LeakedDiv"));
        }

        function BreakLeak()
        {
            document.getElementById("LeakedDiv").expandoProperty =
                null;
        }
        &lt;/script&gt;
    &lt;/head&gt;

    &lt;body onload="SetupLeak()" onunload="BreakLeak()"&gt;
        &lt;div id="LeakedDiv"&gt;&lt;/div&gt;
    &lt;/body&gt;
&lt;/html&gt;
</code></pre>
<p>More complex solutions to this problem involve registration schemes to note which elements/properties need to be unhooked, having the peer element hook events so that it can clean up before the document unloads, but often you can run into additional leak patterns without actually fixing the problem.</p>
<h2>Closures</h2>
<p>Closures are very often responsible for leaks because they create circular references without the programmer being fully aware. It isn&#8217;t immediately obvious that parent function parameters and local variables will be frozen in time, referenced, and held until the closure itself is released. In fact this has become such a common programming tactic, and users have run into issues so often, there are quite a few resources already available. Because they detail some of the history behind closures as well as some of the specific instances of closure leaks we&#8217;ll check those out after applying the closure model to our circular reference diagram and figuring out where these extra references are coming from.</p>
<p><!--src=[ie_leak_patterns_fig02.gif]--><img src="http://i.msdn.microsoft.com/Bb250448.ie_leak_patterns_fig02(en-us,VS.85).gif" alt="Figure 2 Circular References with Closures" /></p>
<p><strong>Figure 2. Circular References with Closures</strong></p>
<p>With normal circular references there were two solid objects holding references to each other, but closures are different. Rather than make the references directly, they are made instead by importing information from their parent function&#8217;s scope. Normally, a function&#8217;s local variables and the parameters used when calling a function only exist for the lifetime of the function itself. With closures, these variables and parameters continue to have an outstanding reference as long as the closure is alive, and since closures can live beyond the lifetime of their parent function so can any of the locals and parameters in that function. In the example, Parameter 1 would normally be released as soon as the function call was over. Because we&#8217;ve added a closure, a second reference is made, and that second reference won&#8217;t be released until the closure is also released. If you happened to attach the closure to an event, then you would have to detach it from that event. If you happened to attach the closure to an expando then you would need to null that expando.</p>
<p>Closures are also created per call, so calling this function twice will create two individual closures, each holding references to the parameters passed in each time. Because of this transparent nature it is really easy to leak closures. The following example provides the most basic of leaks using closures:</p>
<pre><code>&lt;html&gt;
    &lt;head&gt;
        &lt;script language="JScript"&gt;

        function AttachEvents(element)
        {
            // This structure causes element to ref ClickEventHandler
            element.attachEvent("onclick", ClickEventHandler);

            function ClickEventHandler()
            {
                // This closure refs element
            }
        }

        function SetupLeak()
        {
            // The leak happens all at once
            AttachEvents(document.getElementById("LeakedDiv"));
        }

        function BreakLeak()
        {
        }
        &lt;/script&gt;
    &lt;/head\&gt;

    &lt;body onload="SetupLeak()" onunload="BreakLeak()"&gt;
        &lt;div id="LeakedDiv"&gt;&lt;/div&gt;
    &lt;/body&gt;
&lt;/html&gt;</code></pre>
<p>If you are wondering how to break this leak, it won&#8217;t be as easy as a normal circular reference. The &#8220;closure&#8221; can be viewed as a temporary object that exists in the function scope. Once the function exits, you lose reference to the closure itself, so what would you end up calling <strong>detachEvent</strong> with? One of the most interesting approaches to this problem was demonstrated on <a id="ctl00_MTCS_main_ctl03" onclick="javascript:Track('ctl00_MTCS_main_ctl00|ctl00_MTCS_main_ctl03',this);" href="http://spaces.msn.com/members/siteexperts/Blog/cns!1pNcL8JwTfkkjv4gg6LkVCpw!338.entry">MSN spaces thanks to Scott Isaacs</a>. The approach uses a second closure to additionally hook the window&#8217;s <strong>onUnload</strong> event, and because this closure has the same &#8220;scoped&#8221; objects it is able to detach the event, detach itself, and finish the clean up process. To make everything easily fit with our model we can also store the closure on an expando, detach it, and then null the expando, as in the following example.</p>
<pre><code>&lt;html&gt;
    &lt;head&gt;
        &lt;script language="JScript"&gt;

        function AttachEvents(element)
        {
            // In order to remove this we need to put
            // it somewhere. Creates another ref
            element.expandoClick = ClickEventHandler;

            // This structure causes element to ref ClickEventHandler
            element.attachEvent("onclick", element.expandoClick);

            function ClickEventHandler()
            {
                // This closure refs element
            }
        }

        function SetupLeak()
        {
            // The leak happens all at once
            AttachEvents(document.getElementById("LeakedDiv"));
        }

        function BreakLeak()
        {
            document.getElementById("LeakedDiv").detachEvent("onclick",
                document.getElementById("LeakedDiv").expandoClick);
            document.getElementById("LeakedDiv").expandoClick = null;
        }
        &lt;/script&gt;
    &lt;/head&gt;

    &lt;body onload="SetupLeak()" onunload="BreakLeak()"&gt;
        &lt;div id="LeakedDiv"&gt;&lt;/div&gt;
    &lt;/body&gt;
&lt;/html&gt;</code></pre>
<p>In a <a id="ctl00_MTCS_main_ctl04" onclick="javascript:Track('ctl00_MTCS_main_ctl00|ctl00_MTCS_main_ctl04',this);" href="http://support.microsoft.com/default.aspx?scid=KB;EN-US;830555">Knowledge Base article</a>, we actually recommend that you try not to use closures unless they are necessary. In the example, I&#8217;ve given we don&#8217;t need to use a closure as the event handler, instead we can move the closure to a global scope. When the closure becomes a function, it no longer inherits the parameters or local variables from its parent function so we don&#8217;t have to worry about closure-based circular references at all. Most code can be fixed by creating an architecture that doesn&#8217;t rely on closures where they aren&#8217;t necessary.</p>
<p>Finally, Eric Lippert, one of the developers of the scripting engines, has a <a id="ctl00_MTCS_main_ctl05" onclick="javascript:Track('ctl00_MTCS_main_ctl00|ctl00_MTCS_main_ctl05',this);" href="http://blogs.msdn.com/ericlippert/archive/2003/09/17/53028.aspx">great post on closures in general</a>. His final recommendations are also along the lines of only using closures when truly necessary. While his article doesn&#8217;t mention any of the workarounds for the closure pattern, hopefully we&#8217;ve covered enough examples here to get you started.</p>
<h2>Cross-Page Leaks</h2>
<p>Leaks that are based on order of insertion are almost always caused by the creation of intermediate objects that don&#8217;t get cleaned up properly. That is exactly the case when creating dynamic elements and then attaching them to the DOM. The basic pattern is attaching two dynamically created objects together temporarily which creates a scope from the child to the parent element. Later, when you attach this two-element tree to the primary tree, they both inherit the scope of the document and a temporary object is leaked. The following diagram shows two methods for attaching dynamically created elements to the tree. In the first model, attach each child element to its parent, and finally attach the entire subtree to the primary tree. This method can cause leaks through temporary objects if other conditions are met. In the second model, we attach elements into the primary tree working our way from top-level dynamically created element down through all of the children. Because each attachment inherits the scope of the primary document we never generate temporary scopes. This method is much better at avoiding potential memory leaks.</p>
<p><!--src=[ie_leak_patterns_fig03.gif]--><img src="http://i.msdn.microsoft.com/Bb250448.ie_leak_patterns_fig03(en-us,VS.85).gif" alt="Figure 3 DOM Insertion Order Leak Model" /></p>
<p><strong>Figure 3. DOM Insertion Order Leak Model</strong></p>
<p>Next, we are going to cover an example of a leak that is transparent to most leak-detection algorithms. Because we don&#8217;t leak any publicly visible elements and the objects we leak are very small you might never notice this problem. For our example to work, the dynamically created elements will have to contain a script pointer in the form of an inline function. This will allow us to leak an internal script object that is created temporarily as we attach elements together. Because the leak is small, we&#8217;ll have to run thousands of samples. In fact, the objects leaked are only a few bytes. By running the sample and navigating to an empty page, you can see the difference in memory consumption between the two versions. When we use the first DOM model of attaching child to parent, then parent to the primary tree, our memory usage goes up a bit. This is a cross-navigation leak and the memory isn&#8217;t reclaimed until you restart the IE process. If you run the sample a few more times, using the second DOM model of attaching the parent to the primary tree and then the child to the parent, your memory won&#8217;t continue to climb and you&#8217;ll find that you&#8217;ve fixed the cross-page navigation leak.</p>
<pre><code>&lt;html&gt;
    &lt;head&gt;
        &lt;script language="JScript"&gt;

        function LeakMemory()
        {
            var hostElement = document.getElementById("hostElement");

            // Do it a lot, look at Task Manager for memory response

            for(i = 0; i &lt; 5000; i++)
            {
                var parentDiv =
                    document.createElement("&lt;div onClick='foo()'&gt;");
                var childDiv =
                    document.createElement("&lt;div onClick='foo()'&gt;");

                // This will leak a temporary object
                parentDiv.appendChild(childDiv);
                hostElement.appendChild(parentDiv);
                hostElement.removeChild(parentDiv);
                parentDiv.removeChild(childDiv);
                parentDiv = null;
                childDiv = null;
            }
            hostElement = null;
        }

        function CleanMemory()
        {
            var hostElement = document.getElementById("hostElement");

            // Do it a lot, look at Task Manager for memory response

            for(i = 0; i &lt; 5000; i++)
            {
                var parentDiv =
                    document.createElement("&lt;div onClick='foo()'&gt;");
                var childDiv =
                    document.createElement("&lt;div onClick='foo()'&gt;");

                // Changing the order is important, this won't leak
                hostElement.appendChild(parentDiv);
                parentDiv.appendChild(childDiv);
                hostElement.removeChild(parentDiv);
                parentDiv.removeChild(childDiv);
                parentDiv = null;
                childDiv = null;
            }
            hostElement = null;
        }
        &lt;/script&gt;
    &lt;/head&gt;

    &lt;body&gt;
        &lt;button onclick="LeakMemory()"&gt;Memory Leaking Insert&lt;/button&gt;
        &lt;button onclick="CleanMemory()"&gt;Clean Insert&lt;/button&gt;
        &lt;div id="hostElement"&gt;&lt;/div&gt;
    &lt;/body&gt;
&lt;/html&gt;</code></pre>
<p>This leak deserves clarification, because our workaround goes against some best practices in IE. The key points to understand about the leak are that DOM elements are being created with scripts already attached. This is actually crucial to the leak, because if we create DOM elements that don&#8217;t contain any script and attach them together in the same manner we don&#8217;t have a leak problem. This gives rise to a second workaround that might be even better for larger subtrees (in the example we only have two elements, so building the tree off the primary DOM isn&#8217;t a performance hit). The second workaround would be to create your elements with no scripts attached initially so that you can safely build your subtree. After you&#8217;ve attached your subtree to the primary DOM, go back and wire up any script events at that point. Remember to follow the principles for circular references and closures so you don&#8217;t cause a different leak in your code as you hook up your events.</p>
<p>I really wanted to point out this issue because it shows that not all memory leaks are easy to find. It could take thousands of iterations of a smaller pattern to become visible, and it might be something slight, like the order of insertion of DOM elements that causes the problem to arise. If you tend to program using only best practices, then you think you are safe, but this leak shows that even best practices can exhibit leaks. Our solution here was to improve upon the best practice or even introduce a new best practice in order to remove the leaking condition.</p>
<h2>Pseudo-Leaks</h2>
<p>Often times the actual behavior and expected behavior of some APIs can lead you to misdiagnose memory leaks. Pseudo-leaks almost always appear on the same page during dynamic scripting operations and should rarely be visible after navigation away from the page to a blank page. That is how you can eliminate the issue as a cross-page leak and then start to work on whether the memory consumption is expected. We&#8217;ll use script text rewriting as our example of a pseudo-leak.</p>
<p>Like the DOM Insertion Order issue, this issue also relies on the creation of temporary objects in order to &#8220;leak&#8221; memory. By rewriting the script text inside of a script element over and over again, slowly you&#8217;ll begin to leak various script engine objects that were attached to the previous contents. In particular, objects related to debugging script are left behind as are fully formed code elements.</p>
<pre><code>&lt;html&gt;
    &lt;head&gt;
        &lt;script language="JScript"&gt;

        function LeakMemory()
        {
            // Do it a lot, look at Task Manager for memory response

            for(i = 0; i &lt; 5000; i++)
            {
                hostElement.text = "function foo() { }";
            }
        }
        &lt;/script&gt;
    &lt;/head&gt;

    &lt;body&gt;
        &lt;button onclick="LeakMemory()"&gt;Memory Leaking Insert&lt;/button&gt;
        &lt;script id="hostElement"&gt;function foo() { }&lt;/script&gt;
    &lt;/body&gt;
&lt;/html&gt;</code></pre>
<p>If you run the above code and use the Task Manager trick again, while navigating between the &#8220;leaking&#8221; page and a blank page, you won&#8217;t notice a script leak. This script leak is entirely within a page and when you navigate away then you get your memory back. The reason this one is bad is due to expected behavior. You expect that after rewriting some script that the original script won&#8217;t stay around. But it really has to, because it might have been used already for event attachments and there might be outstanding reference counts. As you can see, this is a pseudo-leak. On the surface the amount of memory consumption looks really bad, but there is a completely valid reason.</p>
<h2>Conclusion</h2>
<p>Every Web developer builds a personal list of code examples that they know leak and learns to work around those leaks when they see them in code. This is extremely handy and is the reason the Web is relatively leak-free today. Thinking about the leaks in terms of patterns instead of individual code examples, you can start to develop even better strategies for dealing with them. The idea is to take them into account during the design phase and make sure you have plans for any potential leaks. Use defensive coding practices and assume that you&#8217;ll need to clean up all your own memory. While this is an overstatement of the problem, you very rarely need to clean up your own memory; it becomes obvious which variables and expando properties have the potential for leaking.</p>
<p>In the interest of patterns and design I highly recommend <a id="ctl00_MTCS_main_ctl07" onclick="javascript:Track('ctl00_MTCS_main_ctl00|ctl00_MTCS_main_ctl07',this);" href="http://spaces.msn.com/members/siteexperts/Blog/cns!1pNcL8JwTfkkjv4gg6LkVCpw!338.entry">Scott&#8217;s short blog entry</a> because it demonstrates a general purpose example of removing all closure-based leaks. It does require a bit more code, but the practice is sound and the improved pattern is easy to spot in code and to debug. Similar registration schemes can be used for expando-based circular references as long as care is taken that the registration method itself isn&#8217;t riddled with leaks (especially where closures are used)!</p>
<p><!----></p>
<p><!----></p>
<p><strong>About the author</strong></p>
<p><strong>Justin Rogers</strong> recently joined the Internet Explorer team as an Object Model developer working on extensibility and previously worked on such notable projects as the .NET QuickStart Tutorials, .NET Terrarium, and SQL Reporting Services Management Studio in SQL Server 2005.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.zfkun.com/blog/index.php/archives/109/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>结婚了</title>
		<link>http://www.zfkun.com/blog/index.php/archives/107</link>
		<comments>http://www.zfkun.com/blog/index.php/archives/107#comments</comments>
		<pubDate>Tue, 23 Feb 2010 10:20:04 +0000</pubDate>
		<dc:creator>影之迷惑</dc:creator>
				<category><![CDATA[Life]]></category>
		<category><![CDATA[marry]]></category>
		<category><![CDATA[结婚]]></category>

		<guid isPermaLink="false">http://www.zfkun.com/blog/?p=107</guid>
		<description><![CDATA[结婚了 ，有情人终是要成眷属的。
]]></description>
			<content:encoded><![CDATA[<p>结婚了 ，有情人终是要成眷属的。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.zfkun.com/blog/index.php/archives/107/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>好累</title>
		<link>http://www.zfkun.com/blog/index.php/archives/104</link>
		<comments>http://www.zfkun.com/blog/index.php/archives/104#comments</comments>
		<pubDate>Sat, 30 Jan 2010 07:57:52 +0000</pubDate>
		<dc:creator>影之迷惑</dc:creator>
				<category><![CDATA[Essay]]></category>
		<category><![CDATA[压力]]></category>
		<category><![CDATA[希望]]></category>
		<category><![CDATA[累]]></category>

		<guid isPermaLink="false">http://www.zfkun.com/blog/?p=104</guid>
		<description><![CDATA[太久了，
没安稳的睡过，烦躁、犹豫、无奈、恐惧。
凌乱的压力压的我透不过气，咬牙。
不求可怜、不求同情、也不求理解。
只相信，
最终，
做到想做的、得到想要的、给予能给的、看到想看的……
好累。
]]></description>
			<content:encoded><![CDATA[<p>太久了，</p>
<p>没安稳的睡过，烦躁、犹豫、无奈、恐惧。</p>
<p>凌乱的压力压的我透不过气，咬牙。</p>
<p>不求可怜、不求同情、也不求理解。</p>
<p>只相信，</p>
<p>最终，</p>
<p>做到想做的、得到想要的、给予能给的、看到想看的……</p>
<p>好累。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.zfkun.com/blog/index.php/archives/104/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Windows 下 Nginx + PHP5 的安装与配置</title>
		<link>http://www.zfkun.com/blog/index.php/archives/102</link>
		<comments>http://www.zfkun.com/blog/index.php/archives/102#comments</comments>
		<pubDate>Thu, 28 Jan 2010 15:26:33 +0000</pubDate>
		<dc:creator>影之迷惑</dc:creator>
				<category><![CDATA[Develop]]></category>
		<category><![CDATA[nginx]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[windows]]></category>

		<guid isPermaLink="false">http://www.zfkun.com/blog/?p=102</guid>
		<description><![CDATA[Nginx 是一个轻量级的高性能 Http WebServer，以事件驱动方式编写，因此相比 Apache 而言，Nginx 更加稳定、性能更好，而且配置简单，资源占用较低。以下是在 Windows 7 安装中 Nginx 和 PHP5.3 的步骤。]]></description>
			<content:encoded><![CDATA[<p>Nginx 是一个轻量级的高性能 Http WebServer，以事件驱动方式编写，因此相比 Apache 而言，Nginx 更加稳定、性能更好，而且配置简单，资源占用较低。以下是在 Windows 7 安装中 Nginx 和 PHP5.3 的步骤。</p>
<p><strong>安装 PHP5<br />
</strong>首先，从 http://www.php.net/downloads.php 下载最新的 PHP 5.3 Windows 版本，解压至 C:\php5，把压缩包中的 php.ini-recommended，更名为 php.ini，然后打开修改几个选项：</p>
<p name="code" class="c">
error_reporting = E_ALL<br />
display_errors = On<br />
extension_dir = &#8220;C:\php5\ext&#8221;</p>
<p>; 动态扩展，可以根据需要去掉 extension 前面的注释 ;<br />
; 如加载 PDO, MySQL<br />
extension=php_pdo.dll<br />
extension=php_pdo_mysql.dll</p>
<p>; CGI 设置<br />
cgi.fix_pathinfo = 1
</p>
<p>PHP 加载扩展需要注意依赖性，比如 php_exif.dll 需要 php_mbstring.dll，你必须要把 php_mbstring.dll 放在 php_exif.dll 前面才能加载成功。有些扩展依赖额外的 dll 文件，如 PHP 5.0+ ，php_mysqli.dll 依赖 libmysql.dll，而 php_oci8.dll，你则需要安装 Oracle 8 的客户端。如果你对这些依赖性不是太了解，可以参考一下安装包中的 install.txt 文件。</p>
<p>依赖文件的搜索顺序：首先是 php.exe 所在的目录，如果是 ISAPI 模式，那么会搜索 Web Server 的启动位置，比如 Apache 的 bin 目录；其次是 Windows PATH 环境变量中的目录。这里不要复制任何文件到 Windows 目录中，有必要的话，可以把 C:\php5 加到 PATH 中，便于以后 PHP 的升级。</p>
<p><strong>安装 Nginx</strong><br />
从 v0.7.52 开始，Nginx 开始发布 Windows 版本的 Nginx，你可以在其官方网站上面下载：</p>
<p>http://nginx.net</p>
<p>如果需要老版本的 Nginx for Windows，可以在 Kevin Worthington 的网站上面找找。</p>
<p>我使用的是 0.8.29，下载好以后，解压释放文件到 C:\nginx。</p>
<p>那么如何配置 Nginx，使其可以和 PHP 协同工作？</p>
<p><strong>配置 PHP FastCGI<br />
</strong>Nginx 需要和 FastCGI Server 配合才能处理请求，有两种方式运行 PHP FastCGI Server，一种就是使用 PHP 内置的 FastCGI 管理器：</p>
<p name="code" class="c">
C:/php5/php-cgi.exe -b 127.0.0.1:9000 -c C:/php5/php.ini
</p>
<p>另外一种方式是使用第三方工具，比如 PHP-FPM 、cgi-fcgi 等。显然！要在 Windows 中使用这些工具是件极其痛苦的事情，你可能需要 Cygwin 之类的东西才行，的确有人这么做了，虽然我觉得那是自寻烦恼。</p>
<p>下一步，修改 Nginx ，将 php 请求转发至 PHP FastCGI Server：</p>
<p name="code" class="c">
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000<br />
location ~ ^(.+\.php)(.*)$ {<br />
root D:/public_html;<br />
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;<br />
include php.conf;<br />
}
</p>
<p>root 也就是 $document_root 指的是你的 php scripts 根目录，设置为你的网站根目录。在 Windows 下，需要注意的是 root 的路径，最好使用 &#8220;/&#8221; 作为路径分隔符，而不是 Windows 默认的 &#8220;\&#8221;，否则容易出问题，比如，这个路径：D:\public_html\test，就不会起作用，Nginx 会抛出 500 错误，原因是 \test 中 \t 被解析为制表符。当然再加上一个反斜杠转义也是可以的，如：D:\\public_html\\test。</p>
<p>php.conf 配置文件：</p>
<p name="code" class="c">
# 连接到本机 9000 端口，这里的端口是指 PHP FastCGI Server 开启的端口，<br />
# 请与 php-cgi.exe 开启的端口保持一致<br />
# 当 Nginx 收到 php 文件的请求时，会自动转发到 PHP FastCGI Server<br />
fastcgi_pass 127.0.0.1:9000;<br />
fastcgi_index index.php;</p>
<p># Nginx 默认是不支持 CGI PATH_INFO，SCRIPT_NAME 的值也不标准（糅合了 PATH_INFO）<br />
# 下面的两行指令，可以从 SCRIPT_NAME 中剥离出 PATH_INFO<br />
fastcgi_split_path_info ^(.+\.php)(.*)$;<br />
fastcgi_param PATH_INFO $fastcgi_path_info;</p>
<p>include fastcgi_params;
</p>
<p>创建一个独立的 php.conf 保存配置，纯粹是为了精简 nginx.conf，个人习惯而已，也可以全部写在主配置文件中。</p>
<p>修改 php.ini，设置 cgi.fix_pathinfo = 1，这非常重要，PHP 会修正 SCRIPT_FILENAME 为真实的文件地址，否则 PHP 将无法找到需要处理的 php 文件。</p>
<p>一些其他的设置，主服务器：</p>
<p name="code" class="c">
# 默认开启的进程数<br />
worker_processes 1;</p>
<p>error_log logs/error.log;<br />
#error_log logs/error.log notice;<br />
#error_log logs/error.log info;</p>
<p>#pid logs/nginx.pid;</p>
<p>events {<br />
# 一个进程所处理的最大连接数上限，<br />
# 本地开发，不需要默认的 1024，这里改为 64<br />
worker_connections 64;<br />
}
</p>
<p>当某个目录下面不存在默认 index.php index.html 等首页文件时，Nginx 会抛出 403 ERROR，如果你需要罗列此目录，则可以在 http {… } 中加入如下命令：</p>
<p name="code" class="c">
autoindex on;<br />
autoindex_exact_size on;<br />
autoindex_localtime on;
</p>
<p><strong>OK，整合到一起</strong><br />
创建 start_nginx.bat，用于同时启动 PHP FastCGI 和 Nginx：</p>
<p name="code" class="c">
@echo off<br />
REM Windows 下无效<br />
REM set PHP_FCGI_CHILDREN=5</p>
<p>REM 每个进程处理的最大请求数，或设置为 Windows 环境变量<br />
set PHP_FCGI_MAX_REQUESTS=1000</p>
<p>echo Starting PHP FastCGI&#8230;<br />
RunHiddenConsole C:/php5/php-cgi.exe -b 127.0.0.1:9000 -c C:/php5/php.ini</p>
<p>echo Starting nginx&#8230;<br />
C:/nginx/nginx.exe
</p>
<p>RunHiddenConsole.exe 是一个用来隐藏 DOS 窗口的小程序，可以在这里下载。<br />
start_nginx.bat 开启后，也会有 DOS 窗口，但是可以安全的关掉，并不会关闭 Nginx 和 php-cgi.exe。</p>
<p>同样 stop_nginx.bat，用来关闭：</p>
<p name="code" class="c">
@echo off<br />
echo Stopping nginx&#8230;<br />
taskkill /F /IM nginx.exe &gt; nul<br />
echo Stopping PHP FastCGI&#8230;<br />
taskkill /F /IM php-cgi.exe &gt; nul<br />
exit
</p>
<p>到这里基本配置完毕了。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.zfkun.com/blog/index.php/archives/102/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Nginx 0.8.x + PHP 5.2.10（FastCGI）搭建胜过Apache十倍的Web服务器（第5版）</title>
		<link>http://www.zfkun.com/blog/index.php/archives/95</link>
		<comments>http://www.zfkun.com/blog/index.php/archives/95#comments</comments>
		<pubDate>Wed, 27 Jan 2010 16:40:35 +0000</pubDate>
		<dc:creator>影之迷惑</dc:creator>
				<category><![CDATA[Develop]]></category>
		<category><![CDATA[apache]]></category>
		<category><![CDATA[apc]]></category>
		<category><![CDATA[centos]]></category>
		<category><![CDATA[epoll]]></category>
		<category><![CDATA[html]]></category>
		<category><![CDATA[http]]></category>
		<category><![CDATA[httpd]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[memcache]]></category>
		<category><![CDATA[memcached]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[nginx]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[xcache]]></category>

		<guid isPermaLink="false">http://www.zfkun.com/blog/?p=95</guid>
		<description><![CDATA[本文是张宴撰写的关于搭建“Nginx + PHP（FastCGI）”Web服务器的第5篇文章。本系列文章作为国内最早详细介绍 Nginx + PHP 安装、配置、使用的资料之一，为推动 Nginx 在国内的发展产生了积极的作用。这是一篇关于Nginx 0.7.x系列版本的文章，安装、配置方式与第4篇文章相差不大，但增加了MySQL安装配置的信息、PHP 5.2.10 的 php-fpm 补丁。Nginx 0.7.x系列版本虽然为开发版，但在很多大型网站的生产环境中已经使用。]]></description>
			<content:encoded><![CDATA[<p>[文章作者：张宴 本文版本：v5.5 最后修改：2009.09.18 原文链接：<a href="http://blog.s135.com/nginx_php_v5/" target="_blank">http://blog.s135.com/nginx_php_v5/</a>]</p>
<p>前言：本文是我撰写的关于搭建“Nginx + PHP（FastCGI）”Web服务器的第5篇文章。本系列文章作为国内最早详细介绍 Nginx + PHP 安装、配置、使用的资料之一，为推动 Nginx 在国内的发展产生了积极的作用。这是一篇关于Nginx 0.7.x系列版本的文章，安装、配置方式与第4篇文章相差不大，但增加了MySQL安装配置的信息、<strong>PHP 5.2.10 的 php-fpm 补丁</strong>。Nginx 0.7.x系列版本虽然为开发版，但在很多大型网站的生产环境中已经使用。</p>
<p>链接：《<a href="post/297/" target="_blank">2007年9月的第1版</a>》、《<a href="post/314/" target="_blank">2007年12月的第2版</a>》、《<a href="post/351/" target="_blank">2008年6月的第3版</a>》、《<a href="nginx_php_v4/" target="_blank">2008年8月的第4版</a>》</p>
<p><a href="http://blog.s135.com/attachment/200806/nginx.png" target="_blank"><img title="点击在新窗口中浏览此图片" src="http://blog.s135.com/attachment/200806/nginx.png" border="0" alt="点击在新窗口中浏览此图片" /></a></p>
<p><a href="http://www.nginx.net/" target="_blank">Nginx</a> (&#8220;engine x&#8221;) 是一个高性能的 HTTP 和反向代理服务器，也是一个 IMAP/POP3/SMTP 代理服务器。 Nginx 是由 Igor Sysoev 为俄罗斯访问量第二的 Rambler.ru 站点开发的，它已经在该站点运行超过两年半了。Igor 将源代码以类BSD许可证的形式发布。</p>
<p>Nginx 超越 Apache 的高性能和稳定性，使得国内使用 Nginx 作为 Web 服务器的网站也越来越多，其中包括<a href="http://blog.sina.com.cn/" target="_blank">新浪博客</a>、<a href="http://v.sina.com.cn/" target="_blank">新浪播客</a>、<a href="http://news.163.com/" target="_blank">网易新闻</a>等门户网站频道，<a href="http://www.6.cn/" target="_blank">六间房</a>、<a href="http://www.56.com/" target="_blank">56.com</a>等视频分享网站，<a href="http://www.discuz.net/" target="_blank">Discuz!官方论坛</a>、<a href="http://www.newsmth.net/" target="_blank">水木社区</a>等知名论坛，<a href="http://www.douban.com/" target="_blank">豆瓣</a>、<a href="http://www.yupoo.com/" target="_blank">YUPOO相册</a>、<a href="http://www.hainei.com/" target="_blank">海内SNS</a>、<a href="http://www.xunlei.com/" target="_blank">迅雷在线</a>等新兴Web 2.0网站。</p>
<p>Nginx 的官方中文维基：<a href="http://wiki.nginx.org/NginxChs" target="_blank">http://wiki.nginx.org/NginxChs</a></p>
<p>在高并发连接的情况下，Nginx是Apache服务器不错的替代品。Nginx同时也可以作为7层负载均衡服务器来使用。根据我的测试结果，<strong>Nginx 0.8.15 + PHP 5.2.10 (FastCGI) 可以承受3万以上的并发连接数，相当于同等环境下Apache的10倍</strong>。</p>
<p>根据我的经验，4GB内存的服务器+Apache（prefork模式）一般只能处理3000个并发连接，因为它们将占用3GB以上的内存，还得为系统预留1GB的内存。我曾经就有两台Apache服务器，因为在配置文件中设置的MaxClients为4000，当Apache并发连接数达到3800时，导致服务器内存和Swap空间用满而崩溃。</p>
<p>而这台 Nginx 0.8.15 + PHP 5.2.10 (FastCGI) 服务器在3万并发连接下，开启的10个Nginx进程消耗150M内存（15M*10=150M），开启的64个php-cgi进程消耗1280M内存（20M*64=1280M），加上系统自身消耗的内存，总共消耗不到2GB内存。如果服务器内存较小，完全可以只开启25个php-cgi进程，这样php-cgi消耗的总内存数才500M。</p>
<p>在3万并发连接下，访问Nginx 0.8.15 + PHP 5.2.10 (FastCGI) 服务器的PHP程序，仍然速度飞快。下图为Nginx的状态监控页面，显示的活动连接数为28457（关于Nginx的监控页配置，会在本文接下来所给出的Nginx配置文件中写明）：</p>
<p><a href="http://blog.s135.com/attachment/200712/nginx_status.png" target="_blank"><img title="点击在新窗口中浏览此图片" src="http://blog.s135.com/attachment/200712/nginx_status.png" border="0" alt="点击在新窗口中浏览此图片" /></a></p>
<p>我生产环境下的两台Nginx + PHP5（FastCGI）服务器，跑多个一般复杂的纯PHP动态程序，单台Nginx + PHP5（FastCGI）服务器跑PHP动态程序的处理能力已经超过“700次请求/秒”，相当于每天可以承受6000万（700*60*60*24=60480000）的访问量（<a href="read.php/334.htm" target="_blank">更多信息见此</a>），而服务器的系统负载也不高：</p>
<p><a href="http://blog.s135.com/attachment/200803/nginx_php_la.gif" target="_blank"><img title="点击在新窗口中浏览此图片" src="http://blog.s135.com/attachment/200803/nginx_php_la.gif" border="0" alt="点击在新窗口中浏览此图片" /></a></p>
<p>2009年9月3日下午2：30，金山游戏《剑侠情缘网络版叁》临时维护1小时（<a href="http://kefu.xoyo.com/gonggao/jx3/2009-09-03/750438.shtml" target="_blank">http://kefu.xoyo.com/gonggao/jx3/2009-09-03/750438.shtml</a>），大量玩家上官网，论坛、评论、客服等动态应用Nginx服务器集群，每台服务器的Nginx活动连接数达到2.8万，这是笔者遇到的Nginx生产环境最高并发值。</p>
<p><a href="http://blog.s135.com/attachment/200909/nginx_c30k.png" target="_blank"><img title="点击在新窗口中浏览此图片" src="http://blog.s135.com/attachment/200909/nginx_c30k.png" border="0" alt="点击在新窗口中浏览此图片" /></a></p>
<hr />
下面是用100个并发连接分别去压生产环境中同一负载均衡器VIP下、提供相同服务的两台服务器，一台为Nginx，另一台为Apache，Nginx每秒处理的请求数是Apache的两倍多，Nginx服务器的系统负载、CPU使用率远低于Apache：</p>
<p>你可以将连接数开到10000～30000，去压Nginx和Apache上的phpinfo.php，这是用浏览器访问Nginx上的phpinfo.php一切正常，而访问Apache服务器的phpinfo.php，则是该页无法显示。4G内存的服务器，即使再优化，Apache也很难在“webbench -c 30000 -t 60 http://xxx.xxx.xxx.xxx/phpinfo.php”的压力情况下正常访问，而调整参数优化后的Nginx可以。</p>
<p>webbench 下载地址：<a href="http://blog.s135.com/post/288/" target="_blank">http://blog.s135.com/post/288/</a></p>
<p>注意：webbench 做压力测试时，该软件自身也会消耗CPU和内存资源，为了测试准确，请将 webbench 安装在别的服务器上。</p>
<p>测试结果：##### Nginx + PHP #####</p>
<p name="code" class="c">[root@localhost webbench-1.5]# webbench -c 100 -t 30 http://192.168.1.21/phpinfo.php<br />
Webbench &#8211; Simple Web Benchmark 1.5<br />
Copyright (c) Radim Kolar 1997-2004, GPL Open Source Software.</p>
<p>Benchmarking: GET http://192.168.1.21/phpinfo.php<br />
100 clients, running 30 sec.</p>
<p>Speed=102450 pages/min, 16490596 bytes/sec.<br />
Requests: 51225 susceed, 0 failed.</p>
<p>top &#8211; 14:06:13 up 27 days,  2:25,  2 users,  load average: 14.57, 9.89, 6.51<br />
Tasks: 287 total,   4 running, 283 sleeping,   0 stopped,   0 zombie<br />
Cpu(s): 49.9% us,  6.7% sy,  0.0% ni, 41.4% id,  1.1% wa,  0.1% hi,  0.8% si<br />
Mem:   6230016k total,  2959468k used,  3270548k free,   635992k buffers<br />
Swap:  2031608k total,     3696k used,  2027912k free,  1231444k cached
</p>
<p>测试结果：#####  Apache + PHP #####</p>
<p name="code" class="c">
[root@localhost webbench-1.5]# webbench -c 100 -t 30 http://192.168.1.27/phpinfo.php<br />
Webbench &#8211; Simple Web Benchmark 1.5<br />
Copyright (c) Radim Kolar 1997-2004, GPL Open Source Software.</p>
<p>Benchmarking: GET http://192.168.1.27/phpinfo.php<br />
100 clients, running 30 sec.</p>
<p>Speed=42184 pages/min, 31512914 bytes/sec.<br />
Requests: 21092 susceed, 0 failed.</p>
<p>top &#8211; 14:06:20 up 27 days,  2:13,  2 users,  load average: 62.15, 26.36, 13.42<br />
Tasks: 318 total,   7 running, 310 sleeping,   0 stopped,   1 zombie<br />
Cpu(s): 80.4% us, 10.6% sy,  0.0% ni,  7.9% id,  0.1% wa,  0.1% hi,  0.9% si<br />
Mem:   6230016k total,  3075948k used,  3154068k free,   379896k buffers<br />
Swap:  2031608k total,    12592k used,  2019016k free,  1117868k cached
</p>
<p>为什么Nginx的性能要比Apache高得多？这得益于Nginx使用了最新的epoll（Linux 2.6内核）和kqueue（freebsd）网络I/O模型，而Apache则使用的是传统的select模型。目前Linux下能够承受高并发访问的Squid、Memcached都采用的是epoll网络I/O模型。</p>
<p>处理大量的连接的读写，Apache所采用的select网络I/O模型非常低效。下面用一个比喻来解析Apache采用的select模型和Nginx采用的epoll模型进行之间的区别：</p>
<p>假设你在大学读书，住的宿舍楼有很多间房间，你的朋友要来找你。select版宿管大妈就会带着你的朋友挨个房间去找，直到找到你为止。而epoll版宿管大妈会先记下每位同学的房间号，你的朋友来时，只需告诉你的朋友你住在哪个房间即可，不用亲自带着你的朋友满大楼找人。如果来了10000个人，都要找自己住这栋楼的同学时，select版和epoll版宿管大妈，谁的效率更高，不言自明。同理，在高并发服务器中，轮询I/O是最耗时间的操作之一，select和epoll的性能谁的性能更高，同样十分明了。</p>
<p>安装步骤：<br />
（系统要求：Linux 2.6+ 内核，本文中的Linux操作系统为CentOS 5.3，另在RedHat AS4上也安装成功）<br />
<strong>一、获取相关开源程序：</strong><br />
1、【适用CentOS操作系统】利用CentOS Linux系统自带的yum命令安装、升级所需的程序库（RedHat等其他Linux发行版可从安装光盘中找到这些程序库的RPM包，进行安装）：</p>
<p name="code" class="c">sudo -s<br />
LANG=C<br />
yum -y install gcc gcc-c++ autoconf libjpeg libjpeg-devel libpng libpng-devel freetype freetype-devel libxml2 libxml2-devel zlib zlib-devel glibc glibc-devel glib2 glib2-devel bzip2 bzip2-devel ncurses ncurses-devel curl curl-devel e2fsprogs e2fsprogs-devel krb5 krb5-devel libidn libidn-devel openssl openssl-devel openldap openldap-devel nss_ldap openldap-clients openldap-servers</p>
<p>2、【适用RedHat操作系统】RedHat等其他Linux发行版可从安装光盘中找到这些程序库的RPM包（事先可通过类似“rpm -qa | grep libjpeg”的命令查看所需的RPM包是否存在，通常是“xxx-devel”不存在，需要安装）。RedHat可以直接利用CentOS的RPM包安装，以下是RPM包下载网址：<br />
①、RedHat AS4 &amp; CentOS 4<br />
<a href="http://mirrors.163.com/centos/4/os/i386/CentOS/RPMS/" target="_blank">http://mirrors.163.com/centos/4/os/i386/CentOS/RPMS/</a><br />
<a href="http://mirrors.163.com/centos/4/os/x86_64/CentOS/RPMS/" target="_blank">http://mirrors.163.com/centos/4/os/x86_64/CentOS/RPMS/</a></p>
<p>②、RedHat AS5 &amp; CentOS 5<br />
<a href="http://mirrors.163.com/centos/5/os/i386/CentOS/" target="_blank">http://mirrors.163.com/centos/5/os/i386/CentOS/</a><br />
<a href="http://mirrors.163.com/centos/5/os/x86_64/CentOS/" target="_blank">http://mirrors.163.com/centos/5/os/x86_64/CentOS/</a></p>
<p>③、RPM包搜索网站<br />
<a href="http://rpm.pbone.net/" target="_blank">http://rpm.pbone.net/</a><br />
<a href="http://www.rpmfind.net/" target="_blank">http://www.rpmfind.net/</a></p>
<p>④、RedHat AS4 系统环境，通常情况下缺少的支持包安装：<br />
Ⅰ、i386 系统</p>
<p name="code" class="c">wget http://blog.s135.com/soft/linux/nginx_php/rpm/i386/libjpeg-devel-6b-33.i386.rpm<br />
rpm -ivh libjpeg-devel-6b-33.i386.rpm<br />
wget http://blog.s135.com/soft/linux/nginx_php/rpm/i386/freetype-devel-2.1.9-1.i386.rpm<br />
rpm -ivh freetype-devel-2.1.9-1.i386.rpm<br />
wget http://blog.s135.com/soft/linux/nginx_php/rpm/i386/libpng-devel-1.2.7-1.i386.rpm<br />
rpm -ivh libpng-devel-1.2.7-1.i386.rpm</p>
<p>Ⅱ、x86_64 系统</p>
<p name="code" class="c">wget http://blog.s135.com/soft/linux/nginx_php/rpm/x86_64/libjpeg-devel-6b-33.x86_64.rpm<br />
rpm -ivh libjpeg-devel-6b-33.x86_64.rpm<br />
wget http://blog.s135.com/soft/linux/nginx_php/rpm/x86_64/freetype-devel-2.1.9-1.x86_64.rpm<br />
rpm -ivh freetype-devel-2.1.9-1.x86_64.rpm<br />
wget http://blog.s135.com/soft/linux/nginx_php/rpm/x86_64/libpng-devel-1.2.7-1.x86_64.rpm<br />
rpm -ivh libpng-devel-1.2.7-1.x86_64.rpm</p>
<p>3、【适用CentOS、RedHat及其它Linux操作系统】下载程序源码包：<br />
本文中提到的所有开源软件为截止到2009年09月18日的最新稳定版。<br />
①、从软件的官方网站下载：</p>
<p name="code" class="c">mkdir -p /data0/software<br />
cd /data0/software<br />
wget http://sysoev.ru/nginx/nginx-0.8.15.tar.gz<br />
wget http://www.php.net/get/php-5.2.10.tar.gz/from/this/mirror<br />
wget http://blog.s135.com/soft/linux/nginx_php/phpfpm/php-5.2.10-fpm-0.5.11.diff.gz<br />
wget http://dev.mysql.com/get/Downloads/MySQL-5.1/mysql-5.1.38.tar.gz/from/http://mysql.he.net/<br />
wget http://ftp.gnu.org/pub/gnu/libiconv/libiconv-1.13.tar.gz<br />
wget http://downloads.sourceforge.net/mcrypt/libmcrypt-2.5.8.tar.gz?modtime=1171868460&amp;big_mirror=0<br />
wget http://downloads.sourceforge.net/mcrypt/mcrypt-2.6.8.tar.gz?modtime=1194463373&amp;big_mirror=0<br />
wget http://pecl.php.net/get/memcache-2.2.5.tgz<br />
wget http://downloads.sourceforge.net/mhash/mhash-0.9.9.9.tar.gz?modtime=1175740843&amp;big_mirror=0<br />
wget ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre-7.9.tar.gz<br />
wget http://bart.eaccelerator.net/source/0.9.5.3/eaccelerator-0.9.5.3.tar.bz2<br />
wget http://pecl.php.net/get/PDO_MYSQL-1.0.2.tgz<br />
wget http://blog.s135.com/soft/linux/nginx_php/imagick/ImageMagick.tar.gz<br />
wget http://pecl.php.net/get/imagick-2.2.2.tgz</p>
<p>②、从blog.s135.com下载（比较稳定，只允许在本站，或者在Linux/Unix下通过Wget、Curl等命令下载以下软件）：</p>
<p name="code" class="c">mkdir -p /data0/software<br />
cd /data0/software<br />
wget http://blog.s135.com/soft/linux/nginx_php/nginx/nginx-0.8.15.tar.gz<br />
wget http://blog.s135.com/soft/linux/nginx_php/php/php-5.2.10.tar.gz<br />
wget http://blog.s135.com/soft/linux/nginx_php/phpfpm/php-5.2.10-fpm-0.5.11.diff.gz<br />
wget http://blog.s135.com/soft/linux/nginx_php/mysql/mysql-5.1.38.tar.gz<br />
wget http://blog.s135.com/soft/linux/nginx_php/libiconv/libiconv-1.13.tar.gz<br />
wget http://blog.s135.com/soft/linux/nginx_php/mcrypt/libmcrypt-2.5.8.tar.gz<br />
wget http://blog.s135.com/soft/linux/nginx_php/mcrypt/mcrypt-2.6.8.tar.gz<br />
wget http://blog.s135.com/soft/linux/nginx_php/memcache/memcache-2.2.5.tgz<br />
wget http://blog.s135.com/soft/linux/nginx_php/mhash/mhash-0.9.9.9.tar.gz<br />
wget http://blog.s135.com/soft/linux/nginx_php/pcre/pcre-7.9.tar.gz<br />
wget http://blog.s135.com/soft/linux/nginx_php/eaccelerator/eaccelerator-0.9.5.3.tar.bz2<br />
wget http://blog.s135.com/soft/linux/nginx_php/pdo/PDO_MYSQL-1.0.2.tgz<br />
wget http://blog.s135.com/soft/linux/nginx_php/imagick/ImageMagick.tar.gz<br />
wget http://blog.s135.com/soft/linux/nginx_php/imagick/imagick-2.2.2.tgz</p>
<p><strong>二、安装PHP 5.2.10（FastCGI模式）</strong><br />
1、编译安装PHP 5.2.10所需的支持库：</p>
<p name="code" class="c">tar zxvf libiconv-1.13.tar.gz<br />
cd libiconv-1.13/<br />
./configure &#8211;prefix=/usr/local<br />
make<br />
make install<br />
cd ../</p>
<p>tar zxvf libmcrypt-2.5.8.tar.gz<br />
cd libmcrypt-2.5.8/<br />
./configure<br />
make<br />
make install<br />
/sbin/ldconfig<br />
cd libltdl/<br />
./configure &#8211;enable-ltdl-install<br />
make<br />
make install<br />
cd ../../</p>
<p>tar zxvf mhash-0.9.9.9.tar.gz<br />
cd mhash-0.9.9.9/<br />
./configure<br />
make<br />
make install<br />
cd ../</p>
<p>ln -s /usr/local/lib/libmcrypt.la /usr/lib/libmcrypt.la<br />
ln -s /usr/local/lib/libmcrypt.so /usr/lib/libmcrypt.so<br />
ln -s /usr/local/lib/libmcrypt.so.4 /usr/lib/libmcrypt.so.4<br />
ln -s /usr/local/lib/libmcrypt.so.4.4.8 /usr/lib/libmcrypt.so.4.4.8<br />
ln -s /usr/local/lib/libmhash.a /usr/lib/libmhash.a<br />
ln -s /usr/local/lib/libmhash.la /usr/lib/libmhash.la<br />
ln -s /usr/local/lib/libmhash.so /usr/lib/libmhash.so<br />
ln -s /usr/local/lib/libmhash.so.2 /usr/lib/libmhash.so.2<br />
ln -s /usr/local/lib/libmhash.so.2.0.1 /usr/lib/libmhash.so.2.0.1</p>
<p>tar zxvf mcrypt-2.6.8.tar.gz<br />
cd mcrypt-2.6.8/<br />
/sbin/ldconfig<br />
./configure<br />
make<br />
make install<br />
cd ../</p>
<p>2、编译安装MySQL 5.1.38</p>
<p name="code" class="c">/usr/sbin/groupadd mysql<br />
/usr/sbin/useradd -g mysql mysql<br />
tar zxvf mysql-5.1.38.tar.gz<br />
cd mysql-5.1.38/<br />
./configure &#8211;prefix=/usr/local/webserver/mysql/ &#8211;enable-assembler &#8211;with-extra-charsets=complex &#8211;enable-thread-safe-client &#8211;with-big-tables &#8211;with-readline &#8211;with-ssl &#8211;with-embedded-server &#8211;enable-local-infile &#8211;with-plugins=innobase<br />
make &amp;&amp; make install<br />
chmod +w /usr/local/webserver/mysql<br />
chown -R mysql:mysql /usr/local/webserver/mysql<br />
cd ../</p>
<p>附：以下为附加步骤，如果你想在这台服务器上运行MySQL数据库，则执行以下两步。如果你只是希望让PHP支持MySQL扩展库，能够连接其他服务器上的MySQL数据库，那么，以下两步无需执行。</p>
<p>①、创建MySQL数据库存放目录</p>
<p name="code" class="c">mkdir -p /data0/mysql/3306/data/<br />
chown -R mysql:mysql /data0/mysql/</p>
<p>②、以mysql用户帐号的身份建立数据表：</p>
<p name="code" class="c">/usr/local/webserver/mysql/bin/mysql_install_db &#8211;basedir=/usr/local/webserver/mysql &#8211;datadir=/data0/mysql/3306/data &#8211;user=mysql</p>
<p>③、创建my.cnf配置文件：</p>
<p name="code" class="c">vi /data0/mysql/3306/my.cnf</p>
<p>输入以下内容：</p>
<p name="code" class="c">[client]<br />
default-character-set = utf8<br />
port    = 3306<br />
socket  = /tmp/mysql.sock</p>
<p>[mysql]<br />
prompt=&#8221;(\u:blog.s135.com:)[\d]&gt; &#8221;<br />
no-auto-rehash</p>
<p>[mysqld]<br />
#default-character-set = utf8<br />
user    = mysql<br />
port    = 3306<br />
socket  = /tmp/mysql.sock<br />
basedir = /usr/local/webserver/mysql<br />
datadir = /data0/mysql/3306/data<br />
open_files_limit    = 10240<br />
back_log = 600<br />
max_connections = 3000<br />
max_connect_errors = 6000<br />
table_cache = 614<br />
external-locking = FALSE<br />
max_allowed_packet = 32M<br />
sort_buffer_size = 2M<br />
join_buffer_size = 2M<br />
thread_cache_size = 300<br />
thread_concurrency = 8<br />
query_cache_size = 32M<br />
query_cache_limit = 2M<br />
query_cache_min_res_unit = 2k<br />
default-storage-engine = MyISAM<br />
default_table_type = MyISAM<br />
thread_stack = 192K<br />
transaction_isolation = READ-COMMITTED<br />
tmp_table_size = 246M<br />
max_heap_table_size = 246M<br />
long_query_time = 1<br />
log_long_format<br />
log-bin = /data0/mysql/3306/binlog<br />
binlog_cache_size = 4M<br />
binlog_format = MIXED<br />
max_binlog_cache_size = 8M<br />
max_binlog_size = 512M<br />
expire_logs_days = 7<br />
key_buffer_size = 256M<br />
read_buffer_size = 1M<br />
read_rnd_buffer_size = 16M<br />
bulk_insert_buffer_size = 64M<br />
myisam_sort_buffer_size = 128M<br />
myisam_max_sort_file_size = 10G<br />
myisam_max_extra_sort_file_size = 10G<br />
myisam_repair_threads = 1<br />
myisam_recover</p>
<p>skip-name-resolve<br />
master-connect-retry = 10<br />
slave-skip-errors = 1032,1062,126,1114,1146,1048,1396</p>
<p>server-id = 1</p>
<p>innodb_additional_mem_pool_size = 16M<br />
innodb_buffer_pool_size = 2048M<br />
innodb_data_file_path = ibdata1:1024M:autoextend<br />
innodb_file_io_threads = 4<br />
innodb_thread_concurrency = 8<br />
innodb_flush_log_at_trx_commit = 2<br />
innodb_log_buffer_size = 16M<br />
innodb_log_file_size = 128M<br />
innodb_log_files_in_group = 3<br />
innodb_max_dirty_pages_pct = 90<br />
innodb_lock_wait_timeout = 120<br />
innodb_file_per_table = 0<br />
[mysqldump]<br />
quick<br />
max_allowed_packet = 32M</p>
<p>④、创建管理MySQL数据库的shell脚本：</p>
<p name="code" class="c">vi /data0/mysql/3306/mysql</p>
<p>输入以下内容（这里的用户名admin和密码12345678接下来的步骤会创建）：</p>
<p name="code" class="c">
#!/bin/sh</p>
<p>mysql_port=3306<br />
mysql_username=&#8221;admin&#8221;<br />
mysql_password=&#8221;12345678&#8243;</p>
<p>function_start_mysql()<br />
{<br />
printf &#8220;Starting MySQL&#8230;\n&#8221;<br />
/bin/sh /usr/local/webserver/mysql/bin/mysqld_safe &#8211;defaults-file=/data0/mysql/${mysql_port}/my.cnf 2>&#038;1 > /dev/null &#038;<br />
}</p>
<p>function_stop_mysql()<br />
{<br />
printf &#8220;Stoping MySQL&#8230;\n&#8221;<br />
/usr/local/webserver/mysql/bin/mysqladmin -u ${mysql_username} -p${mysql_password} -S /tmp/mysql.sock shutdown<br />
}</p>
<p>function_restart_mysql()<br />
{<br />
printf &#8220;Restarting MySQL&#8230;\n&#8221;<br />
function_stop_mysql<br />
sleep 5<br />
function_start_mysql<br />
}</p>
<p>function_kill_mysql()<br />
{<br />
kill -9 $(ps -ef | grep &#8216;bin/mysqld_safe&#8217; | grep ${mysql_port} | awk &#8216;{printf $2}&#8217;)<br />
kill -9 $(ps -ef | grep &#8216;libexec/mysqld&#8217; | grep ${mysql_port} | awk &#8216;{printf $2}&#8217;)<br />
}</p>
<p>if [ "$1" = "start" ]; then<br />
function_start_mysql<br />
elif [ "$1" = "stop" ]; then<br />
function_stop_mysql<br />
elif [ "$1" = "restart" ]; then<br />
function_restart_mysql<br />
elif [ "$1" = "kill" ]; then<br />
function_kill_mysql<br />
else<br />
printf &#8220;Usage: /data0/mysql/${mysql_port}/mysql {start|stop|restart|kill}\n&#8221;<br />
fi
</p>
<p>⑤、赋予shell脚本可执行权限：</p>
<p name="code" class="c">chmod +x /data0/mysql/3306/mysql</p>
<p>⑥、启动MySQL：</p>
<p name="code" class="c">/data0/mysql/3306/mysql start</p>
<p>⑦、通过命令行登录管理MySQL服务器（提示输入密码时直接回车）：</p>
<p name="code" class="c">/usr/local/webserver/mysql/bin/mysql -u root -p -S /tmp/mysql.sock</p>
<p>⑧、输入以下SQL语句，创建一个具有root权限的用户（admin）和密码（12345678）：</p>
<p name="code" class="c">GRANT ALL PRIVILEGES ON *.* TO &#8216;admin&#8217;@'localhost&#8217; IDENTIFIED BY &#8216;12345678&#8242;;<br />
GRANT ALL PRIVILEGES ON *.* TO &#8216;admin&#8217;@'127.0.0.1&#8242; IDENTIFIED BY &#8216;12345678&#8242;;</p>
<p>⑨、（可选）停止MySQL：</p>
<p name="code" class="c">/data0/mysql/3306/mysql stop</p>
<p>3、编译安装PHP（FastCGI模式）</p>
<p name="code" class="c">tar zxvf php-5.2.10.tar.gz<br />
gzip -cd php-5.2.10-fpm-0.5.11.diff.gz | patch -d php-5.2.10 -p1<br />
cd php-5.2.10/<br />
./configure &#8211;prefix=/usr/local/webserver/php &#8211;with-config-file-path=/usr/local/webserver/php/etc &#8211;with-mysql=/usr/local/webserver/mysql &#8211;with-mysqli=/usr/local/webserver/mysql/bin/mysql_config &#8211;with-iconv-dir=/usr/local &#8211;with-freetype-dir &#8211;with-jpeg-dir &#8211;with-png-dir &#8211;with-zlib &#8211;with-libxml-dir=/usr &#8211;enable-xml &#8211;disable-rpath &#8211;enable-discard-path &#8211;enable-safe-mode &#8211;enable-bcmath &#8211;enable-shmop &#8211;enable-sysvsem &#8211;enable-inline-optimization &#8211;with-curl &#8211;with-curlwrappers &#8211;enable-mbregex &#8211;enable-fastcgi &#8211;enable-fpm &#8211;enable-force-cgi-redirect &#8211;enable-mbstring &#8211;with-mcrypt &#8211;with-gd &#8211;enable-gd-native-ttf &#8211;with-openssl &#8211;with-mhash &#8211;enable-pcntl &#8211;enable-sockets &#8211;with-ldap &#8211;with-ldap-sasl &#8211;with-xmlrpc &#8211;enable-zip &#8211;enable-soap &#8211;without-pear<br />
make ZEND_EXTRA_LIBS=&#8217;-liconv&#8217;<br />
make install<br />
cp php.ini-dist /usr/local/webserver/php/etc/php.ini<br />
cd ../<br />
curl http://pear.php.net/go-pear | /usr/local/webserver/php/bin/php</p>
<p>4、编译安装PHP5扩展模块</p>
<p name="code" class="c">tar zxvf memcache-2.2.5.tgz<br />
cd memcache-2.2.5/<br />
/usr/local/webserver/php/bin/phpize<br />
./configure &#8211;with-php-config=/usr/local/webserver/php/bin/php-config<br />
make<br />
make install<br />
cd ../</p>
<p>tar jxvf eaccelerator-0.9.5.3.tar.bz2<br />
cd eaccelerator-0.9.5.3/<br />
/usr/local/webserver/php/bin/phpize<br />
./configure &#8211;enable-eaccelerator=shared &#8211;with-php-config=/usr/local/webserver/php/bin/php-config<br />
make<br />
make install<br />
cd ../</p>
<p>tar zxvf PDO_MYSQL-1.0.2.tgz<br />
cd PDO_MYSQL-1.0.2/<br />
/usr/local/webserver/php/bin/phpize<br />
./configure &#8211;with-php-config=/usr/local/webserver/php/bin/php-config &#8211;with-pdo-mysql=/usr/local/webserver/mysql<br />
make<br />
make install<br />
cd ../</p>
<p>tar zxvf ImageMagick.tar.gz<br />
cd ImageMagick-6.5.1-2/<br />
./configure<br />
make<br />
make install<br />
cd ../</p>
<p>tar zxvf imagick-2.2.2.tgz<br />
cd imagick-2.2.2/<br />
/usr/local/webserver/php/bin/phpize<br />
./configure &#8211;with-php-config=/usr/local/webserver/php/bin/php-config<br />
make<br />
make install<br />
cd ../</p>
<p>5、修改php.ini文件<br />
<strong>手工修改：</strong>查找/usr/local/webserver/php/etc/php.ini中的extension_dir = &#8220;./&#8221;<br />
修改为extension_dir = &#8220;/usr/local/webserver/php/lib/php/extensions/no-debug-non-zts-20060613/&#8221;<br />
并在此行后增加以下几行，然后保存：<br />
extension = &#8220;memcache.so&#8221;<br />
extension = &#8220;pdo_mysql.so&#8221;<br />
extension = &#8220;imagick.so&#8221;</p>
<p>再查找output_buffering = Off<br />
修改为output_buffering = On</p>
<p><strong>自动修改：</strong>若嫌手工修改麻烦，可执行以下shell命令，自动完成对php.ini文件的修改：</p>
<p name="code" class="c">sed -i &#8217;s#extension_dir = &#8220;./&#8221;#extension_dir = &#8220;/usr/local/webserver/php/lib/php/extensions/no-debug-non-zts-20060613/&#8221;\nextension = &#8220;memcache.so&#8221;\nextension = &#8220;pdo_mysql.so&#8221;\nextension = &#8220;imagick.so&#8221;\n#&#8217; /usr/local/webserver/php/etc/php.ini<br />
sed -i &#8217;s#output_buffering = Off#output_buffering = On#&#8217; /usr/local/webserver/php/etc/php.ini<br />
sed -i &#8220;s#; always_populate_raw_post_data = On#always_populate_raw_post_data = On#g&#8221; /usr/local/webserver/php/etc/php.ini</p>
<p>6、配置eAccelerator加速PHP：</p>
<p name="code" class="c">mkdir -p /usr/local/webserver/eaccelerator_cache<br />
vi /usr/local/webserver/php/etc/php.ini</p>
<p>按shift+g键跳到配置文件的最末尾，加上以下配置信息：</p>
<p name="code" class="c">[eaccelerator]<br />
zend_extension=&#8221;/usr/local/webserver/php/lib/php/extensions/no-debug-non-zts-20060613/eaccelerator.so&#8221;<br />
eaccelerator.shm_size=&#8221;64&#8243;<br />
eaccelerator.cache_dir=&#8221;/usr/local/webserver/eaccelerator_cache&#8221;<br />
eaccelerator.enable=&#8221;1&#8243;<br />
eaccelerator.optimizer=&#8221;1&#8243;<br />
eaccelerator.check_mtime=&#8221;1&#8243;<br />
eaccelerator.debug=&#8221;0&#8243;<br />
eaccelerator.filter=&#8221;"<br />
eaccelerator.shm_max=&#8221;0&#8243;<br />
eaccelerator.shm_ttl=&#8221;3600&#8243;<br />
eaccelerator.shm_prune_period=&#8221;3600&#8243;<br />
eaccelerator.shm_only=&#8221;0&#8243;<br />
eaccelerator.compress=&#8221;1&#8243;<br />
eaccelerator.compress_level=&#8221;9&#8243;</p>
<p>7、创建www用户和组，以及供blog.s135.com和www.s135.com两个虚拟主机使用的目录：</p>
<p name="code" class="c">/usr/sbin/groupadd www<br />
/usr/sbin/useradd -g www www<br />
mkdir -p /data0/htdocs/blog<br />
chmod +w /data0/htdocs/blog<br />
chown -R www:www /data0/htdocs/blog<br />
mkdir -p /data0/htdocs/www<br />
chmod +w /data0/htdocs/www<br />
chown -R www:www /data0/htdocs/www</p>
<p>8、创建php-fpm配置文件（php-fpm是为PHP打的一个FastCGI管理补丁，可以平滑变更php.ini配置而无需重启php-cgi）：<br />
在/usr/local/webserver/php/etc/目录中创建php-fpm.conf文件：</p>
<p name="code" class="c">rm -f /usr/local/webserver/php/etc/php-fpm.conf<br />
vi /usr/local/webserver/php/etc/php-fpm.conf</p>
<p>输入以下内容（如果您安装 Nginx + PHP 用于程序调试，请将以下的&lt;value name=&#8221;display_errors&#8221;&gt;0&lt;/value&gt;改为&lt;value name=&#8221;display_errors&#8221;&gt;1&lt;/value&gt;，以便显示PHP错误信息，否则，Nginx 会报状态为500的空白错误页）：</p>
<div name="code" class="xml">
&lt;?xml version=&#8221;1.0&#8243; ?&gt;<br />
&lt;configuration&gt;</p>
<p>All relative paths in this config are relative to php&#8217;s install prefix</p>
<p>&lt;section name=&#8221;global_options&#8221;&gt;</p>
<p>Pid file<br />
&lt;value name=&#8221;pid_file&#8221;&gt;/usr/local/webserver/php/logs/php-fpm.pid&lt;/value&gt;</p>
<p>Error log file<br />
&lt;value name=&#8221;error_log&#8221;&gt;/usr/local/webserver/php/logs/php-fpm.log&lt;/value&gt;</p>
<p>Log level<br />
&lt;value name=&#8221;log_level&#8221;&gt;notice&lt;/value&gt;</p>
<p>When this amount of php processes exited with SIGSEGV or SIGBUS &#8230;<br />
&lt;value name=&#8221;emergency_restart_threshold&#8221;&gt;10&lt;/value&gt;</p>
<p>&#8230; in a less than this interval of time, a graceful restart will be initiated.<br />
Useful to work around accidental curruptions in accelerator&#8217;s shared memory.<br />
&lt;value name=&#8221;emergency_restart_interval&#8221;&gt;1m&lt;/value&gt;</p>
<p>Time limit on waiting child&#8217;s reaction on signals from master<br />
&lt;value name=&#8221;process_control_timeout&#8221;&gt;5s&lt;/value&gt;</p>
<p>Set to &#8216;no&#8217; to debug fpm<br />
&lt;value name=&#8221;daemonize&#8221;&gt;yes&lt;/value&gt;</p>
<p>&lt;/section&gt;</p>
<p>&lt;workers&gt;</p>
<p>&lt;section name=&#8221;pool&#8221;&gt;</p>
<p>Name of pool. Used in logs and stats.<br />
&lt;value name=&#8221;name&#8221;&gt;default&lt;/value&gt;</p>
<p>Address to accept fastcgi requests on.<br />
Valid syntax is &#8216;ip.ad.re.ss:port&#8217; or just &#8216;port&#8217; or &#8216;/path/to/unix/socket&#8217;<br />
&lt;value name=&#8221;listen_address&#8221;&gt;127.0.0.1:9000&lt;/value&gt;</p>
<p>&lt;value name=&#8221;listen_options&#8221;&gt;</p>
<p>Set listen(2) backlog<br />
&lt;value name=&#8221;backlog&#8221;&gt;-1&lt;/value&gt;</p>
<p>Set permissions for unix socket, if one used.<br />
In Linux read/write permissions must be set in order to allow connections from web server.<br />
Many BSD-derrived systems allow connections regardless of permissions.<br />
&lt;value name=&#8221;owner&#8221;&gt;&lt;/value&gt;<br />
&lt;value name=&#8221;group&#8221;&gt;&lt;/value&gt;<br />
&lt;value name=&#8221;mode&#8221;&gt;0666&lt;/value&gt;<br />
&lt;/value&gt;</p>
<p>Additional php.ini defines, specific to this pool of workers.<br />
&lt;value name=&#8221;php_defines&#8221;&gt;<br />
&lt;value name=&#8221;sendmail_path&#8221;&gt;/usr/sbin/sendmail -t -i&lt;/value&gt;<br />
&lt;value name=&#8221;display_errors&#8221;&gt;1&lt;/value&gt;<br />
&lt;/value&gt;</p>
<p>Unix user of processes<br />
&lt;value name=&#8221;user&#8221;&gt;www&lt;/value&gt;</p>
<p>Unix group of processes<br />
&lt;value name=&#8221;group&#8221;&gt;www&lt;/value&gt;</p>
<p>Process manager settings<br />
&lt;value name=&#8221;pm&#8221;&gt;</p>
<p>Sets style of controling worker process count.<br />
Valid values are &#8217;static&#8217; and &#8216;apache-like&#8217;<br />
&lt;value name=&#8221;style&#8221;&gt;static&lt;/value&gt;</p>
<p>Sets the limit on the number of simultaneous requests that will be served.<br />
Equivalent to Apache MaxClients directive.<br />
Equivalent to PHP_FCGI_CHILDREN environment in original php.fcgi<br />
Used with any pm_style.<br />
&lt;value name=&#8221;max_children&#8221;&gt;128&lt;/value&gt;</p>
<p>Settings group for &#8216;apache-like&#8217; pm style<br />
&lt;value name=&#8221;apache_like&#8221;&gt;</p>
<p>Sets the number of server processes created on startup.<br />
Used only when &#8216;apache-like&#8217; pm_style is selected<br />
&lt;value name=&#8221;StartServers&#8221;&gt;20&lt;/value&gt;</p>
<p>Sets the desired minimum number of idle server processes.<br />
Used only when &#8216;apache-like&#8217; pm_style is selected<br />
&lt;value name=&#8221;MinSpareServers&#8221;&gt;5&lt;/value&gt;</p>
<p>Sets the desired maximum number of idle server processes.<br />
Used only when &#8216;apache-like&#8217; pm_style is selected<br />
&lt;value name=&#8221;MaxSpareServers&#8221;&gt;35&lt;/value&gt;</p>
<p>&lt;/value&gt;</p>
<p>&lt;/value&gt;</p>
<p>The timeout (in seconds) for serving a single request after which the worker process will be terminated<br />
Should be used when &#8216;max_execution_time&#8217; ini option does not stop script execution for some reason<br />
&#8216;0s&#8217; means &#8216;off&#8217;<br />
&lt;value name=&#8221;request_terminate_timeout&#8221;&gt;0s&lt;/value&gt;</p>
<p>The timeout (in seconds) for serving of single request after which a php backtrace will be dumped to slow.log file<br />
&#8216;0s&#8217; means &#8216;off&#8217;<br />
&lt;value name=&#8221;request_slowlog_timeout&#8221;&gt;0s&lt;/value&gt;</p>
<p>The log file for slow requests<br />
&lt;value name=&#8221;slowlog&#8221;&gt;logs/slow.log&lt;/value&gt;</p>
<p>Set open file desc rlimit<br />
&lt;value name=&#8221;rlimit_files&#8221;&gt;65535&lt;/value&gt;</p>
<p>Set max core size rlimit<br />
&lt;value name=&#8221;rlimit_core&#8221;&gt;0&lt;/value&gt;</p>
<p>Chroot to this directory at the start, absolute path<br />
&lt;value name=&#8221;chroot&#8221;&gt;&lt;/value&gt;</p>
<p>Chdir to this directory at the start, absolute path<br />
&lt;value name=&#8221;chdir&#8221;&gt;&lt;/value&gt;</p>
<p>Redirect workers&#8217; stdout and stderr into main error log.<br />
If not set, they will be redirected to /dev/null, according to FastCGI specs<br />
&lt;value name=&#8221;catch_workers_output&#8221;&gt;yes&lt;/value&gt;</p>
<p>How much requests each process should execute before respawn.<br />
Useful to work around memory leaks in 3rd party libraries.<br />
For endless request processing please specify 0<br />
Equivalent to PHP_FCGI_MAX_REQUESTS<br />
&lt;value name=&#8221;max_requests&#8221;&gt;102400&lt;/value&gt;</p>
<p>Comma separated list of ipv4 addresses of FastCGI clients that allowed to connect.<br />
Equivalent to FCGI_WEB_SERVER_ADDRS environment in original php.fcgi (5.2.2+)<br />
Makes sense only with AF_INET listening socket.<br />
&lt;value name=&#8221;allowed_clients&#8221;&gt;127.0.0.1&lt;/value&gt;</p>
<p>Pass environment variables like LD_LIBRARY_PATH<br />
All $VARIABLEs are taken from current environment<br />
&lt;value name=&#8221;environment&#8221;&gt;<br />
&lt;value name=&#8221;HOSTNAME&#8221;&gt;$HOSTNAME&lt;/value&gt;<br />
&lt;value name=&#8221;PATH&#8221;&gt;/usr/local/bin:/usr/bin:/bin&lt;/value&gt;<br />
&lt;value name=&#8221;TMP&#8221;&gt;/tmp&lt;/value&gt;<br />
&lt;value name=&#8221;TMPDIR&#8221;&gt;/tmp&lt;/value&gt;<br />
&lt;value name=&#8221;TEMP&#8221;&gt;/tmp&lt;/value&gt;<br />
&lt;value name=&#8221;OSTYPE&#8221;&gt;$OSTYPE&lt;/value&gt;<br />
&lt;value name=&#8221;MACHTYPE&#8221;&gt;$MACHTYPE&lt;/value&gt;<br />
&lt;value name=&#8221;MALLOC_CHECK_&#8221;&gt;2&lt;/value&gt;<br />
&lt;/value&gt;</p>
<p>&lt;/section&gt;</p>
<p>&lt;/workers&gt;</p>
<p>&lt;/configuration&gt;
</p></div>
<p>9、启动php-cgi进程，监听127.0.0.1的9000端口，进程数为200（如果服务器内存小于3GB，可以只开启64个进程），用户为www：</p>
<p name="code" class="c">ulimit -SHn 65535<br />
/usr/local/webserver/php/sbin/php-fpm start</p>
<p>注：/usr/local/webserver/php/sbin/php-fpm还有其他参数，包括：start|stop|quit|restart|reload|logrotate，修改php.ini后不重启php-cgi，重新加载配置文件使用reload。</p>
<p><strong>三、安装Nginx 0.8.15</strong><br />
1、安装Nginx所需的pcre库：</p>
<p name="code" class="c">tar zxvf pcre-7.9.tar.gz<br />
cd pcre-7.9/<br />
./configure<br />
make &amp;&amp; make install<br />
cd ../</p>
<p>2、安装Nginx</p>
<p name="code" class="c">tar zxvf nginx-0.8.15.tar.gz<br />
cd nginx-0.8.15/<br />
./configure &#8211;user=www &#8211;group=www &#8211;prefix=/usr/local/webserver/nginx &#8211;with-http_stub_status_module &#8211;with-http_ssl_module<br />
make &amp;&amp; make install<br />
cd ../</p>
<p>3、创建Nginx日志目录</p>
<p name="code" class="c">mkdir -p /data1/logs<br />
chmod +w /data1/logs<br />
chown -R www:www /data1/logs</p>
<p>4、创建Nginx配置文件<br />
①、在/usr/local/webserver/nginx/conf/目录中创建nginx.conf文件：</p>
<p name="code" class="c">rm -f /usr/local/webserver/nginx/conf/nginx.conf<br />
vi /usr/local/webserver/nginx/conf/nginx.conf</p>
<p>输入以下内容：</p>
<p name="code" class="c">user  www www;<br />
worker_processes 8;<br />
error_log  /data1/logs/nginx_error.log  crit;<br />
pid        /usr/local/webserver/nginx/nginx.pid;</p>
<p>#Specifies the value for maximum file descriptors that can be opened by this process.<br />
worker_rlimit_nofile 65535;</p>
<p>events<br />
{<br />
use epoll;<br />
worker_connections 65535;<br />
}</p>
<p>http<br />
{<br />
include       mime.types;<br />
default_type  application/octet-stream;</p>
<p>#charset  gb2312;</p>
<p>server_names_hash_bucket_size 128;<br />
client_header_buffer_size 32k;<br />
large_client_header_buffers 4 32k;<br />
client_max_body_size 8m;</p>
<p>sendfile on;<br />
tcp_nopush     on;</p>
<p>keepalive_timeout 60;</p>
<p>tcp_nodelay on;</p>
<p>fastcgi_connect_timeout 300;<br />
fastcgi_send_timeout 300;<br />
fastcgi_read_timeout 300;<br />
fastcgi_buffer_size 64k;<br />
fastcgi_buffers 4 64k;<br />
fastcgi_busy_buffers_size 128k;<br />
fastcgi_temp_file_write_size 128k;</p>
<p>gzip on;<br />
gzip_min_length  1k;<br />
gzip_buffers     4 16k;<br />
gzip_http_version 1.0;<br />
gzip_comp_level 2;<br />
gzip_types       text/plain application/x-javascript text/css application/xml;<br />
gzip_vary on;</p>
<p>#limit_zone  crawler  $binary_remote_addr  10m;</p>
<p>server<br />
{<br />
listen       80;<br />
server_name  blog.s135.com;<br />
index index.html index.htm index.php;<br />
root  /data0/htdocs/blog;</p>
<p>#limit_conn   crawler  20;</p>
<p>location ~ .*\.(php|php5)?$<br />
{<br />
#fastcgi_pass  unix:/tmp/php-cgi.sock;<br />
fastcgi_pass  127.0.0.1:9000;<br />
fastcgi_index index.php;<br />
include fcgi.conf;<br />
}</p>
<p>location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$<br />
{<br />
expires      30d;<br />
}</p>
<p>location ~ .*\.(js|css)?$<br />
{<br />
expires      1h;<br />
}</p>
<p>log_format  access  &#8217;$remote_addr &#8211; $remote_user [$time_local] &#8220;$request&#8221; &#8216;<br />
&#8216;$status $body_bytes_sent &#8220;$http_referer&#8221; &#8216;<br />
&#8216;&#8221;$http_user_agent&#8221; $http_x_forwarded_for&#8217;;<br />
access_log  /data1/logs/access.log  access;<br />
}</p>
<p>server<br />
{<br />
listen       80;<br />
server_name  www.s135.com;<br />
index index.html index.htm index.php;<br />
root  /data0/htdocs/www;</p>
<p>location ~ .*\.(php|php5)?$<br />
{<br />
#fastcgi_pass  unix:/tmp/php-cgi.sock;<br />
fastcgi_pass  127.0.0.1:9000;<br />
fastcgi_index index.php;<br />
include fcgi.conf;<br />
}</p>
<p>log_format  wwwlogs  &#8217;$remote_addr &#8211; $remote_user [$time_local] &#8220;$request&#8221; &#8216;<br />
&#8216;$status $body_bytes_sent &#8220;$http_referer&#8221; &#8216;<br />
&#8216;&#8221;$http_user_agent&#8221; $http_x_forwarded_for&#8217;;<br />
access_log  /data1/logs/wwwlogs.log  wwwlogs;<br />
}</p>
<p>server<br />
{<br />
listen  80;<br />
server_name  status.blog.s135.com;</p>
<p>location / {<br />
stub_status on;<br />
access_log   off;<br />
}<br />
}<br />
}</p>
<p>②、在/usr/local/webserver/nginx/conf/目录中创建fcgi.conf文件：</p>
<p name="code" class="c">vi /usr/local/webserver/nginx/conf/fcgi.conf</p>
<p>输入以下内容：</p>
<p name="code" class="c">fastcgi_param  GATEWAY_INTERFACE  CGI/1.1;<br />
fastcgi_param  SERVER_SOFTWARE    nginx;</p>
<p>fastcgi_param  QUERY_STRING       $query_string;<br />
fastcgi_param  REQUEST_METHOD     $request_method;<br />
fastcgi_param  CONTENT_TYPE       $content_type;<br />
fastcgi_param  CONTENT_LENGTH     $content_length;</p>
<p>fastcgi_param  SCRIPT_FILENAME    $document_root$fastcgi_script_name;<br />
fastcgi_param  SCRIPT_NAME        $fastcgi_script_name;<br />
fastcgi_param  REQUEST_URI        $request_uri;<br />
fastcgi_param  DOCUMENT_URI       $document_uri;<br />
fastcgi_param  DOCUMENT_ROOT      $document_root;<br />
fastcgi_param  SERVER_PROTOCOL    $server_protocol;</p>
<p>fastcgi_param  REMOTE_ADDR        $remote_addr;<br />
fastcgi_param  REMOTE_PORT        $remote_port;<br />
fastcgi_param  SERVER_ADDR        $server_addr;<br />
fastcgi_param  SERVER_PORT        $server_port;<br />
fastcgi_param  SERVER_NAME        $server_name;</p>
<p># PHP only, required if PHP was built with &#8211;enable-force-cgi-redirect<br />
fastcgi_param  REDIRECT_STATUS    200;</p>
<p>5、启动Nginx</p>
<p name="code" class="c">ulimit -SHn 65535<br />
/usr/local/webserver/nginx/sbin/nginx</p>
<p><strong>四、配置开机自动启动Nginx + PHP</strong></p>
<p name="code" class="c">vi /etc/rc.local</p>
<p>在末尾增加以下内容：</p>
<p name="code" class="c">ulimit -SHn 65535<br />
/usr/local/webserver/php/sbin/php-fpm start<br />
/usr/local/webserver/nginx/sbin/nginx</p>
<p><strong>五、优化Linux内核参数</strong></p>
<p name="code" class="c">vi /etc/sysctl.conf</p>
<p>在末尾增加以下内容：</p>
<p name="code" class="c"># Add<br />
net.ipv4.tcp_max_syn_backlog = 65536<br />
net.core.netdev_max_backlog =  32768<br />
net.core.somaxconn = 32768</p>
<p>net.core.wmem_default = 8388608<br />
net.core.rmem_default = 8388608<br />
net.core.rmem_max = 16777216<br />
net.core.wmem_max = 16777216</p>
<p>net.ipv4.tcp_timestamps = 0<br />
net.ipv4.tcp_synack_retries = 2<br />
net.ipv4.tcp_syn_retries = 2</p>
<p>net.ipv4.tcp_tw_recycle = 1<br />
#net.ipv4.tcp_tw_len = 1<br />
net.ipv4.tcp_tw_reuse = 1</p>
<p>net.ipv4.tcp_mem = 94500000 915000000 927000000<br />
net.ipv4.tcp_max_orphans = 3276800</p>
<p>#net.ipv4.tcp_fin_timeout = 30<br />
#net.ipv4.tcp_keepalive_time = 120<br />
net.ipv4.ip_local_port_range = 1024  65535</p>
<p>使配置立即生效：</p>
<p name="code" class="c">/sbin/sysctl -p</p>
<p><strong>六、在不停止Nginx服务的情况下平滑变更Nginx配置</strong><br />
1、修改/usr/local/webserver/nginx/conf/nginx.conf配置文件后，请执行以下命令检查配置文件是否正确：</p>
<p name="code" class="c">/usr/local/webserver/nginx/sbin/nginx -t</p>
<p>如果屏幕显示以下两行信息，说明配置文件正确：<br />
the configuration file /usr/local/webserver/nginx/conf/nginx.conf syntax is ok<br />
the configuration file /usr/local/webserver/nginx/conf/nginx.conf was tested successfully</p>
<p>2、这时，输入以下命令查看Nginx主进程号：</p>
<p name="code" class="c">ps -ef | grep &#8220;nginx: master process&#8221; | grep -v &#8220;grep&#8221; | awk -F &#8216; &#8216; &#8216;{print $2}&#8217;</p>
<p>屏幕显示的即为Nginx主进程号，例如：<br />
6302<br />
这时，执行以下命令即可使修改过的Nginx配置文件生效：</p>
<p name="code" class="c">kill -HUP 6302</p>
<p>或者无需这么麻烦，找到Nginx的Pid文件：</p>
<p name="code" class="c">kill -HUP `cat /usr/local/webserver/nginx/nginx.pid`</p>
<p><strong>七、编写每天定时切割Nginx日志的脚本</strong><br />
1、创建脚本/usr/local/webserver/nginx/sbin/cut_nginx_log.sh</p>
<p name="code" class="c">vi /usr/local/webserver/nginx/sbin/cut_nginx_log.sh</p>
<p>输入以下内容：</p>
<p name="code" class="c">#!/bin/bash<br />
# This script run at 00:00</p>
<p># The Nginx logs path<br />
logs_path=&#8221;/usr/local/webserver/nginx/logs/&#8221;</p>
<p>mkdir -p ${logs_path}$(date -d &#8220;yesterday&#8221; +&#8221;%Y&#8221;)/$(date -d &#8220;yesterday&#8221; +&#8221;%m&#8221;)/<br />
mv ${logs_path}access.log ${logs_path}$(date -d &#8220;yesterday&#8221; +&#8221;%Y&#8221;)/$(date -d &#8220;yesterday&#8221; +&#8221;%m&#8221;)/access_$(date -d &#8220;yesterday&#8221; +&#8221;%Y%m%d&#8221;).log<br />
kill -USR1 `cat /usr/local/webserver/nginx/nginx.pid`</p>
<p>2、设置crontab，每天凌晨00:00切割nginx访问日志</p>
<p name="code" class="c">crontab -e</p>
<p>输入以下内容：</p>
<p name="code" class="c">00 00 * * * /bin/bash  /usr/local/webserver/nginx/sbin/cut_nginx_log.sh</p>
<p><strong>附：文章修改历史</strong></p>
<p>● [2009年05月06日] [Version 5.0] 在4.14版本的基础上重新撰写本文，支持PHP 5.2.9，增加MySQL配置过程</p>
<p>● [2009年05月10日] [Version 5.1] 增加压力测试方法。</p>
<p>● [2009年05月20日] [Version 5.2] Nginx升级到0.7.58版本；PHP编译选项增加：&#8211;with-xmlrpc &#8211;enable-zip。</p>
<p>● [2009年06月10日] [Version 5.3] Nginx升级到0.7.59版本；MySQL升级到5.1.35版本。</p>
<p>● [2009年06月26日] [Version 5.4] Nginx升级到0.7.61版本；PHP升级到5.2.10版本；PCRE升级到7.9版本；PHP增加soap扩展；关闭了PHP的PEAR；优化sysctl配置。</p>
<p>● [2009年09月18日] [Version 5.5] Nginx升级到0.8.15版本；PCRE升级到7.9版本；解决PHP 5.2.10 的PEAR问题。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.zfkun.com/blog/index.php/archives/95/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>房贷：等额本息和等额本金有什么区别？</title>
		<link>http://www.zfkun.com/blog/index.php/archives/93</link>
		<comments>http://www.zfkun.com/blog/index.php/archives/93#comments</comments>
		<pubDate>Mon, 25 Jan 2010 14:39:42 +0000</pubDate>
		<dc:creator>影之迷惑</dc:creator>
				<category><![CDATA[Life]]></category>
		<category><![CDATA[房贷]]></category>
		<category><![CDATA[本息]]></category>
		<category><![CDATA[本金]]></category>
		<category><![CDATA[等额]]></category>

		<guid isPermaLink="false">http://www.zfkun.com/blog/?p=93</guid>
		<description><![CDATA[等额本息：本金逐月递增，利息逐月递减，月还款数不变。等额本金：本金保持相同，利息逐月递减，月还款数递减。适合于有计划提前还贷。利息少的是等额本金方式的还款。]]></description>
			<content:encoded><![CDATA[<p>    等额本息：本金逐月递增，利息逐月递减，月还款数不变。 </p>
<p>    等额本金：本金保持相同，利息逐月递减，月还款数递减。适合于有计划提前还贷。 </p>
<p>利息少的是等额本金方式的还款。 </p>
<p>     目前，银行的个人住房货款的还款方式主要有等额本息和等额本金两种方式。等额本息还贷方式每月按相同金额还贷款本息，月还款中利息逐月递减，本金逐月递增；等额本金还贷方式还款金额递减，月还款中本金保持相同金额，利息逐月递减。 </p>
<p>     二者的主要区别在于，前者每期还款金额相同，即每月本金加利息总额相同，客户还贷压力均衡，但利息负担相对较多；后者又叫‘递减还款法’,每月本金相同,利息不同,前期还款压力大,但以后的还款金额逐渐递减,利息总负担较少。 </p>
<p>     现在知道这两种方式的人们几乎都认为选择等额本金划算,因为选择等额本息多支付了本息,而等额本金则少支付利息,而且认为一旦提前还贷时，会发现等额本息的还款，原来自己前期还的钱绝大部分是利息，而不是本金，由此会觉得吃亏很多。 </p>
<p>     总体来看，“等额本息”是会比“递减还款”多付一些利息。以1万元20年期贷款为标准，前者会比后者多支付800多元的利息。40万20年期的贷款，则要多支付800×40=32000元的利息。看似银行多收了利息，但实际上，等额本金还款法随着本金的递减，银行可以加速还款，尽快回笼资金，降低经营风险在这一点上是有利于防范风险的。<br />
在实际操作中,等额本息更利于客户的掌握,方便客户还款.事实上有很多客户在进行比较后,还是愿意选择了“等额还款方式”，因为这钟方式月还款额固定，便于客户记忆，还款压力均衡，实际与等额本金差别不大。因为这些客户也同样看到了因为时间使资金的使用价值产生了不同，简单说就是等额本息还款法由于自己占用银行的本金时间长，自然就要多付些利息；等额本金还款法随着本金的递减，自己占用银行的本金时间短，利息也自然减少，并不存在自己吃亏，而银行赚取更多利息的问题。 </p>
<p>     实质上，两种贷款方式是一致的，没有优劣之分。只有在需求的不同时，才有不同的选择。 </p>
<p>     因为等额本息还款法还款压力均衡但需多付些利息，所以适合有一定积蓄，但收入可能持平或下降、生活负担日益加重、并且没有打算提前还款的人群。<br />
     而等额本金还款法，由于贷款人本金归还得快，利息就可以少付，但前期还款额度大，因此适合当前收入较高者、或预计不久将来收入大幅增长，.准备提前还款人群，.则较为有利。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.zfkun.com/blog/index.php/archives/93/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>CSS圆角—透明圆角化背景图片</title>
		<link>http://www.zfkun.com/blog/index.php/archives/91</link>
		<comments>http://www.zfkun.com/blog/index.php/archives/91#comments</comments>
		<pubDate>Thu, 21 Jan 2010 03:11:53 +0000</pubDate>
		<dc:creator>影之迷惑</dc:creator>
				<category><![CDATA[Web]]></category>
		<category><![CDATA[css]]></category>
		<category><![CDATA[sprites]]></category>
		<category><![CDATA[圆角]]></category>
		<category><![CDATA[弹性]]></category>

		<guid isPermaLink="false">http://www.zfkun.com/blog/?p=91</guid>
		<description><![CDATA[序言：第一章中我介绍了最基本的纯CSS圆角框的实现原理，并给出Demo，在本章中会对上一个模型作一些新的创新，实现将背景图片透明圆角化。并给出一些漂亮的通用演示效果。
在上面的案例中，我只给出最为原始的圆角框模型，它还是存在一些不足之处。比如不能将图片应用到圆角框内。而在本例中，我会在上面的基础上作出一些创新。就是将背景图片也圆角化。]]></description>
			<content:encoded><![CDATA[<p>作者：<a href="http://www.blueidea.com/common/contact.asp?type=作者&amp;username=by0001" target="_blank">by0001</a>　来自：<a href="http://www.blueidea.com/">蓝色理想</a><br />
原文：<a href="http://www.blueidea.com/tech/web/2010/7353.asp">http://www.blueidea.com/tech/web/2010/7353.asp</a></p>
<p>序言：第一章中我介绍了最基本的纯CSS圆角框的实现原理，并给出Demo，在本章中会对上一个模型作一些新的创新，实现将背景图片透明圆角化。并给出一些漂亮的通用演示效果。</p>
<p>在上面的案例中，我只给出最为原始的圆角框模型，它还是存在一些不足之处。比如不能将图片应用到圆角框内。而在本例中，我会在上面的基础上作出一些创新。就是将背景图片也圆角化，好像目前在网络上还没有这样的功能应用，我只见过用js方式来实现的，可以参看我的《<a href="http://www.blueidea.com/tech/web/2009/6488.asp" target="_blank">超圆滑圆角框的半完美解决方案</a>》一文中后面几种JS方案。但是纯CSS方式的实现可是我独家所创，如有雷同，只能说英雄所见略同。呵呵！</p>
<p>还是先看看最终的效果图，让大家有一个大概的印象。</p>
<p style="text-align: center;"><img class="aligncenter" src="http://www.blueidea.com/articleimg/2010/01/7353/01.jpg" border="0" alt="" width="510" height="533" /></p>
<p style="text-align: center;">图一</p>
<p>像这种小面积布局在网页设计中应用得很普遍，但目前网络流行的作法都是采用图片的方式来实现的，将图片按上中下切成三块内容，然后使用三个同级的DIV或SPAN容器各自填充一张图，但是这种方法有一个最大的毛病：不能自动适应宽度的变化，一般做法都是采用固定宽度的方式，这是由于图片的宽度决定的。</p>
<p>当然对于一些比较有经验的人员来说，可以采用九宫格布局（可参看我的另一篇文章《<a href="http://www.blueidea.com/tech/web/2009/6800.asp" target="_blank">九宫格基本布局</a>》）方式或者滑动门方式来做到自适应宽度的变化，九宫格一般都需要用到八张图片，而滑动门虽然只用一张图片，但为了适应宽度的变化，这张图片一般都做得很大。<br />
而我现在独创的这种方法可以完全做到适应不同宽度的需要，并且全部兼容所有的浏览器，而所需要的仅仅是一张很小的水平平辅的背景图片而已。</p>
<p><strong>基本原理</strong>：</p>
<p style="text-align: center;">我们都知道图片是方方正正的，不可能做出圆角效果，那么我们如何来做外圆透明的图片呢？其实道理说明了也就是一件很简单的事情，你看过下面的放大示意图后可能就会“哦”地一声，原来不过如此……<br />
<img class="aligncenter" src="http://www.blueidea.com/articleimg/2010/01/7353/02.jpg" border="0" alt="" width="464" height="388" /></p>
<p style="text-align: center;">图二</p>
<p>是的，看到这个效果图你会一目了然，可是要想到这个方法，我却浪费了不少脑细胞。呵呵！</p>
<p>实现这种方法原理很简单：<strong>在每个b标签中各加载一次同样的图片，并结合背景定位background-position方式来达到效果。</strong>我们知道，同一张图片加载多少次对于性能的影响并不大，因为这张图片已经被电脑缓存到本地，和用css sprites合并图片一样的道理。</p>
<p>但是需要注意的是：每个B标签加载图片的定位是不一样的。</p>
<p><strong>背景图片定位原理</strong>：　　</p>
<p>b1标签位于第一位，它主要用来描绘上边框线，所以它不需要加载背景图片。</p>
<p>b2标签位于第二位，它是第一个需要加载背景图片的，但是不需要图片负偏移，所以直接居左居顶定位就可以了。</p>
<pre name="code" class="css">
.b2{background-position:left top;}
</pre>
<p>b3标签位于第三位，它需要加载背景图片，让它的背景图片向上负偏移b2的高度值就可以，也就是1px。</p>
<pre name="code" class="css">
.b3{background-position:left -1px;}
</pre>
<p>b4位于第四位，所以它向上负偏移b2+b3高度值的和，为2px.。</p>
<pre name="code" class="css">
.b4{background-position:left -2px;}
</pre>
<p>H3标签位于第五位，所以它的背景图片需要向上负偏移b2+b3+b4高度值的各，也就是4px；</p>
<pre name="code" class="css">
h3{background-position:left -4px;}
</pre>
<p>这样，b2、b3、b4、h3的图片叠加起来和原始图片上下渐变的效果完全重合，如同一张图片，这样就达到模拟圆角图片的效果。<br />
怎么样，原理够简单明了吧！</p>
<p>原理清楚后，要实现起来也就是一件水到渠成的事！</p>
<p><strong>HTML结构层</strong>：</p>
<p>如同我们在第一章中模型所见，保持结构不变。</p>
<p><strong>CSS样式层：（只写关键代码）</strong></p>
<p>将上面的几句代码进行合并，如下所示：</p>
<pre name="code" class="css">
.sharp b.b2{background-position:left top;}
.sharp b.b3{background-position:left -1px;}
.sharp b.b4{background-position:left -2px;}
.sharp .content h3{background-position:left -4px;}
</pre>
<p>和第一章中同样的道理，我们肯定要在各个不同的块框中有不同的背景图片的变化，也就是说，我们也要实现不同的换肤方案，当一个页面要多次调用同一个圆角框时，也可以让它们有些丰富的变化。实现不同的风格。OK，没问题，你只需要简单的将下面的样式中的背景图片的路径改变一下就可以了。</p>
<pre name="code" class="css">
.color1 .b2,.color1 .b3,.color1 .b4,.color1 h3{background:url(images/bg1.gif) repeat-x;}
</pre>
<p>你可以实现不同的颜色方案，就看你的设计师给你多少张不同图片了。</p>
<p>一种风格的定制也是一件简单的事情：</p>
<pre name="code" class="css">
*颜色方案一,绿色风格----------------------------------------*/
/*边框色*/
.color1 .b2,.color1 .b3,.color1 .b4,.color1 .b5,.color1 .b6,
.color1 .b7,.color1 .content{border-color:#A0C044;}
.color1 .b1,.color1 .b8{background:#A0C044;}
.color1 h3{border-bottom:1px #679800 solid;}
/*图片路径*/
.color1 .b2,.color1 .b3,.color1 .b4,.color1 h3{background:url(images/bg1.gif) repeat-x;}
/*文字内容背景色*/
.color1 .b5,.color1 .b6,.color1 .b7{background:#FFF;}
</pre>
<p>你只需要复制上面的代码，简单修改一下边框色，背景色，图片路径就变成你想要的风格了，是不是很简单呢？然后在你想应用样式的容器上定义这个color1类名即可。</p>
<p>在我的演示模型中，我定义了9种风格的变化，看看有没有适合你需要，直接复制就可以使用了，祝您用得开心！</p>
<p><strong>为了演示效果，本模型的宽度值全部采用百分比实现的，你可以随意伸缩宽度，看看它能否适应弹性的变化。</strong></p>
<p><strong>本模型在以下浏览器中完美通过：<br />
IE5.5、IE6、IE7、IE8、FF3、TT、Maxthon2.1.5、Opera9.6、Safari4.0、Chrome2.0。</strong></p>
<p><a class="aligncenter" href="http://www.zfkun.com/soft/CSS_RoundAngle_2.rar" target="_blank">压缩包下载</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.zfkun.com/blog/index.php/archives/91/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>CSS圆角—基本圆角框</title>
		<link>http://www.zfkun.com/blog/index.php/archives/87</link>
		<comments>http://www.zfkun.com/blog/index.php/archives/87#comments</comments>
		<pubDate>Thu, 21 Jan 2010 02:50:03 +0000</pubDate>
		<dc:creator>影之迷惑</dc:creator>
				<category><![CDATA[Web]]></category>
		<category><![CDATA[css]]></category>
		<category><![CDATA[sprites]]></category>
		<category><![CDATA[圆角]]></category>
		<category><![CDATA[弹性]]></category>

		<guid isPermaLink="false">http://www.zfkun.com/blog/?p=87</guid>
		<description><![CDATA[纯CSS实现圆角框是一件大家都说烂了的事件，我也写过两篇总结文章，为什么还会有这篇文章呢，事情是这样的。在我们的以前的项目中，实现圆角框往往是用背景图片来实现的，但是，当这些项目发布上线后，在维护过程中，有时需要添加一些新的需求，因为以前的项目中大量采用了圆角图片，并且这些图片全部采用了CSS sprites方式合并的图，为了不增加更多的额外工作，并且也不想用JS来添加更多的http请求，所以需要一些简单的CSS方案来解决这个问题。而我的个人爱好，也喜欢采用无图片的方式来处理这些效果。总觉得CSS能完成的工作，为什么不让它来实现呢？]]></description>
			<content:encoded><![CDATA[<p>作者：<a href="http://www.blueidea.com/common/contact.asp?type=作者&amp;username=by0001" target="_blank">by0001</a>　来自：<a href="http://www.blueidea.com/">蓝色理想</a></p>
<p>原文：<a href="http://www.blueidea.com/tech/web/2010/7347.asp">http://www.blueidea.com/tech/web/2010/7347.asp</a></p>
<p>序言：在我的文章《<a href="http://www.blueidea.com/tech/web/2009/6488.asp" target="_blank">超圆滑圆角框的半完美解决方案</a>》中已经总结了七种不同的圆角框解决方案，基本上总结完了目前网络上比较流行的圆角框实现方案。而在我的另一篇文章《无图片山顶角》中又是一个另类的实现方法。</p>
<p>纯CSS实现圆角框是一件大家都说烂了的事件，我也写过两篇总结文章，为什么还会有这篇文章呢，事情是这样的。在我们的以前的项目中，实现圆角框往往是用背景图片来实现的，但是，当这些项目发布上线后，在维护过程中，有时需要添加一些新的需求，因为以前的项目中大量采用了圆角图片，并且这些图片全部采用了CSS sprites方式合并的图，为了不增加更多的额外工作，并且也不想用JS来添加更多的http请求，所以需要一些简单的CSS方案来解决这个问题。而我的个人爱好，也喜欢采用无图片的方式来处理这些效果。总觉得CSS能完成的工作，为什么不让它来实现呢？</p>
<p><strong>实现原理</strong>：</p>
<p>纯CSS方式实现圆角框的原理在网络上已经有很多人详细解说了，下面这个示意图是我将其中的一个圆角进行放大后的效果。</p>
<p><img src="http://www.blueidea.com/articleimg/2010/01/7347/01.png" border="0" alt="" width="451" height="321" /></p>
<p>图一</p>
<p>从上面效果图中我们可以看到其实这种圆角框是靠一个个容器堆砌而成的，每一个容器的宽度不同，这个宽度是由margin外边距来实现的，如：margin:0 5px;就是左右两侧的外边距5像素，从上到下有5条线，其外边距分别为5px，3px，2px，1px，依次递减。因此根据这个原理我们可以实现简单的html结构和样式。</p>
<p><strong>1、Html结构层：</strong></p>
<pre name="code" class="html">
&lt;div&gt;
       &lt;b&gt;&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;b&gt;&lt;/b&gt;
       &lt;div&gt;文字内容&lt;/div&gt;
       &lt;/div&gt;
       &lt;b&gt;&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;b&gt;&lt;/b&gt;  
&lt;/div&gt;
</pre>
<p>b1~b4构成上面的左右两个圆角结构体，而b5~b8则构建了下面左右两个圆角结构体。而content则是内容主体，将这些全部放在一个大的容器中，并给它的一个类名sharp，用来设置通用的样式。再给它叠加了一个color1类名，这个类名用来区别不同的颜色方案，因为可能会有不同颜色的圆角框。</p>
<p><strong>2、CSS样式：</strong></p>
<pre name="code" class="css">
.b1,.b2,.b3,.b4,.b5,.b6,.b7,.b8{height:1px; font-size:1px; overflow:hidden; display:block;}
.b1,.b8{margin:0 5px;}
.b2,.b7{margin:0 3px;border-right:2px solid; border-left:2px solid;}
.b3,.b6{margin:0 2px;border-right:1px solid; border-left:1px solid;}
.b4,.b5{margin:0 1px;border-right:1px solid; border-left:1px solid; height:2px;}
</pre>
<p>将每个b标签都设置为块状结构，并定义其高度为1像素，超出部分溢出隐藏。从上面样式中我们已经看到margin值的设置，是从大到小减少的。而b1和b8的设置是一样，已经将它们合并在一起了，同样的原理，b2和b7、b3和b6、b4和b5都是一样的设置。这是因为上面两个圆和下面的两个圆是一样，只是顺序是相对的，所以将它合并设置在一起。有利于减少CSS样式代码的字符大小。后面三句和第二句有点不同的地方是多设置了左右边框的样式，但是在这儿并没有设置边框的颜色，这是为什么呢，因为这个边框颜色是我们需要适时变化，所以将它们分离出来，在下面的代码中单独定义。</p>
<p>接下我们设置内容区的样式：</p>
<pre name="code" class="css">
.content {border-right:1px solid;border-left:1px solid;overflow:hidden;}
</pre>
<p>也是只设置左右边框线，但是不设置颜色值，它和上面八个b标签一起构成圆角框的外边框轮廓。</p>
<p>往往在一个页面中存在多个圆角框，而每个圆角框有可能其边框颜色各不相同，有没有可能针对不同的设计制作不同的换肤方案呢，答案是有的。在我的这个应用中，可以换不同的皮肤颜色，并且设置颜色方案也并不是一件很难的事情。下面看看我是如何将它们应用到不同的颜色的。</p>
<p>在上面的样式设计中，我已经给颜色方案留下了可以扩展的空间。我将所有的涉及到边框色的类名全部集中在一起，用群选择符给它们设置一个边框的颜色就可以了。如下所示：</p>
<pre name="code" class="css">
.color1 .b2,.color1 .b3,.color1 .b4,.color1 .b5,.color1 .b6,
.color1 .b7,.color1 .content{}{border-color:#96C2F1;}
.color1 .b1,.color1 .b8{background:#96C2F1;}
</pre>
<p>注意：需要将这两句的颜色值设置为一样的，第二句中虽说是设置的background背景色，但它同样是上下边框线的颜色，这一点一定要记住。因为b1和b8并没有设置border，但它的高度值为1px，所以用它的背景色就达到了模拟上下边框的颜色了。<br />
现在已经将一个圆角框描述出来了，但是有一个问题要注意，就是内容区的背景色，因为这儿是存载文字主体的地方。所以还需要加入下面这句话，也是群集选择符来设置圆角内的所有背景色。</p>
<pre name="code" class="css">
.color1 .b2,.color1 .b3,.color1 .b4,.color1 .b5,
.color1 .b6,.color1 .b7,.color1 .content{background:#EFF7FF;}
</pre>
<p>这儿除了b1和b8外，其它的标签都包含进来了，并且包括content容器，将它们的背景色全部设置一个颜色，这样除了线框外的所有地方都成为一种颜色了。在这儿我也用到包含选择符，给它们都加了一个color1，这是颜色方案1的类名，依照这个原理可以设置不同的换肤方案。</p>
<p>好了，我们将上面的所有代码集中起来，就完成一个纯CSS圆角框的实例模型，在源码中，我设置了六套颜色方案，其它的颜色方案就看你的了。</p>
<p>下面是源码演示后的截图：</p>
<p><img src="http://www.blueidea.com/articleimg/2010/01/7347/02.jpg" border="0" alt="" width="510" height="445" /></p>
<p>图二</p>
<p>为了演示效果，本模型的宽度值全部采用百分比实现的，你可以随意伸缩宽度，看看它能否适应弹性的变化。</p>
<p>本模型在以下浏览器中完美通过：<br />
<strong>IE5.5、IE6、IE7、IE8、FF3、TT、Maxthon2.1.5、Opera9.6、Safari4.0、Chrome2.0。</strong></p>
<p><a class="aligncenter" href="http://www.zfkun.com/soft/CSS_RoundAngle_1.rar" target="_blank">压缩包下载</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.zfkun.com/blog/index.php/archives/87/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MyEclipse 8.0 GA 下载合集</title>
		<link>http://www.zfkun.com/blog/index.php/archives/83</link>
		<comments>http://www.zfkun.com/blog/index.php/archives/83#comments</comments>
		<pubDate>Wed, 20 Jan 2010 05:14:20 +0000</pubDate>
		<dc:creator>影之迷惑</dc:creator>
				<category><![CDATA[Resource]]></category>
		<category><![CDATA[eclipse]]></category>
		<category><![CDATA[ga]]></category>
		<category><![CDATA[myeclipse]]></category>

		<guid isPermaLink="false">http://www.zfkun.com/blog/?p=83</guid>
		<description><![CDATA[MyEclipse官方放出了最新版本的MyEclipse 8.0 GA 系列下载(国内无法访问MyEclipse站点需代理）。直接复制下载链接地址到下载工具中。下载后请使用MD5校验工具校验下文件的有效性。]]></description>
			<content:encoded><![CDATA[<p>MyEclipse官方放出了最新版本的MyEclipse 8.0 GA 系列下载(国内无法访问MyEclipse站点需代理）。直接复制下载链接地址到下载工具中。下载后请使用MD5校验工具校验下文件的有效性。</p>
<ol>
<li><strong>MyEclipse 8.0 GA Windows 版本下载</strong>，支持 window 7/Vista/XP/NT/2000/98
<ul>
<li><a href="http://downloads.myeclipseide.com/downloads/products/eworkbench/galileo/myeclipse-8.0.0-win32.exe" target="_blank">download</a></li>
<li>MyEclipse 8.0 GA Windows 版文件大小：782.47 MB</li>
<li>MyEclipse 8.0 GA Windows 版MD5 : 3ace64b656a7ca57f1628633d87d167b</li>
</ul>
</li>
<li><strong>MyEclipse 8.0 GA Linux 版本下载</strong>(支持32位Linux版本)
<ul>
<li><a href="http://downloads.myeclipseide.com/downloads/products/eworkbench/galileo/myeclipse-8.0.0-linux-gtk-x86.tgz" target="_blank">download</a></li>
<li>MyEclipse 8.0 GA Linux 版（32位）文件大小：818.18 MB</li>
<li>MyEclipse 8.0 GA Linux 版（32位）MD5 : 32Bit:8c2404849a638a139855e4c2a12bd719</li>
</ul>
</li>
<li><strong>MyEclipse 8.0 GA Linux 版本下载</strong>(支持64位Linux版本)
<ul>
<li><a href="http://downloads.myeclipseide.com/downloads/products/eworkbench/galileo/myeclipse-8.0.0-linux-gtk-x86_64.tgz" target="_blank">download</a></li>
<li>MyEclipse 8.0 GA Linux 版（64位）文件大小：818.18 MB</li>
<li>MyEclipse 8.0 GA Linux 版（64位）MD5 : 64Bit:79fd08a2c57d30aa4d58b27d61675bb0</li>
</ul>
</li>
<li><strong>MyEclipse 8.0 GA Mac OS/X版本下载</strong>
<ul>
<li><a href="http://downloads.myeclipseide.com/downloads/products/eworkbench/galileo/myeclipse-8.0.0-macosx.tgz" target="_blank">download</a></li>
<li>MyEclipse 8.0 GA Mac OS/X版 文件大小：722.15 MB</li>
<li>MyEclipse 8.0 GA Mac OS/X版 MD5 : 9a119fc2219eebbc2bd28d66919e577f</li>
</ul>
</li>
<li><strong>MyEclipse 8.0 GA 归档升级版本下载</strong>
<ul>
<li><a href="http://downloads.myeclipseide.com/downloads/products/eworkbench/galileo/myeclipse-8.0.0-archived-update-site.zip" target="_blank">download</a></li>
<li>MyEclipse 8.0 GA 归档升级版本 文件大小：661.67 MB</li>
<li>MyEclipse 8.0 GA 归档升级版本 MD5 : 50a87f85f63179aad44299518d9bb441</li>
</ul>
</li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://www.zfkun.com/blog/index.php/archives/83/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
