<?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>haohtml&#039;s blog &#187; php</title>
	<atom:link href="http://blog.haohtml.com/index.php/tag/php/feed" rel="self" type="application/rss+xml" />
	<link>http://blog.haohtml.com</link>
	<description>haohtml&#039;s life and works blog</description>
	<lastBuildDate>Sat, 31 Jul 2010 10:45:51 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>PHP Warning: date() [function.date]: It is not safe是什么问题</title>
		<link>http://blog.haohtml.com/index.php/archives/4837</link>
		<comments>http://blog.haohtml.com/index.php/archives/4837#comments</comments>
		<pubDate>Tue, 27 Jul 2010 04:46:51 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[网络编程]]></category>
		<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://blog.haohtml.com/?p=4837</guid>
		<description><![CDATA[在用PHP5.3以上的PHP版本时，只要是涉及时间的会报一个&#8221;PHP Warning: date() [function.date]: It is not safe to rely on the system&#8217;s timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected &#8216;UTC&#8217; for &#8217;8.0/no DST&#8217; [...]]]></description>
			<content:encoded><![CDATA[<p><span style="font-size: small;"><strong>在用PHP5.3以上的PHP版本时，只要是涉及时间的会报一个&#8221;</strong>PHP Warning: date() [function.date]: It is not safe to rely on the system&#8217;s timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected &#8216;UTC&#8217; for &#8217;8.0/no DST&#8217; instead in<strong>&#8220;这样的错。如何解决呢？</strong></span></p>
<p><span style="font-size: small;"><strong>实际上，从 PHP 5.1.0 ，当对使用date（）等函数时，如果timezone设置不正确，在每一次调用时间函数时,都会产生<strong><tt>E_NOTICE</tt></strong> 或者 <strong><tt>E_WARNING</tt></strong> 信息。而又在<span style="font-family: Arial;">php5.1.0 中，date.timezone这个选项，默认情况下是关闭的，无论用什么php命令都是格林威治标准时间，但是</span></strong>PHP5.3 中好像如果没有设置也会强行抛出了这个错误的,解决此问题，只要本地化一下，就行了。</span></p>
<p><span style="font-size: small;"><span style="color: #ff0000; font-size: medium;"><strong>以下 是两种方法(任选一种都 行)：</strong></span><br />
</span><strong></strong></p>
<p><span style="font-size: small;">一、在页头使用 date_default_timezone_set()设置</span></p>
<p><span style="font-size: small;">date_default_timezone_set(&#8216;PRC&#8217;); //东八时区<br />
echo date(&#8216;Y-m-d H:i:s&#8217;);</span></p>
<p><span id="more-4837"></span></p>
<p><span style="font-size: small;">二、修改php.ini。<br />
打开php5.ini查找date.timezone 去掉前面的分号　= 后面加XXX，重启http服务（如apache2或iis等）即可。</span></p>
<p><span style="font-size: small;">XXX可以任意正确的值。对于我们国内来 说：可以为以下值：Asia/Chongqing ，Asia/Shanghai ，Asia/Urumqi （依次为重庆，上海，乌鲁木齐）港台地区可用：Asia/Macao ，Asia/Hong_Kong ，Asia/Taipei （依次为澳门，香港，台北），还有新加坡：Asia/Singapore，当然PRC也行。</span></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.haohtml.com/index.php/archives/4837/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PHP新的垃圾回收机制:Zend GC详解</title>
		<link>http://blog.haohtml.com/index.php/archives/4794</link>
		<comments>http://blog.haohtml.com/index.php/archives/4794#comments</comments>
		<pubDate>Sun, 25 Jul 2010 10:53:31 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[网络编程]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[内存管理]]></category>

		<guid isPermaLink="false">http://blog.haohtml.com/?p=4794</guid>
		<description><![CDATA[http://blog.csdn.net/phpkernel/archive/2010/07/14/5734743.aspx]]></description>
			<content:encoded><![CDATA[<p><a href="http://blog.csdn.net/phpkernel/archive/2010/07/14/5734743.aspx" target="_blank">http://blog.csdn.net/phpkernel/archive/2010/07/14/5734743.aspx</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.haohtml.com/index.php/archives/4794/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>深入理解PHP中的匿名函数</title>
		<link>http://blog.haohtml.com/index.php/archives/4790</link>
		<comments>http://blog.haohtml.com/index.php/archives/4790#comments</comments>
		<pubDate>Sun, 25 Jul 2010 10:30:00 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[网络编程]]></category>
		<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://blog.haohtml.com/?p=4790</guid>
		<description><![CDATA[匿名函数的作用就是扩大函数的使用功能，在PHP 5.3以前，传递Callback的方式，我们只有俩种选择： ◆字符串的函数名 ◆使用create_function的返回 在PHP5.3以后, 我们多了一个选择, 也就是Closure。 1. $func = function () { &#8230; }; 2. array_walk($arr, $func); 从实现上来说, 第一种方式: 传递函数名字符串是最简单的。而第二种方式create_function, 其实和第一种方式本质上一样的, create_function返回一个字符串的函数名, 这个函数名的格式是: 1. &#8220;\000_lambda_&#8221; . count(anonymous_functions)++ 我们来看看create_function的实现步骤： 1. 获取参数, 函数体; 2. 拼凑一个&#8221;function __lambda_func (参数) { 函数体;} &#8220;的字符串; 3. eval; 4. 通过__lambda_func在函数表中找到eval后得到的函数体, 找不到就出错; 5. 定义一个函数名:&#8221;\000_lambda_&#8221; . count(anonymous_functions)++; 6. 用新的函数名替换__lambda_func; 7. 返回新的函数。 我们来验证下： 1. 5. [...]]]></description>
			<content:encoded><![CDATA[<p>匿名函数的作用就是扩大函数的使用功能，在PHP 5.3以前，传递Callback的方式，我们只有俩种选择：</p>
<p>◆字符串的函数名</p>
<p>◆使用create_function的返回</p>
<p>在PHP5.3以后, 我们多了一个选择, 也就是Closure。</p>
<p>1. $func = function () { &#8230; };</p>
<p>2. array_walk($arr, $func);</p>
<p>从实现上来说, 第一种方式: 传递函数名字符串是最简单的。而第二种方式create_function, 其实和第一种方式本质上一样的, create_function返回一个字符串的函数名, 这个函数名的格式是:<span id="more-4790"></span></p>
<p>1. &#8220;\000_lambda_&#8221; . count(anonymous_functions)++</p>
<p>我们来看看create_function的实现步骤：</p>
<p>1. 获取参数, 函数体;</p>
<p>2. 拼凑一个&#8221;function __lambda_func (参数) { 函数体;} &#8220;的字符串;</p>
<p>3. eval;</p>
<p>4. 通过__lambda_func在函数表中找到eval后得到的函数体, 找不到就出错;</p>
<p>5. 定义一个函数名:&#8221;\000_lambda_&#8221; . count(anonymous_functions)++;</p>
<p>6. 用新的函数名替换__lambda_func;</p>
<p>7. 返回新的函数。</p>
<p>我们来验证下：</p>
<p>1.</p>
<p>5. //输出  __lambda_fun</p>
<p>因为在eval的时候, 函数名是”__lambda_func”, 所以匿名函数内会输出__lambda_func, 而因为最后用”\000_lambda_”.count(anonymous_functions)++重命名了函数表中的”__lambda_func”函数, 所以可通过”\000_lambda_” . count(anonymous_functions)++调用这个匿名函数。为了证实这一点, 可以将create_function的返回值dump出来查看。</p>
<p>而在PHP 5.3发布的时候, 其中有一条new feature就是支持闭包/Lambda Function, 我第一反应是以为zval新增了一个IS_FUNCTION, 但实际上是构造了一个PHP 5.3引入的Closure”类”的实例, Closure类的构造函数是私有的, 所以不能被直接实例化, 另外Closure类是Final类, 所以也不能做为基类派生子类.</p>
<p>1. //php-5.3.0</p>
<p>2. $class = new ReflectionClass(&#8220;Closure&#8221;);</p>
<p>3. var_dump($class-&gt;isInternal());</p>
<p>4. var_dump($class-&gt;isAbstract() );</p>
<p>5. var_dump($class-&gt;isFinal());</p>
<p>6. var_dump($class-&gt;isInterface());</p>
<p>7. //输出:</p>
<p>8. bool(true)</p>
<p>9. bool(false)</p>
<p>10. bool(true)</p>
<p>11. bool(false)</p>
<p>12. ?&gt;</p>
<p>而PHP 5.3中对闭包的支持, 也仅仅是把要保持的外部变量, 做为Closure对象的”Static属性”(并不是普通意义上的可遍历/访问的属性).</p>
<p>1. //php-5.3.0</p>
<p>2. $b = &#8220;laruence&#8221;;</p>
<p>3. $func = function($a) use($b) {};</p>
<p>4. var_dump($func);</p>
<p>5. /* 输出:</p>
<p>6. object(Closure)#1 (2) {</p>
<p>7. ["static"]=&gt;</p>
<p>8.  array(1) {</p>
<p>9. ["b"]=&gt; string(8) &#8220;laruence&#8221;</p>
<p>10. }</p>
<p>11. ["parameter"]=&gt;</p>
<p>12. array(1) {</p>
<p>13.  ["$a"]=&gt; string(10) &#8220;&#8221;</p>
<p>14.  }</p>
<p>15.  }</p>
<p>16.  */</p>
<p>这个实现, 个人认为和JS对闭包的支持比起来, 还是有些太简陋了。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.haohtml.com/index.php/archives/4790/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>深入理解PHP原理之变量生命期(一)</title>
		<link>http://blog.haohtml.com/index.php/archives/4786</link>
		<comments>http://blog.haohtml.com/index.php/archives/4786#comments</comments>
		<pubDate>Sun, 25 Jul 2010 07:25:12 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[网络编程]]></category>
		<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://blog.haohtml.com/?p=4786</guid>
		<description><![CDATA[作者: laruence(http://www.laruence.com) 本文地址: http://www.laruence.com/2009/12/26/1198.html 转载请注明出处 对于PHP的中的数据来源, 不外乎有俩种: 1. 来自代码中 2. 来自外部(GET/POST/DB) 对于代码中的变量(也就是直接量)来说, 变量分配/赋值在编译期, 活跃在执行器, 在请求关闭期被销毁.对于这些变量来说, 使用APC进行Opcode缓存, 则会缓存这部分变量的值. 而对于来自外部的变量, 变量分配/赋值在编译器后, 执行期前, 在请求关闭期被销毁,对于这些变量来说, 使用APC进行OpCode缓存, 是不会被缓存的. 今天就着重关注下外部变量的一个部分,GET来的数据的整个生命周期. 假设, 有如下请求到来:      GET /index.php?name=laruence&#38;career[]=yahoo&#38;career[]=baidu 而, 在index.php中: &#60;?php      $name      = $_GET['name'];      $career = $_GET['career']; //array 我们知道, 在最后的执行期, $_GET数组必然包含如下片段:      $_GET = array(           'name' =&#62; 'laruence',           'career' =&#62; array(                'yahoo', 'baidu',           ),      ) 那么, [...]]]></description>
			<content:encoded><![CDATA[<div>
<ul>
<li>作者: laruence(<a title="风雪之隅" href="http://www.laruence.com/" target="_blank">http://www.laruence.com</a>)</li>
<li>本文地址: <a title="Permanet Link to 深入理解PHP原理之变量生命期(一)" href="http://www.laruence.com/2009/12/26/1198.html">http://www.laruence.com/2009/12/26/1198.html</a></li>
<li>转载请注明出处</li>
</ul>
</div>
<p>对于PHP的中的数据来源, 不外乎有俩种:</p>
<pre>
<ol>
<li>1. 来自代码中</li>
<li>2. 来自外部(GET/POST/DB)</li>
</ol>
</pre>
<p>对于代码中的变量(也就是直接量)来说, 变量分配/赋值在编译期, 活跃在执行器, 在请求关闭期被销毁.对于这些变量来说, 使用APC进行Opcode缓存, 则会缓存这部分变量的值.<span id="more-4786"></span><!--more--></p>
<p>而对于来自外部的变量, 变量分配/赋值在编译器后, 执行期前, 在请求关闭期被销毁,对于这些变量来说, 使用APC进行OpCode缓存, 是不会被缓存的.</p>
<p>今天就着重关注下外部变量的一个部分,GET来的数据的整个生命周期.</p>
<p>假设, 有如下请求到来:</p>
<pre>
<ol>
<li>     GET /index.php?name=laruence&amp;career[]=yahoo&amp;career[]=baidu</li>
</ol>
</pre>
<p>而, 在index.php中:</p>
<pre>
<ol>
<li>&lt;?php</li>
<li>     $name      = $_GET['name'];</li>
<li>     $career = $_GET['career']; //array</li>
</ol>
</pre>
<p>我们知道, 在最后的执行期, $_GET数组必然包含如下片段:</p>
<pre>
<ol>
<li>     $_GET = array(</li>
<li>          'name'   =&gt; 'laruence',</li>
<li>          'career' =&gt; array(</li>
<li>               'yahoo', 'baidu',</li>
<li>          ),</li>
<li>     )</li>
</ol>
</pre>
<p>那么, 我们今天就重点关注下, Query String是如何构建成_GET数组的(关于GET变量的生成, 请一并阅读我之前的文章: “<a href="http://www.laruence.com/2008/11/07/581.html" target="_blank">PHP的GET/POST等大变量生成过程</a>“):</p>
<p>在请求到来时刻,php_request_startup(定义在main.c)被调用,来做初始化现场. 在这个过程中包括设置超时值,调用各个模块的请求初始化函数. 当然也包括我们关心的, 创建变量环境.</p>
<p>php_hash_environment根据php.ini中的variables_order来依次初始化各个预定义大变量, 那么对于$_GET来说:</p>
<pre>
<ol>
<li>...</li>
<li>case 'g':</li>
<li>case 'G':</li>
<li>     if (!_gpc_flags[2]) {</li>
<li>          sapi_module.treat_data(PARSE_GET, NULL, NULL TSRMLS_CC);</li>
<li>          _gpc_flags[2] = 1;</li>
<li>          if (PG(register_globals)) {</li>
<li>               php_autoglobal_merge(&amp;EG(symbol_table),</li>
<li>                    Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_GET]) TSRMLS_CC);</li>
<li>          }</li>
<li>     }</li>
<li>break;</li>
<li>...</li>
</ol>
</pre>
<p>大体可以看出,这段逻辑,首先通过treat_data来生成变量hash(PG(http_globals)[TRACK_VARS_GET]), 如果打开了auto_register_globals,则再把$_GET数组中的变量加入到符号表中.</p>
<p>treat_data是属于sapi_module_struct中的一个成员:</p>
<pre>
<ol>
<li> 注意:     本文基于apache2handler方式的sapi, 这个启动过程和之前的文章sapi</li>
<li>原理中的启动过程略有不同, php5通过注册apache2的ap_hook_post_config挂钩,</li>
<li>在apache server启动的时候启动php(php_apache_server_startup,定义在</li>
<li>sapi/apache2hander/sapi_apache2.c中), 在这个函数中调用sapi_startup启动sapi,</li>
<li>继而通过调用php_apache2_startup来注册sapi module struct,</li>
<li>然后调用php_module_startup来初始化PHP, 其中又会初始化ZEND引擎,</li>
<li>以及填充zend_module_struct中的treat_data成员(通过php_startup_sapi_content_types)</li>
<li>为php_default_treat_data</li>
</ol>
</pre>
<p>现在回过头来继续看treat_data(也就是php_default_treat_data):</p>
<pre>
<ol>
<li>....</li>
<li>if (arg == PARSE_GET) {     /* GET data */</li>
<li>     c_var = SG(request_info).query_string;</li>
<li>     if (c_var &amp;&amp; *c_var) {</li>
<li>          res = (char *) estrdup(c_var);</li>
<li>          free_buffer = 1;</li>
<li>     } else {</li>
<li>          free_buffer = 0;</li>
<li>     }</li>
<li>} else if (arg == PARSE_COOKIE) {       /* Cookie data */</li>
<li>....</li>
</ol>
</pre>
<p>在上面的逻辑中, 给res复制为query_string, SG(request_info)是一个代表了当前请求信息的结构体,  其中query_string是在php_apache_request_ctor中通过复制apache的reqeust_rec结构体中的args而 来的.</p>
<p>对于本文的例子来说, 此时res即为”name=laruence&amp;career[]=yahoo&amp;career[]=baidu”,</p>
<p>继续在treat_data中, 随后的逻辑是:</p>
<pre>
<ol>
<li>var = php_strtok_r(res, separator, &amp;strtok_buf);</li>
<li>...</li>
<li>while (var) {</li>
<li>     val = strchr(var, '=');</li>
<li>     if (arg == PARSE_COOKIE) {</li>
<li>          /* Remove leading spaces from cookie names,</li>
<li>               needed for multi-cookie header where ; can be followed by a space */</li>
<li>          while (isspace(*var)) {</li>
<li>               var++;</li>
<li>          }</li>
<li>          if (var == val || *var == '\0') {</li>
<li>               goto next_cookie;</li>
<li>          }</li>
<li>     }</li>
<li>     if (val) { /* have a value */</li>
<li>          int val_len;</li>
<li>          unsigned int new_val_len;</li>
<li>          *val++ = '\0';</li>
<li>          php_url_decode(var, strlen(var));</li>
<li>          val_len = php_url_decode(val, strlen(val));</li>
<li>          val = estrndup(val, val_len);</li>
<li>          if (sapi_module.input_filter(arg, var, &amp;val, val_len, &amp;new_val_len TSRMLS_CC)) {</li>
<li>               php_register_variable_safe(var, val, new_val_len, array_ptr TSRMLS_CC);</li>
<li>          }</li>
<li>          efree(val);</li>
<li>     } else {</li>
<li>...</li>
</ol>
</pre>
<p>首先, 通过php_strtok_r把res根据”&amp;”分割成一个一个的”key=value”段, 接下来分别为var和val复制为key和value, 注意到这个过程中会分别对var和val做php_url_decode.</p>
<p>最后通过php_register_variable_safe, 给array_ptr(此时指向PG(http_globals)[TRACK_VARS_GET], 也就是$_GET)添加一个名为var值为val的成员.</p>
<p>到了这一步, 我们的$_GET数组中, 就包含了如下的成员:</p>
<pre>
<ol>
<li>'name'   =&gt; 'laruence',</li>
<li>'career' =&gt; array(</li>
<li>     'yahoo', 'baidu',</li>
<li>),</li>
</ol>
</pre>
<p>未完待续(变量的销毁过程)…</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.haohtml.com/index.php/archives/4786/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>php 中BMP转jpg或者其它任何格式</title>
		<link>http://blog.haohtml.com/index.php/archives/4716</link>
		<comments>http://blog.haohtml.com/index.php/archives/4716#comments</comments>
		<pubDate>Tue, 20 Jul 2010 04:47:18 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[网络编程]]></category>
		<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://blog.haohtml.com/?p=4716</guid>
		<description><![CDATA[function ImageCreateFromBMP( $filename ) { // Ouverture du fichier en mode binaire if ( ! $f1 = fopen ( $filename , &#8220;rb&#8221; )) return FALSE ; // 1 : Chargement des ent�tes FICHIER $FILE = unpack ( &#8220;vfile_type/Vfile_size/Vreserved/Vbitmap_offset&#8221; , fread ( $f1 , 14 )); if ( $FILE [ 'file_type' ] != 19778 ) return [...]]]></description>
			<content:encoded><![CDATA[<blockquote><p>function ImageCreateFromBMP( $filename )<br />
{<br />
// Ouverture du fichier en mode binaire<br />
if ( ! $f1 = fopen ( $filename , &#8220;rb&#8221; )) return FALSE ;<br />
// 1 : Chargement des ent�tes FICHIER<br />
$FILE = unpack ( &#8220;vfile_type/Vfile_size/Vreserved/Vbitmap_offset&#8221; , fread ( $f1 , 14 ));<br />
if ( $FILE [ 'file_type' ] != 19778 ) return FALSE ;<br />
// 2 : Chargement des ent�tes BMP<br />
$BMP = unpack ( &#8216;Vheader_size/Vwidth/Vheight/vplanes/vbits_per_pixel&#8217; . &#8216;/Vcompression/Vsize_bitmap/Vhoriz_resolution&#8217; .<br />
&#8216;/Vvert_resolution/Vcolors_used/Vcolors_important&#8217; , fread ( $f1 , 40 ));<br />
$BMP [ 'colors' ] = pow ( 2 , $BMP [ 'bits_per_pixel' ]);<br />
if ( $BMP [ 'size_bitmap' ] == 0 ) $BMP [ 'size_bitmap' ] = $FILE [ 'file_size' ] &#8211; $FILE [ 'bitmap_offset' ];<br />
$BMP [ 'bytes_per_pixel' ] = $BMP [ 'bits_per_pixel' ] / 8 ;<br />
$BMP [ 'bytes_per_pixel2' ] = ceil ( $BMP [ 'bytes_per_pixel' ]);<br />
$BMP [ 'decal' ] = ( $BMP [ 'width' ] * $BMP [ 'bytes_per_pixel' ] / 4 );<br />
$BMP [ 'decal' ] -= floor ( $BMP [ 'width' ] * $BMP [ 'bytes_per_pixel' ] / 4 );<br />
$BMP [ 'decal' ] = 4 &#8211; ( 4 * $BMP [ 'decal' ]);<br />
if ( $BMP [ 'decal' ] == 4 ) $BMP [ 'decal' ] = 0 ;<br />
// 3 : Chargement des couleurs de la palette<br />
$PALETTE = array ();<br />
if ( $BMP [ 'colors' ] &lt; 16777216 )<br />
{<br />
$PALETTE = unpack ( &#8216;V&#8217; . $BMP [ 'colors' ] , fread ( $f1 , $BMP [ 'colors' ] * 4 ));<br />
}<br />
// 4 : Cr�ation de l&#8217;image<br />
$IMG = fread ( $f1 , $BMP [ 'size_bitmap' ]);<br />
$VIDE = chr ( 0 );<br />
$res = imagecreatetruecolor( $BMP [ 'width' ] , $BMP [ 'height' ]);<br />
$P = 0 ;<br />
$Y = $BMP [ 'height' ] &#8211; 1 ;<br />
while ( $Y &gt;= 0 )<br />
{<br />
$X = 0 ;<br />
while ( $X &lt; $BMP [ 'width' ])<br />
{<br />
if ( $BMP [ 'bits_per_pixel' ] == 24 )<br />
$COLOR = unpack ( &#8220;V&#8221; , substr ( $IMG , $P , 3 ) . $VIDE );<br />
elseif ( $BMP [ 'bits_per_pixel' ] == 16 )<br />
{<br />
$COLOR = unpack ( &#8220;n&#8221; , substr ( $IMG , $P , 2 ));<br />
$COLOR [ 1 ] = $PALETTE [ $COLOR [ 1 ] + 1 ];<br />
}<br />
elseif ( $BMP [ 'bits_per_pixel' ] == 8 )<br />
{<br />
$COLOR = unpack ( &#8220;n&#8221; , $VIDE . substr ( $IMG , $P , 1 ));<br />
$COLOR [ 1 ] = $PALETTE [ $COLOR [ 1 ] + 1 ];<br />
}<br />
elseif ( $BMP [ 'bits_per_pixel' ] == 4 )<br />
{<br />
$COLOR = unpack ( &#8220;n&#8221; , $VIDE . substr ( $IMG , floor ( $P ) , 1 ));<br />
if (( $P * 2 ) % 2 == 0 ) $COLOR [ 1 ] = ( $COLOR [ 1 ] &gt;&gt; 4 ) ; else $COLOR [ 1 ] = ( $COLOR [ 1 ] &amp; 0x0F );<br />
$COLOR [ 1 ] = $PALETTE [ $COLOR [ 1 ] + 1 ];<br />
}<br />
elseif ( $BMP [ 'bits_per_pixel' ] == 1 )<br />
{<br />
$COLOR = unpack ( &#8220;n&#8221; , $VIDE . substr ( $IMG , floor ( $P ) , 1 ));<br />
if (( $P * 8 ) % 8 == 0 ) $COLOR [ 1 ] = $COLOR [ 1 ] &gt;&gt; 7 ;<br />
elseif (( $P * 8 ) % 8 == 1 ) $COLOR [ 1 ] = ( $COLOR [ 1 ] &amp; 0&#215;40 ) &gt;&gt; 6 ;<br />
elseif (( $P * 8 ) % 8 == 2 ) $COLOR [ 1 ] = ( $COLOR [ 1 ] &amp; 0&#215;20 ) &gt;&gt; 5 ;<br />
elseif (( $P * 8 ) % 8 == 3 ) $COLOR [ 1 ] = ( $COLOR [ 1 ] &amp; 0&#215;10 ) &gt;&gt; 4 ;<br />
elseif (( $P * 8 ) % 8 == 4 ) $COLOR [ 1 ] = ( $COLOR [ 1 ] &amp; 0&#215;8 ) &gt;&gt; 3 ;<br />
elseif (( $P * 8 ) % 8 == 5 ) $COLOR [ 1 ] = ( $COLOR [ 1 ] &amp; 0&#215;4 ) &gt;&gt; 2 ;<br />
elseif (( $P * 8 ) % 8 == 6 ) $COLOR [ 1 ] = ( $COLOR [ 1 ] &amp; 0&#215;2 ) &gt;&gt; 1 ;<br />
elseif (( $P * 8 ) % 8 == 7 ) $COLOR [ 1 ] = ( $COLOR [ 1 ] &amp; 0&#215;1 );<br />
$COLOR [ 1 ] = $PALETTE [ $COLOR [ 1 ] + 1 ];<br />
}<br />
else<br />
return FALSE ;<br />
imagesetpixel( $res , $X , $Y , $COLOR [ 1 ]);<br />
$X ++ ;<br />
$P += $BMP [ 'bytes_per_pixel' ];<br />
}<br />
$Y &#8212; ;<br />
$P += $BMP [ 'decal' ];<br />
}<br />
// Fermeture du fichier<br />
fclose ( $f1 );<br />
return $res ;<br />
}</p>
<p>function ImageCreateFromBMP( $filename )<br />
{<br />
// Ouverture du fichier en mode binaire<br />
if ( ! $f1 = fopen ( $filename , &#8220;rb&#8221; )) return FALSE ;<br />
// 1 : Chargement des ent�tes FICHIER<br />
$FILE = unpack ( &#8220;vfile_type/Vfile_size/Vreserved/Vbitmap_offset&#8221; , fread ( $f1 , 14 ));<br />
if ( $FILE [ 'file_type' ] != 19778 ) return FALSE ;<br />
// 2 : Chargement des ent�tes BMP<br />
$BMP = unpack ( &#8216;Vheader_size/Vwidth/Vheight/vplanes/vbits_per_pixel&#8217; . &#8216;/Vcompression/Vsize_bitmap/Vhoriz_resolution&#8217; .<br />
&#8216;/Vvert_resolution/Vcolors_used/Vcolors_important&#8217; , fread ( $f1 , 40 ));<br />
$BMP [ 'colors' ] = pow ( 2 , $BMP [ 'bits_per_pixel' ]);<br />
if ( $BMP [ 'size_bitmap' ] == 0 ) $BMP [ 'size_bitmap' ] = $FILE [ 'file_size' ] &#8211; $FILE [ 'bitmap_offset' ];<br />
$BMP [ 'bytes_per_pixel' ] = $BMP [ 'bits_per_pixel' ] / 8 ;<br />
$BMP [ 'bytes_per_pixel2' ] = ceil ( $BMP [ 'bytes_per_pixel' ]);<br />
$BMP [ 'decal' ] = ( $BMP [ 'width' ] * $BMP [ 'bytes_per_pixel' ] / 4 );<br />
$BMP [ 'decal' ] -= floor ( $BMP [ 'width' ] * $BMP [ 'bytes_per_pixel' ] / 4 );<br />
$BMP [ 'decal' ] = 4 &#8211; ( 4 * $BMP [ 'decal' ]);<br />
if ( $BMP [ 'decal' ] == 4 ) $BMP [ 'decal' ] = 0 ;<br />
// 3 : Chargement des couleurs de la palette<br />
$PALETTE = array ();<br />
if ( $BMP [ 'colors' ] &lt; 16777216 )<br />
{<br />
$PALETTE = unpack ( &#8216;V&#8217; . $BMP [ 'colors' ] , fread ( $f1 , $BMP [ 'colors' ] * 4 ));<br />
}<br />
// 4 : Cr�ation de l&#8217;image<br />
$IMG = fread ( $f1 , $BMP [ 'size_bitmap' ]);<br />
$VIDE = chr ( 0 );<br />
$res = imagecreatetruecolor( $BMP [ 'width' ] , $BMP [ 'height' ]);<br />
$P = 0 ;<br />
$Y = $BMP [ 'height' ] &#8211; 1 ;<br />
while ( $Y &gt;= 0 )<br />
{<br />
$X = 0 ;<br />
while ( $X &lt; $BMP [ 'width' ])<br />
{<br />
if ( $BMP [ 'bits_per_pixel' ] == 24 )<br />
$COLOR = unpack ( &#8220;V&#8221; , substr ( $IMG , $P , 3 ) . $VIDE );<br />
elseif ( $BMP [ 'bits_per_pixel' ] == 16 )<br />
{<br />
$COLOR = unpack ( &#8220;n&#8221; , substr ( $IMG , $P , 2 ));<br />
$COLOR [ 1 ] = $PALETTE [ $COLOR [ 1 ] + 1 ];<br />
}<br />
elseif ( $BMP [ 'bits_per_pixel' ] == 8 )<br />
{<br />
$COLOR = unpack ( &#8220;n&#8221; , $VIDE . substr ( $IMG , $P , 1 ));<br />
$COLOR [ 1 ] = $PALETTE [ $COLOR [ 1 ] + 1 ];<br />
}<br />
elseif ( $BMP [ 'bits_per_pixel' ] == 4 )<br />
{<br />
$COLOR = unpack ( &#8220;n&#8221; , $VIDE . substr ( $IMG , floor ( $P ) , 1 ));<br />
if (( $P * 2 ) % 2 == 0 ) $COLOR [ 1 ] = ( $COLOR [ 1 ] &gt;&gt; 4 ) ; else $COLOR [ 1 ] = ( $COLOR [ 1 ] &amp; 0x0F );<br />
$COLOR [ 1 ] = $PALETTE [ $COLOR [ 1 ] + 1 ];<br />
}<br />
elseif ( $BMP [ 'bits_per_pixel' ] == 1 )<br />
{<br />
$COLOR = unpack ( &#8220;n&#8221; , $VIDE . substr ( $IMG , floor ( $P ) , 1 ));<br />
if (( $P * 8 ) % 8 == 0 ) $COLOR [ 1 ] = $COLOR [ 1 ] &gt;&gt; 7 ;<br />
elseif (( $P * 8 ) % 8 == 1 ) $COLOR [ 1 ] = ( $COLOR [ 1 ] &amp; 0&#215;40 ) &gt;&gt; 6 ;<br />
elseif (( $P * 8 ) % 8 == 2 ) $COLOR [ 1 ] = ( $COLOR [ 1 ] &amp; 0&#215;20 ) &gt;&gt; 5 ;<br />
elseif (( $P * 8 ) % 8 == 3 ) $COLOR [ 1 ] = ( $COLOR [ 1 ] &amp; 0&#215;10 ) &gt;&gt; 4 ;<br />
elseif (( $P * 8 ) % 8 == 4 ) $COLOR [ 1 ] = ( $COLOR [ 1 ] &amp; 0&#215;8 ) &gt;&gt; 3 ;<br />
elseif (( $P * 8 ) % 8 == 5 ) $COLOR [ 1 ] = ( $COLOR [ 1 ] &amp; 0&#215;4 ) &gt;&gt; 2 ;<br />
elseif (( $P * 8 ) % 8 == 6 ) $COLOR [ 1 ] = ( $COLOR [ 1 ] &amp; 0&#215;2 ) &gt;&gt; 1 ;<br />
elseif (( $P * 8 ) % 8 == 7 ) $COLOR [ 1 ] = ( $COLOR [ 1 ] &amp; 0&#215;1 );<br />
$COLOR [ 1 ] = $PALETTE [ $COLOR [ 1 ] + 1 ];<br />
}<br />
else<br />
return FALSE ;<br />
imagesetpixel( $res , $X , $Y , $COLOR [ 1 ]);<br />
$X ++ ;<br />
$P += $BMP [ 'bytes_per_pixel' ];<br />
}<br />
$Y &#8212; ;<br />
$P += $BMP [ 'decal' ];<br />
}<br />
// Fermeture du fichier<br />
fclose ( $f1 );<br />
return $res ;<br />
}</p></blockquote>
<p>用法：</p>
<blockquote><p>$src_img = &#8220;testA.bmp&#8221;;//源图片<br />
$dst_img = &#8220;testB.jpg&#8221;; //目标图片<br />
$mi = ImageCreateFromBMP( $src_img );<br />
imagejpeg( $mi , $dst_img );<br />
imagedestroy($mi );//释放内存</p></blockquote>
<p>可以把其它格式，如 png,bmp,gif 等转换为 jpg 格式</p>
<blockquote><p>//把其它图片格式转化为 jpg<br />
function ImageToJPG($srcFile,$dstFile)<br />
{<br />
$quality=90;<br />
$data = @GetImageSize($srcFile);<br />
switch ($data['2'])<br />
{<br />
case 1:<br />
$im = imagecreatefromgif($srcFile);<br />
break;<br />
case 2:<br />
$im = imagecreatefromjpeg($srcFile);<br />
break;<br />
case 3:<br />
$im = imagecreatefrompng($srcFile);<br />
break;<br />
case 6:<br />
$im = ImageCreateFromBMP( $srcFile );<br />
break;<br />
}<br />
$dstX=$srcW=@ImageSX($im);<br />
$dstY=$srcH=@ImageSY($im);</p>
<p>$ni=@imageCreateTrueColor($dstX,$dstY);<br />
@ImageCopyResampled($ni,$im,0,0,0,0,$dstX,$dstY,$srcW,$srcH);<br />
@ImageJpeg($ni,$dstFile,$quality);<br />
@imagedestroy($im);<br />
@imagedestroy($ni);<br />
}</p></blockquote>
]]></content:encoded>
			<wfw:commentRss>http://blog.haohtml.com/index.php/archives/4716/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Php操作JSON</title>
		<link>http://blog.haohtml.com/index.php/archives/4592</link>
		<comments>http://blog.haohtml.com/index.php/archives/4592#comments</comments>
		<pubDate>Tue, 13 Jul 2010 01:07:37 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[网络编程]]></category>
		<category><![CDATA[json]]></category>
		<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://blog.haohtml.com/?p=4592</guid>
		<description><![CDATA[整理两个现成的函数：json_decode、json_encode 说明：其中json_encode 表示把常用的传统的数据类型如对象、数组、关联数组等转成JSON字符串。其实与JAVA里面的那个工具是一样的。而json_decode刚好相反。 解决需求1.修改数据表的时候动态生成一个JSON片段。供JS调用。 服务器端的代码： function plan2() { $link = mysql_connect(&#8220;localhost&#8221;,&#8221;root&#8221;,&#8221;123&#8243;) or die(&#8220;&#60;font color=red&#62;无法建立起来连接。错误信息如下&#60;/font&#62;&#8221;); mysql_query(&#8220;SET NAMES gbk&#8221;); mysql_select_db(&#8220;phpcms&#8221;,$link) or die(&#8220;&#60;font color=red&#62;在服务器上面无法找到此请确认已建立此DB &#8220;); $result = mysql_query(&#8220;select id,uuid,uuidtable from dytable &#8220;); $num_rows = @mysql_num_rows($result); //看一下返回多少行记录 if ($num_rows == 0) { $b = array();         //这样长度为0 返回的是一个空数组 }else{ while ($row = mysql_fetch_array($result,MYSQL_ASSOC)){ $b[] = $row; [...]]]></description>
			<content:encoded><![CDATA[<div id="_mcePaste">整理两个现成的函数：json_decode、json_encode</div>
<div id="_mcePaste">说明：其中json_encode 表示把常用的传统的数据类型如对象、数组、关联数组等转成JSON字符串。其实与JAVA里面的那个工具是一样的。而json_decode刚好相反。</div>
<div id="_mcePaste">解决需求1.修改数据表的时候动态生成一个JSON片段。供JS调用。</div>
<div id="_mcePaste">服务器端的代码：</div>
<div id="_mcePaste">function plan2() {</div>
<div id="_mcePaste">$link = mysql_connect(&#8220;localhost&#8221;,&#8221;root&#8221;,&#8221;123&#8243;) or die(&#8220;&lt;font color=red&gt;无法建立起来连接。错误信息如下&lt;/font&gt;&#8221;);</div>
<div id="_mcePaste">mysql_query(&#8220;SET NAMES gbk&#8221;);</div>
<div id="_mcePaste">mysql_select_db(&#8220;phpcms&#8221;,$link) or die(&#8220;&lt;font color=red&gt;在服务器上面无法找到此请确认已建立此DB &#8220;);</div>
<div id="_mcePaste">$result = mysql_query(&#8220;select id,uuid,uuidtable from dytable &#8220;);</div>
<div id="_mcePaste">$num_rows = @mysql_num_rows($result); //看一下返回多少行记录</div>
<div id="_mcePaste">if ($num_rows == 0) {</div>
<div id="_mcePaste">$b = array();         //这样长度为0 返回的是一个空数组</div>
<div id="_mcePaste">}else{</div>
<div id="_mcePaste">while ($row = mysql_fetch_array($result,MYSQL_ASSOC)){</div>
<div id="_mcePaste">$b[] = $row;</div>
<div id="_mcePaste">}</div>
<div id="_mcePaste">}</div>
<div id="_mcePaste">echo json_encode($b);</div>
<div id="_mcePaste">mysql_close();</div>
<div id="_mcePaste">}</div>
<div id="_mcePaste">plan2();</div>
<div id="_mcePaste">这样生成的JSON是比较方便的了！<span id="more-4592"></span></div>
<div id="_mcePaste">2. 客户端如果我们使用JQuery框架的话可以这样处理</div>
<div id="_mcePaste">&lt;script type=&#8221;text/javascript&#8221;&gt;</div>
<div id="_mcePaste">function ajaxcheck() {</div>
<div id="_mcePaste">$.ajax({</div>
<div id="_mcePaste">type:&#8221;GET&#8221;,</div>
<div id="_mcePaste">url: &#8220;http://localhost/PHPCMS/projcode/?number=&#8221;+Math.random(),</div>
<div id="_mcePaste">dataType: &#8216;text&#8217;,           //注意这里面的格式形式！</div>
<div id="_mcePaste">success:function(msg){</div>
<div id="_mcePaste">$(eval(msg)).each(function(){</div>
<div id="_mcePaste">alert(this.id+&#8221; &#8220;+this.uuid);//得到值就可以生成多个IMG标签了！</div>
<div id="_mcePaste">});</div>
<div id="_mcePaste">}</div>
<div id="_mcePaste">})</div>
<div id="_mcePaste">}</div>
<div id="_mcePaste">&lt;/script&gt;</div>
<div id="_mcePaste">如果客户端使用JS的话可以这样处理</div>
<div id="_mcePaste">&lt;script type=&#8221;text/javascript&#8221;&gt;</div>
<div id="_mcePaste">function ajaxcheck() {</div>
<div id="_mcePaste">$.ajax({</div>
<div id="_mcePaste">type:&#8221;GET&#8221;,</div>
<div id="_mcePaste">url: &#8220;http://localhost/PHPCMS/projcode/?number=&#8221;+Math.random(),</div>
<div id="_mcePaste">dataType: &#8216;text&#8217;,</div>
<div id="_mcePaste">success:function(msg){</div>
<div id="_mcePaste">json = eval(msg)</div>
<div id="_mcePaste">for(var i=0; i&lt;json.length; i++)</div>
<div id="_mcePaste">{</div>
<div id="_mcePaste">alert(json[i].id+&#8221; &#8221; + json[i].uuid)</div>
<div id="_mcePaste">}</div>
<div id="_mcePaste">}</div>
<div id="_mcePaste">})</div>
<div id="_mcePaste">}</div>
<div id="_mcePaste">&lt;/script&gt;</div>
<div id="_mcePaste">参考的一个示例代码如下：</div>
<div id="_mcePaste">客户端代码：</div>
<div id="_mcePaste">&lt;!DOCTYPE html PUBLIC &#8220;-//W3C//DTD XHTML 1.0 Transitional//EN&#8221; &#8220;http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&#8221;&gt;</div>
<div id="_mcePaste">&lt;html xmlns=&#8221;http://www.w3.org/1999/xhtml&#8221;&gt;</div>
<div id="_mcePaste">&lt;head&gt;</div>
<div id="_mcePaste">&lt;script type=&#8221;text/javascript&#8221; src=&#8221;../scripts/jquery.js&#8221;&gt;&lt;/script&gt;</div>
<div id="_mcePaste">&lt;meta http-equiv=&#8221;Content-Type&#8221; content=&#8221;text/html; charset=utf-8&#8243; /&gt;</div>
<div id="_mcePaste">&lt;script type=&#8221;text/javascript&#8221;&gt;</div>
<div id="_mcePaste">function ajaxcheck() {</div>
<div id="_mcePaste">$.ajax({</div>
<div id="_mcePaste">type:&#8221;GET&#8221;,</div>
<div id="_mcePaste">url: &#8220;http://localhost/PHPCMS/projcode/?number=&#8221;+Math.random(),</div>
<div id="_mcePaste">dataType: &#8216;text&#8217;,</div>
<div id="_mcePaste">success:function(msg){</div>
<div id="_mcePaste">$(eval(msg)).each(function(){</div>
<div id="_mcePaste">$(&#8220;#output&#8221;).html(&#8220;&lt;img id=&#8217;&#8221;+this.id+&#8221;&#8216; src=&#8217;&#8221;+this.uuid+&#8221;&#8216; /&gt;&#8221;);</div>
<div id="_mcePaste">});</div>
<div id="_mcePaste">}</div>
<div id="_mcePaste">})</div>
<div id="_mcePaste">}</div>
<div id="_mcePaste">&lt;/script&gt;</div>
<div id="_mcePaste">&lt;/head&gt;</div>
<div id="_mcePaste">&lt;body&gt;</div>
<div id="_mcePaste">&lt;button onclick=&#8221;ajaxcheck()&#8221;&gt;TEST&lt;/button&gt;</div>
<div id="_mcePaste">&lt;div id=&#8221;output&#8221;&gt;&lt;/div&gt;</div>
<div id="_mcePaste">&lt;/body&gt;</div>
<div id="_mcePaste">&lt;/html&gt;</div>
<div id="_mcePaste">服务端：</div>
<div id="_mcePaste">function plan2() {</div>
<div id="_mcePaste">$link = mysql_connect(&#8220;localhost&#8221;,&#8221;root&#8221;,&#8221;123&#8243;) or die(&#8220;&lt;font color=red&gt;无法建立起来连接。错误信息如下&lt;/font&gt;&#8221;);</div>
<div id="_mcePaste">mysql_query(&#8220;SET NAMES gbk&#8221;);</div>
<div id="_mcePaste">mysql_select_db(&#8220;phpcms&#8221;,$link) or die(&#8220;&lt;font color=red&gt;在服务器上面无法找到此请确认已建立此DB &#8220;);</div>
<div id="_mcePaste">$result = mysql_query(&#8220;select id,uuid from dytable &#8220;);</div>
<div id="_mcePaste">$num_rows = @mysql_num_rows($result); //看一下返回多少行记录</div>
<div id="_mcePaste">if ($num_rows == 0) {</div>
<div id="_mcePaste">$b = array();         //这样长度为0 返回的是一个空数组</div>
<div id="_mcePaste">}else{</div>
<div id="_mcePaste">while ($row = mysql_fetch_array($result,MYSQL_ASSOC)){</div>
<div id="_mcePaste">$b[] = $row;</div>
<div id="_mcePaste">}</div>
<div id="_mcePaste">}</div>
<div id="_mcePaste">echo json_encode($b);</div>
<div id="_mcePaste">mysql_close();</div>
<div id="_mcePaste">}</div>
<div id="_mcePaste">plan2();</div>
<div id="_mcePaste">以上实现的功能是借助JSON实现的。其实FLASH也有函数解析JSON。</div>
<p>整理两个现成的函数：json_decode、json_encode说明：其中json_encode 表示把常用的传统的数据类型如对象、数组、关联数组等转成JSON字符串。其实与JAVA里面的那个工具是一样的。而json_decode刚好相反。解决需求1.修改数据表的时候动态生成一个JSON片段。供JS调用。服务器端的代码：function plan2() {$link = mysql_connect(&#8220;localhost&#8221;,&#8221;root&#8221;,&#8221;123&#8243;) or die(&#8220;&lt;font color=red&gt;无法建立起来连接。错误信息如下&lt;/font&gt;&#8221;);mysql_query(&#8220;SET NAMES gbk&#8221;);mysql_select_db(&#8220;phpcms&#8221;,$link) or die(&#8220;&lt;font color=red&gt;在服务器上面无法找到此请确认已建立此DB &#8220;);$result = mysql_query(&#8220;select id,uuid,uuidtable from dytable &#8220;);$num_rows = @mysql_num_rows($result); //看一下返回多少行记录if ($num_rows == 0) {    $b = array();         //这样长度为0 返回的是一个空数组             }else{             while ($row = mysql_fetch_array($result,MYSQL_ASSOC)){        $b[] = $row;    }}echo json_encode($b);mysql_close();}plan2(); 这样生成的JSON是比较方便的了！ 2. 客户端如果我们使用JQuery框架的话可以这样处理&lt;script type=&#8221;text/javascript&#8221;&gt; function ajaxcheck() {    $.ajax({        type:&#8221;GET&#8221;,        url: &#8220;http://localhost/PHPCMS/projcode/?number=&#8221;+Math.random(),         dataType: &#8216;text&#8217;,           //注意这里面的格式形式！        success:function(msg){           $(eval(msg)).each(function(){                alert(this.id+&#8221; &#8220;+this.uuid);//得到值就可以生成多个IMG标签了！            });                   }    })}&lt;/script&gt; 如果客户端使用JS的话可以这样处理&lt;script type=&#8221;text/javascript&#8221;&gt; function ajaxcheck() {    $.ajax({        type:&#8221;GET&#8221;,       url: &#8220;http://localhost/PHPCMS/projcode/?number=&#8221;+Math.random(),         dataType: &#8216;text&#8217;,        success:function(msg){                     json = eval(msg)            for(var i=0; i&lt;json.length; i++)            {            alert(json[i].id+&#8221; &#8221; + json[i].uuid)            }        }    })}&lt;/script&gt;   参考的一个示例代码如下：客户端代码：&lt;!DOCTYPE html PUBLIC &#8220;-//W3C//DTD XHTML 1.0 Transitional//EN&#8221; &#8220;http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&#8221;&gt;&lt;html xmlns=&#8221;http://www.w3.org/1999/xhtml&#8221;&gt;&lt;head&gt;&lt;script type=&#8221;text/javascript&#8221; src=&#8221;../scripts/jquery.js&#8221;&gt;&lt;/script&gt;&lt;meta http-equiv=&#8221;Content-Type&#8221; content=&#8221;text/html; charset=utf-8&#8243; /&gt;&lt;script type=&#8221;text/javascript&#8221;&gt; function ajaxcheck() {    $.ajax({        type:&#8221;GET&#8221;,        url: &#8220;http://localhost/PHPCMS/projcode/?number=&#8221;+Math.random(),         dataType: &#8216;text&#8217;,        success:function(msg){            $(eval(msg)).each(function(){                $(&#8220;#output&#8221;).html(&#8220;&lt;img id=&#8217;&#8221;+this.id+&#8221;&#8216; src=&#8217;&#8221;+this.uuid+&#8221;&#8216; /&gt;&#8221;);            });        }    })}&lt;/script&gt;&lt;/head&gt;&lt;body&gt;&lt;button onclick=&#8221;ajaxcheck()&#8221;&gt;TEST&lt;/button&gt;&lt;div id=&#8221;output&#8221;&gt;&lt;/div&gt;&lt;/body&gt;&lt;/html&gt; 服务端：function plan2() {$link = mysql_connect(&#8220;localhost&#8221;,&#8221;root&#8221;,&#8221;123&#8243;) or die(&#8220;&lt;font color=red&gt;无法建立起来连接。错误信息如下&lt;/font&gt;&#8221;);mysql_query(&#8220;SET NAMES gbk&#8221;);mysql_select_db(&#8220;phpcms&#8221;,$link) or die(&#8220;&lt;font color=red&gt;在服务器上面无法找到此请确认已建立此DB &#8220;);$result = mysql_query(&#8220;select id,uuid from dytable &#8220;);$num_rows = @mysql_num_rows($result); //看一下返回多少行记录if ($num_rows == 0) {    $b = array();         //这样长度为0 返回的是一个空数组             }else{             while ($row = mysql_fetch_array($result,MYSQL_ASSOC)){        $b[] = $row;    }}echo json_encode($b);mysql_close();}plan2(); 以上实现的功能是借助JSON实现的。其实FLASH也有函数解析JSON。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.haohtml.com/index.php/archives/4592/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>深入理解 PHP之require/include顺序</title>
		<link>http://blog.haohtml.com/index.php/archives/4380</link>
		<comments>http://blog.haohtml.com/index.php/archives/4380#comments</comments>
		<pubDate>Mon, 05 Jul 2010 10:03:52 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[网络编程]]></category>
		<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://blog.haohtml.com/?p=4380</guid>
		<description><![CDATA[作者: laruence(http://www.laruence.com) 本文地址: http://www.laruence.com/2010/05/04/1450.html 转载请注明出处 // 在大型的Web项目中, include_path是一个模块化设计的根本中的根本(当然,现在也有很多基于autoload的设计, 这个不影响本文的探讨), 但是正是因为include_path, 经常会让我们遇到一些因为没有找到正确的文件而导致的看似”诡异”的问题. 也就有了如下的疑问: include_path是怎么起作用的? 如果有多个include_path顺序是怎么样的? 什么情况下include_path不起作用? 今天, 我就全面的介绍下这个问题, 先从一个例子开始吧. 如下的目录结构:   root     ├ 1.php     ├ 3.php     └ subdir          ├ 2.php           └ 3.php 在1.php中: &#60;?php ini_set("include_path", ".:path_to_subdir"); require("2.php"); ?&#62; 而在2.php中: &#60;?php require("3.php"); ?&#62; 而在root目录下的3.php打印出”root”, 在subdir目录下的3.php打印出”subdir”; 现在, 我的问题来了: 1. 当在root目录下运行1.php, 会得到什么输出? 2. 在subdir下运行上一级目录的1.php, 有会得到什么输出? 3. 当取消include_path中的当前目录path(也就是include_path=”path_to_subdir”), 上面俩个问题又会是什么输出? PHP中的include_path PHP在遇到require(_once)/include(_once)的指令的时候, [...]]]></description>
			<content:encoded><![CDATA[<div>
<ul>
<li>作者: laruence(<a title="风雪之隅" href="http://www.laruence.com/" target="_blank">http://www.laruence.com</a>)</li>
<li>本文地址: <a title="Permanet Link to 深入理解PHP之require/include顺序" href="http://www.laruence.com/2010/05/04/1450.html">http://www.laruence.com/2010/05/04/1450.html</a></li>
<li>转载请注明出处</li>
</ul>
</div>
<div><script type="text/javascript">// <![CDATA[
cT="0";nc="#444444";nBgc="";nBorder="#196FCB";tc="#FFFFFF";tBgc="#19A1FE";tBorder="#196FCB";tDigg="%E6%8E%A8%E8%8D%90";tDugg="%E5%B7%B2%E8%8D%90";defaultItemUrl="WEB_URL";defaultFeedUrl ="http://www.laruence.com/feed";
// ]]&gt;</script><script src="http://re.xianguo.com/api/diggthis.js" type="text/javascript"></script></div>
<p>在大型的Web项目中, include_path是一个模块化设计的根本中的根本(当然,现在也有很多基于autoload的设计,  这个不影响本文的探讨), 但是正是因为include_path, 经常会让我们遇到一些因为没有找到正确的文件而导致的看似”诡异”的问题.</p>
<p>也就有了如下的疑问:</p>
<p>include_path是怎么起作用的?</p>
<p>如果有多个include_path顺序是怎么样的?</p>
<p>什么情况下include_path不起作用?</p>
<p>今天, 我就全面的介绍下这个问题, 先从一个例子开始吧.<span id="more-4380"></span></p>
<p>如下的目录结构:</p>
<pre>
<ol>
<li>  root</li>
<li>    ├ 1.php</li>
<li>    ├ 3.php</li>
<li>    └ subdir</li>
<li>         ├ 2.php</li>
<li>          └ 3.php</li>
</ol>
</pre>
<p>在1.php中:</p>
<pre>
<ol>
<li>&lt;?php</li>
<li>ini_set("include_path", ".:path_to_subdir");</li>
<li>require("2.php");</li>
<li>?&gt;</li>
</ol>
</pre>
<p>而在2.php中:</p>
<pre>
<ol>
<li>&lt;?php</li>
<li>require("3.php");</li>
<li>?&gt;</li>
</ol>
</pre>
<p>而在root目录下的3.php打印出”root”, 在subdir目录下的3.php打印出”subdir”;</p>
<p>现在, 我的问题来了:</p>
<p>1. 当在root目录下运行1.php, 会得到什么输出?</p>
<p>2. 在subdir下运行上一级目录的1.php, 有会得到什么输出?</p>
<p>3. 当取消include_path中的当前目录path(也就是include_path=”path_to_subdir”),  上面俩个问题又会是什么输出?</p>
<p><strong>PHP中的include_path</strong></p>
<p>PHP在遇到require(_once)/include(_once)的指令的时候, 首先会做如下的判断:</p>
<pre>
<ol>
<li>要包含的文件路径是绝对路径么?</li>
<li> 如果是, 则直接包含, 并结束.</li>
<li> 如果不是, 进入另外的逻辑(经过多次调用, 宏展开后进入_php_stream_fopen_with_path)寻找此文件.</li>
</ol>
</pre>
<p>接下来, 在_php_stream_fopen_with_path中, 会做如下判断:</p>
<pre>
<ol>
<li>要包含的文件路径是相对路径么(形如./file, ../dir/file, 以下用"目录相对路径代替")?</li>
<li> 如果是, 则跳过include_path的作用逻辑, 直接解析相对路径(随后单独介绍).</li>
</ol>
</pre>
<p>会根据include_path,和当前执行文件的path组成一个待选的目录列表, 比如对于文章前面的例子来说, 会形成一个如下的待选列表</p>
<pre>
<ol>
<li>".:path_to_subdir:current_script_dir"</li>
</ol>
</pre>
<p>然后, 依次从待选列表头部开始, 根据DEFAULT_DIR_SEPARATOR(本文的环境是”:”)取出待选列表中的一个路径,  然后把要包含的文件名附加在这个路径后面, 进行尝试. 如果成功包含, 则返回, 否则继续下一个待选路径.</p>
<p>到现在为止, 我们已经可以回答我开头提出的3个问题了.</p>
<p>1. 因为在root目录下执行, 所以在1.php中包含2.php的时候,  include_path的第二个待选路径起了作用(path_to_subdir), 找到了path_to_subdir/2.php,  而在2.php包含3.php的时候, 当前工作目录是root下, 所以在包含3.php的时候,  include_path的第一个待选路径”.”(当前工作目录)下就找到的匹配的文件, 所以得到的输出是”root”.</p>
<p>2. 同1, 只不过当前的路径是subdir, 所以得到的输出是”subdir”.</p>
<p>3. 因为没有了当前路径为include_path, 所以在root目录下运行的时候2.php中包含3.php的时候,  是path_to_subdir起了作用, 所以无论在root还是subdir都将得到”subdir”的输出.<br />
而如果在2.php中清空include_path,</p>
<pre>
<ol>
<li>&lt;?php</li>
<li>ini_set("include_path", '');</li>
<li>require("3.php");</li>
<li>?&gt;</li>
</ol>
</pre>
<p>那么将会是current_script_dir起作用, 而这个时候current_script_dir是2.php的路径,  所以还是会得到”subdir”的输出.</p>
<p><strong>目录相对路径</strong></p>
<p>在使用目录相对路径的情况下, 相对路径的基点, 永远都是当前工作目录.</p>
<p>为了说明在目录相对路径下的情况,我们再看个列子, 还是上面的目录结构, 只不过1.php变成了:</p>
<pre>
<ol>
<li>&lt;?php</li>
<li>ini_set("include_path", "/");</li>
<li>require("./subdir/2.php");</li>
<li>?&gt;</li>
</ol>
</pre>
<p>2.php变成了:</p>
<pre>
<ol>
<li>&lt;?php</li>
<li>require("./3.php");</li>
<li>?&gt;</li>
</ol>
</pre>
<p>如果在root目录下执行, 2.php中寻找3.php将会在当前目录的相对路径下寻找, 所以得到的输出是”root”,  而如果是在subdir下执行上一级目录的1.php(php -f ../1.php),  将会因为在subdir下找不到”./subdir/2.php”而异常退出.</p>
<p><strong>后记</strong></p>
<p>1. 因为使用include_path和相对路径的情况下, 性能会和寻找的次数有关, 最坏的情况下,  如果你有10个include_path, 那么最多可能会重试11次才能找到要包含的文件,  所以, 在能使用绝对路径的情况下最好使用绝对路径.</p>
<p>2. 因为目录相对路径的basedir, 永远都是当前工作路径, 如果要使用, 需要和实际部署路径相关,  所以实际使用的很少(当然,  也有借助chdir来完成的模块).</p>
<p>3. 在模块化的系统设计中,  一般应该在模块内, 通过获取模块的部署路径(dirname(__FILE__),  php5.3以后更是提供了__DIR__常量)从而使用绝对路径.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.haohtml.com/index.php/archives/4380/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PHP 识别24位BMP的验证码</title>
		<link>http://blog.haohtml.com/index.php/archives/4377</link>
		<comments>http://blog.haohtml.com/index.php/archives/4377#comments</comments>
		<pubDate>Mon, 05 Jul 2010 09:20:45 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[网络编程]]></category>
		<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://blog.haohtml.com/?p=4377</guid>
		<description><![CDATA[来源:http://www.skiyo.cn/2009/02/25/php-identification-verification-code-24-bit-bmp/ 这个验证码图片是用ASP生成的..理所当然成了BMP格式. 但是对于PHP来说.这是个软伤.因为PHP的GD库根本就没把BMP纳入在内.虽然有wbmp但是还是不一样的. 所以就google了一下.结果又让我一阵喜悦.竟然有个现成的识别256色BMP的类..十分激动..有这个还不是白拿钱的事啊!! 结果又是令人失望的..256色的BMP跟24位色的根本是两个概念..这就意味这我得重新写了.. 看来没有现成的类库和函数.只能自己写了.用最最原始的fopen.分析BMP头.一个一个字节的读了. 所有又去google了BMP的24位色的头分析..那么长的文章…立马就失望了.. 所以无聊就去翻手册..眼睁睁的看着有imagecreatefromgif imagecreatefromjpeg imagecreatefrompng imagecreatefromwbmp等等.就是没有imagecreatefrombmp 于是突发奇想.去google一下imagecreatefrombmp会是什么结果..果然不出我所料.已经有达人写出了这个函数.. function imagecreatefrombmp($file) {     global  $CurrentBit, $echoMode;     $f=fopen($file,"r");     $Header=fread($f,2);     if($Header=="BM")     {         $Size=freaddword($f);         $Reserved1=freadword($f);         $Reserved2=freadword($f);         $FirstByteOfImage=freaddword($f);         $SizeBITMAPINFOHEADER=freaddword($f);         $Width=freaddword($f);         $Height=freaddword($f);         $biPlanes=freadword($f);         $biBitCount=freadword($f);         $RLECompression=freaddword($f);         $WidthxHeight=freaddword($f);         $biXPelsPerMeter=freaddword($f);         $biYPelsPerMeter=freaddword($f);         $NumberOfPalettesUsed=freaddword($f);         $NumberOfImportantColors=freaddword($f);         if($biBitCount&#60;24)         {             $img=imagecreate($Width,$Height);             $Colors=pow(2,$biBitCount);             for($p=0;$p&#60;$Colors;$p++)             {                 $B=freadbyte($f);                 $G=freadbyte($f);                 $R=freadbyte($f);                 $Reserved=freadbyte($f);                 $Palette[]=imagecolorallocate($img,$R,$G,$B);             };             if($RLECompression==0)             {                 $Zbytek=(4-ceil(($Width/(8/$biBitCount)))%4)%4;                 for($y=$Height-1;$y&#62;=0;$y--)                 {                     $CurrentBit=0;                     for($x=0;$x&#60;$Width;$x++)                     {                         $C=freadbits($f,$biBitCount); [...]]]></description>
			<content:encoded><![CDATA[<p>来源:<a href="http://www.skiyo.cn/2009/02/25/php-identification-verification-code-24-bit-bmp/" target="_blank">http://www.skiyo.cn/2009/02/25/php-identification-verification-code-24-bit-bmp/</a></p>
<p>这个验证码图片是用ASP生成的..理所当然成了BMP格式.</p>
<p>但是对于PHP来说.这是个软伤.因为PHP的GD库根本就没把BMP纳入在内.虽然有wbmp但是还是不一样的.</p>
<p>所以就google了一下.结果又让我一阵喜悦.竟然有个现成的识别256色BMP的类..十分激动..有这个还不是白拿钱的事啊!!</p>
<p>结果又是令人失望的..256色的BMP跟24位色的根本是两个概念..这就意味这我得重新写了..</p>
<p>看来没有现成的类库和函数.只能自己写了.用最最原始的fopen.分析BMP头.一个一个字节的读了.</p>
<p>所有又去google了BMP的24位色的头分析..那么长的文章…立马就失望了..<span id="more-4377"></span></p>
<p>所以无聊就去翻手册..眼睁睁的看着有imagecreatefromgif imagecreatefromjpeg  imagecreatefrompng imagecreatefromwbmp等等.就是没有imagecreatefrombmp</p>
<p>于是突发奇想.去google一下imagecreatefrombmp会是什么结果..果然不出我所料.已经有达人写出了这个函数..</p>
<pre>
<ol>
<li>function imagecreatefrombmp($file)</li>
<li>{</li>
<li>    global  $CurrentBit, $echoMode;</li>
<li></li>
<li>    $f=fopen($file,"r");</li>
<li>    $Header=fread($f,2);</li>
<li></li>
<li>    if($Header=="BM")</li>
<li>    {</li>
<li>        $Size=freaddword($f);</li>
<li>        $Reserved1=freadword($f);</li>
<li>        $Reserved2=freadword($f);</li>
<li>        $FirstByteOfImage=freaddword($f);</li>
<li></li>
<li>        $SizeBITMAPINFOHEADER=freaddword($f);</li>
<li>        $Width=freaddword($f);</li>
<li>        $Height=freaddword($f);</li>
<li>        $biPlanes=freadword($f);</li>
<li>        $biBitCount=freadword($f);</li>
<li>        $RLECompression=freaddword($f);</li>
<li>        $WidthxHeight=freaddword($f);</li>
<li>        $biXPelsPerMeter=freaddword($f);</li>
<li>        $biYPelsPerMeter=freaddword($f);</li>
<li>        $NumberOfPalettesUsed=freaddword($f);</li>
<li>        $NumberOfImportantColors=freaddword($f);</li>
<li></li>
<li>        if($biBitCount&lt;24)</li>
<li>        {</li>
<li>            $img=imagecreate($Width,$Height);</li>
<li>            $Colors=pow(2,$biBitCount);</li>
<li>            for($p=0;$p&lt;$Colors;$p++)</li>
<li>            {</li>
<li>                $B=freadbyte($f);</li>
<li>                $G=freadbyte($f);</li>
<li>                $R=freadbyte($f);</li>
<li>                $Reserved=freadbyte($f);</li>
<li>                $Palette[]=imagecolorallocate($img,$R,$G,$B);</li>
<li>            };</li>
<li></li>
<li></li>
<li></li>
<li></li>
<li>            if($RLECompression==0)</li>
<li>            {</li>
<li>                $Zbytek=(4-ceil(($Width/(8/$biBitCount)))%4)%4;</li>
<li></li>
<li>                for($y=$Height-1;$y&gt;=0;$y--)</li>
<li>                {</li>
<li>                    $CurrentBit=0;</li>
<li>                    for($x=0;$x&lt;$Width;$x++)</li>
<li>                    {</li>
<li>                        $C=freadbits($f,$biBitCount);</li>
<li>                        imagesetpixel($img,$x,$y,$Palette[$C]);</li>
<li>                    };</li>
<li>                    if($CurrentBit!=0) {freadbyte($f);};</li>
<li>                    for($g=0;$g&lt;$Zbytek;$g++)</li>
<li>                    freadbyte($f);</li>
<li>                };</li>
<li></li>
<li>            };</li>
<li>        };</li>
<li></li>
<li></li>
<li>        if($RLECompression==1) //$BI_RLE8</li>
<li>        {</li>
<li>            $y=$Height;</li>
<li></li>
<li>            $pocetb=0;</li>
<li></li>
<li>            while(true)</li>
<li>            {</li>
<li>                $y--;</li>
<li>                $prefix=freadbyte($f);</li>
<li>                $suffix=freadbyte($f);</li>
<li>                $pocetb+=2;</li>
<li></li>
<li>                $echoit=false;</li>
<li></li>
<li>                if($echoit)echo "Prefix: $prefix Suffix: $suffix&lt;BR&gt;";</li>
<li>                if(($prefix==0)and($suffix==1)) break;</li>
<li>                if(feof($f)) break;</li>
<li></li>
<li>                while(!(($prefix==0)and($suffix==0)))</li>
<li>                {</li>
<li>                    if($prefix==0)</li>
<li>                    {</li>
<li>                        $pocet=$suffix;</li>
<li>                        $Data.=fread($f,$pocet);</li>
<li>                        $pocetb+=$pocet;</li>
<li>                        if($pocetb%2==1) {freadbyte($f); $pocetb++;};</li>
<li>                    };</li>
<li>                    if($prefix&gt;0)</li>
<li>                    {</li>
<li>                        $pocet=$prefix;</li>
<li>                        for($r=0;$r&lt;$pocet;$r++)</li>
<li>                        $Data.=chr($suffix);</li>
<li>                    };</li>
<li>                    $prefix=freadbyte($f);</li>
<li>                    $suffix=freadbyte($f);</li>
<li>                    $pocetb+=2;</li>
<li>                    if($echoit) echo "Prefix: $prefix Suffix: $suffix&lt;BR&gt;";</li>
<li>                };</li>
<li></li>
<li>                for($x=0;$x&lt;strlen($Data);$x++)</li>
<li>                {</li>
<li>                    imagesetpixel($img,$x,$y,$Palette[ord($Data[$x])]);</li>
<li>                };</li>
<li>                $Data="";</li>
<li></li>
<li>            };</li>
<li></li>
<li>        };</li>
<li></li>
<li></li>
<li>        if($RLECompression==2) //$BI_RLE4</li>
<li>        {</li>
<li>            $y=$Height;</li>
<li>            $pocetb=0;</li>
<li></li>
<li>            /*while(!feof($f))</li>
<li>            echo freadbyte($f)."_".freadbyte($f)."&lt;BR&gt;";*/</li>
<li>            while(true)</li>
<li>            {</li>
<li>                //break;</li>
<li>                $y--;</li>
<li>                $prefix=freadbyte($f);</li>
<li>                $suffix=freadbyte($f);</li>
<li>                $pocetb+=2;</li>
<li></li>
<li>                $echoit=false;</li>
<li></li>
<li>                if($echoit)echo "Prefix: $prefix Suffix: $suffix&lt;BR&gt;";</li>
<li>                if(($prefix==0)and($suffix==1)) break;</li>
<li>                if(feof($f)) break;</li>
<li></li>
<li>                while(!(($prefix==0)and($suffix==0)))</li>
<li>                {</li>
<li>                    if($prefix==0)</li>
<li>                    {</li>
<li>                        $pocet=$suffix;</li>
<li></li>
<li>                        $CurrentBit=0;</li>
<li>                        for($h=0;$h&lt;$pocet;$h++)</li>
<li>                        $Data.=chr(freadbits($f,4));</li>
<li>                        if($CurrentBit!=0) freadbits($f,4);</li>
<li>                        $pocetb+=ceil(($pocet/2));</li>
<li>                        if($pocetb%2==1) {freadbyte($f); $pocetb++;};</li>
<li>                    };</li>
<li>                    if($prefix&gt;0)</li>
<li>                    {</li>
<li>                        $pocet=$prefix;</li>
<li>                        $i=0;</li>
<li>                        for($r=0;$r&lt;$pocet;$r++)</li>
<li>                        {</li>
<li>                            if($i%2==0)</li>
<li>                            {</li>
<li>                                $Data.=chr($suffix%16);</li>
<li>                            }</li>
<li>                            else</li>
<li>                            {</li>
<li>                                $Data.=chr(floor($suffix/16));</li>
<li>                            };</li>
<li>                            $i++;</li>
<li>                        };</li>
<li>                    };</li>
<li>                    $prefix=freadbyte($f);</li>
<li>                    $suffix=freadbyte($f);</li>
<li>                    $pocetb+=2;</li>
<li>                    if($echoit) echo "Prefix: $prefix Suffix: $suffix&lt;BR&gt;";</li>
<li>                };</li>
<li></li>
<li>                for($x=0;$x&lt;strlen($Data);$x++)</li>
<li>                {</li>
<li>                    imagesetpixel($img,$x,$y,$Palette[ord($Data[$x])]);</li>
<li>                };</li>
<li>                $Data="";</li>
<li></li>
<li>            };</li>
<li></li>
<li>        };</li>
<li></li>
<li></li>
<li>        if($biBitCount==24)</li>
<li>        {</li>
<li>            $img=imagecreatetruecolor($Width,$Height);</li>
<li>            $Zbytek=$Width%4;</li>
<li></li>
<li>            for($y=$Height-1;$y&gt;=0;$y--)</li>
<li>            {</li>
<li>                for($x=0;$x&lt;$Width;$x++)</li>
<li>                {</li>
<li>                    $B=freadbyte($f);</li>
<li>                    $G=freadbyte($f);</li>
<li>                    $R=freadbyte($f);</li>
<li>                    $color=imagecolorexact($img,$R,$G,$B);</li>
<li>                    if($color==-1) $color=imagecolorallocate($img,$R,$G,$B);</li>
<li>                    imagesetpixel($img,$x,$y,$color);</li>
<li>                }</li>
<li>                for($z=0;$z&lt;$Zbytek;$z++)</li>
<li>                freadbyte($f);</li>
<li>            };</li>
<li>        };</li>
<li>        return $img;</li>
<li></li>
<li>    };</li>
<li></li>
<li></li>
<li>    fclose($f);</li>
<li></li>
<li></li>
<li>};</li>
<li></li>
<li>function freadbyte($f)</li>
<li>{</li>
<li>    return ord(fread($f,1));</li>
<li>};</li>
<li></li>
<li>function freadword($f)</li>
<li>{</li>
<li>    $b1=freadbyte($f);</li>
<li>    $b2=freadbyte($f);</li>
<li>    return $b2*256+$b1;</li>
<li>};</li>
<li></li>
<li>function freaddword($f)</li>
<li>{</li>
<li>    $b1=freadword($f);</li>
<li>    $b2=freadword($f);</li>
<li>    return $b2*65536+$b1;</li>
<li>};</li>
</ol>
</pre>
<p>这个函数的过程是这样的..用fopen打开文件.一个字节一个字节的读出来..先读BMP头.然后逐行读像素.再用 imagecreatetruecolor新建立个图像.把刚读出来的像素逐个再画到刚才创建的图片上.<br />
最后返回这个图像的resource .</p>
<p>估计大家跟我一样.一开始就被这么长的函数吓到了.其实不用怕.分析一下.我们是要分析24位色的BMP.所以上面函数的大部分语句我们都不 用.if($biBitCount==24)以下的才是关键..</p>
<p>$B=freadbyte($f);<br />
$G=freadbyte($f);<br />
$R=freadbyte($f);</p>
<p>这三行就是读取像素了..我们需要的就是把每个像素放到数组中.这样就容易被操作了.</p>
<p>$array[] = sprintf(“%03d”,$R).sprintf(“%03d”,$G).sprintf(“%03d”,$B);</p>
<p>这样我们就把每个像素放到$array这个数组中了.但是这样还不够.因为我们得识别像素.所以我是这样想的.把白色的(255255255)改为 0.其他颜色改为1.这是因为我这个验证码比较简单.而且干扰颜色非常少..</p>
<p>最后形成的$array就类似这样的了</p>
<p>0001111000   0001111000   0001111000   0000101000<br />
0010000100   0010000100   0010000100   0000100000<br />
0010000100   0010000100   0010000100   0000100000<br />
0010110100   0000000100   0000000100   0000100000<br />
0010110100   0000101000   0000000100   0000100000<br />
0010110100   0000110000   0011000100   0000010000<br />
0010110100   0000001000   0010111000   0000010000<br />
0010000100   0010000100   0010000000   0010001000<br />
0011000100   0010000110   0010000000   0010001000<br />
0001111000   0001111000   0011111100   0011111100</p>
<p>当然 之所以形成这个样子是我输出的时候处理过的.<br />
很容易看的清楚.这是0357..</p>
<p>有的人会问为什么是倒的?这是因为BMP在存储图像的时候就是倒着存放的.比较BT.<br />
不过这个不必担心.我们也不用给他费劲正过来.因为我们是要做比较.只要这个对比码也是倒着的就可以了.</p>
<p>为了更清楚的说明白这个数组是怎么存储内容的.我给大家详细的描述一下.就按照上面的例子.</p>
<p>数组下标0 1 2 3 4 5 6 7 8 9    10…..                                                       …  39<br />
存储内容0 0 0 1 1 1 1 0 0 0   0 0 0 1 1 1 1 0 0 0    0 0 0 1 1 1 1  0 0  0     0 0 0 0 1  0 1 0 0  0  第一行</p>
<p>数组下标40 41  ….                                                                            …79<br />
存储内容0  0 1 0 0 0 0 1 0 0    0 0 1 0 0 0 0 1 0 0    0 0 1 0 0 0 0 1 0  0    0 0 0 0 1 0 0 0 0 0    第二行</p>
<p>为了省略我就不写了..很容易看出来.这是个一维的数组.一共有399个元素..但是为了识别验证码.我们得把其中的每个数字取出来.</p>
<p>0-9 40-49 80-89 …为一组<br />
10-19 50-59 90-99 …为一组<br />
20-29 60-69 100-109…为一组<br />
30-39 70-79 110-119..为一组</p>
<p>你可以自己写个算法..</p>
<p>这样整理出来后..是一个具有4个元素的数组.<br />
每个元素都有100位0和1的数字.</p>
<p>元素取出来了.要跟谁比较呢??对.我们得找个参照物才行..<br />
找参照物就是体力活了..<br />
返回到上面的过程..不断的刷新验证码..直到把0-9都出现了.针对每个.记下他的样子比如说0是这样</p>
<p>0001111000<br />
0010000100<br />
0010000100<br />
0010110100<br />
0010110100<br />
0010110100<br />
0010110100<br />
0010000100<br />
0011000100<br />
0001111000</p>
<p>变成字符串.0就是这样了 0001111000001000010000100001000010110100001011010000101101000010110100001000010000110001000001111000<br />
也就是上面的按照顺序放在一行.</p>
<p>0-9都记下来后.我们可以放到一个数组中,就叫$key吧.</p>
<p>这样的话跟我们生成出来的元素就一一对应了.</p>
<p>下面就要开始比较了.</p>
<p>循环是免不了的.比较的技巧是用similar_text和参照物逐个比较.把相思百分比放到一个数组中.<br />
然后把这个数组中最大的那个百分比取出来.所对应的索引值(此索引值不是自动生成的)就是我们识别出来的数字了.<br />
下面的代码值描述重要的部分</p>
<p>foreach ($keys as $key =&gt; $value) {              //$key就是对比参照组<br />
similar_text($value, $validValue, $p);<br />
$maxArr[$key] = $p;           //把所有的几率放到数组中<br />
}<br />
然后取出$maxArr这个最大的索引值.就是我们识别出来的数字了.</p>
<p>到此验证码算是识别完成了.</p>
<p>但是部署给用户的时候.发现他的机器上用fopen打开远程URL.只有30%的几率能获取到.其他的情况都是HTTP Request  failed…<br />
更改了很多方法还是不成功.结果我的解决办法是.<br />
用CURL把验证码保存到本地.然后fopen打开本地图片就100%OK啦..</p>
<p>至于详细的代码我就不贴了.因为代码是卖给人家的.为了保障人家的利益.所以大家也不要开口跟我要了..思路我已经给出来了.相信你是可以写出来 的.</p>
<p><strong>演示:<a onclick="javascript:pageTracker._trackPageview('/outgoing/www.skiyo.cn/demo/valid/');" href="http://www.skiyo.cn/demo/valid/" target="_blank">http://www.skiyo.cn/demo/valid/</a></strong></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.haohtml.com/index.php/archives/4377/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>给类动态的添加方法..</title>
		<link>http://blog.haohtml.com/index.php/archives/4374</link>
		<comments>http://blog.haohtml.com/index.php/archives/4374#comments</comments>
		<pubDate>Mon, 05 Jul 2010 09:15:25 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[网络编程]]></category>
		<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://blog.haohtml.com/?p=4374</guid>
		<description><![CDATA[今天没事干翻手册.发现create_function这个方法很有意思. 我们可以定义一些用户函数.但是还是用原来的函数名.只不过前面加个$就可以了. 我们来看下例子 $str_shuffle = create_function('$a','echo $a;'); echo $str_shuffle('aaa'); 这样我们就可以制造一个山寨版的str_shuffle了:) create_function的功能远远不止这点.我们还可以给类动态的添加方法.我们来看下面的例子 class Hoge {    var $lamda;    var $text;    function set($lamda)    {        $this-&#62;lamda = $lamda;    }    function callLamda()    {        $func = $this-&#62;lamda;        return $func($this);    }    function get()    {        return $this-&#62;text;    } } $newfunc = create_function('&#38;$class', 'echo $class-&#62;get();' ); $h = new Hoge; $h-&#62;text = "Hi there !"; $h-&#62;set($newfunc); $h-&#62;callLamda();]]></description>
			<content:encoded><![CDATA[<p>今天没事干翻手册.发现<strong>create_function</strong>这个方法很有意思.</p>
<p>我们可以定义一些用户函数.但是还是用原来的函数名.只不过前面加个$就可以了.</p>
<p>我们来看下例子</p>
<pre>
<ol>
<li>$str_shuffle = create_function('$a','echo $a;');</li>
<li>echo $str_shuffle('aaa');</li>
</ol>
</pre>
<p>这样我们就可以制造一个山寨版的str_shuffle了:)<span id="more-4374"></span></p>
<p>create_function的功能远远不止这点.我们还可以给类动态的添加方法.我们来看下面的例子</p>
<pre>
<ol>
<li>class Hoge {</li>
<li>   var $lamda;</li>
<li>   var $text;</li>
<li>   function set($lamda)</li>
<li>   {</li>
<li>       $this-&gt;lamda = $lamda;</li>
<li>   }</li>
<li>   function callLamda()</li>
<li>   {</li>
<li>       $func = $this-&gt;lamda;</li>
<li>       return $func($this);</li>
<li>   }</li>
<li>   function get()</li>
<li>   {</li>
<li>       return $this-&gt;text;</li>
<li>   }</li>
<li>}</li>
<li>$newfunc = create_function('&amp;$class', 'echo $class-&gt;get();' );</li>
<li>$h = new Hoge;</li>
<li>$h-&gt;text = "Hi there !";</li>
<li>$h-&gt;set($newfunc);</li>
<li>$h-&gt;callLamda();</li>
</ol>
</pre>
]]></content:encoded>
			<wfw:commentRss>http://blog.haohtml.com/index.php/archives/4374/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>深入探讨PHP中的内存管理问题</title>
		<link>http://blog.haohtml.com/index.php/archives/4367</link>
		<comments>http://blog.haohtml.com/index.php/archives/4367#comments</comments>
		<pubDate>Mon, 05 Jul 2010 06:50:17 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[网络编程]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[内存管理]]></category>

		<guid isPermaLink="false">http://blog.haohtml.com/?p=4367</guid>
		<description><![CDATA[一、 内存 在PHP中，填充一个字符串变量相当简单，这只需要一个语句&#8221;＜?php $str = &#8216;hello world &#8216;; ?＞&#8221;即可，并且该字符串能够被自由地修改、拷贝和移动。而在C语言中，尽管你能够编写例如&#8221;char *str = &#8220;hello world &#8220;;&#8221;这样的一个简单的静态字符串；但是，却不能修改该字符串，因为它生存于程序空间内。为了创建一个可操纵的字符串，你必须分配一个内存块，并且通过一 个函数（例如strdup()）来复制其内容。 { char *str; str = strdup(&#8220;hello world&#8221;); if (!str) { fprintf(stderr， &#8220;Unable to allocate memory!&#8221;); } } 由于后面我们将分析的各种原因，传统型内存管理函数（例如malloc()，free()，strdup()，realloc()，calloc()， 等等）几乎都不能直接为PHP源代码所使用。 二、 释放内存 在几乎所有的平台上，内存管理都是通 过一种请求和释放模式实现的。首先，一个应用程序请求它下面的层(通常指&#8221;操作系统&#8221;)：&#8221;我想使用一些内存空间&#8221;。如果存在可用的空间，操作系统就会把 它提供给该程序并且打上一个标记以便不会再把这部分内存分配给其它程序。 当应用程序使用完这部分内存，它应该被返回到OS；这样以来，它就能够被 继续分配给其它程序。如果该程序不返回这部分内存，那么OS无法知道是否这块内存不再使用并进而再分配给另一个进程。如果一个内存块没有释放，并且所有者 应用程序丢失了它，那么，我们就说此应用程序&#8221;存在漏洞&#8221;，因为这部分内存无法再为其它程序可用。 在一个典型的客户端应用程序中，较 小的不太经常的内存泄漏有时能够为OS所&#8221;容忍&#8221;，因为在这个进程稍后结束时该泄漏内存会被隐式返回到OS。这并没有什么，因为OS知道它把该内存分配给 了哪个程序，并且它能够确信当该程序终止时不再需要该内存。 而对于长时间运行的服务器守护程序，包括象Apache这样的web服务 器和扩展php模块来说，进程往往被设计为相当长时间一直运行。因为OS不能清理内存使用，所以，任何程序的泄漏-无论是多么小-都将导致重复操作并最终 耗尽所有的系统资源。 现在，我们不妨考虑用户空间内的stristr()函数；为了使用大小写不敏感的搜索来查找一个字符串，它实际 上创建了两个串的各自的一个小型副本，然后执行一个更传统型的大小写敏感的搜索来查找相对的偏移量。然而，在定位该字符串的偏移量之后，它不再使用这些小 写版本的字符串。如果它不释放这些副本，那么，每一个使用stristr()的脚本在每次调用它时都将泄漏一些内存。最后，web服务器进程将拥有所有的 系统内存，但却不能够使用它。 你可以理直气壮地说，理想的解决方案就是编写良好、干净的、一致的代码。这当然不错；但是，在一个象 PHP解释器这样的环境中，这种观点仅对了一半。 三、 [...]]]></description>
			<content:encoded><![CDATA[<p><strong>一、 内存</strong></p>
<p>在PHP中，填充一个字符串变量相当简单，这只需要一个语句&#8221;＜?php $str = &#8216;hello  world &#8216;; ?＞&#8221;即可，并且该字符串能够被自由地修改、拷贝和移动。而在C语言中，尽管你能够编写例如&#8221;char *str = &#8220;hello  world  &#8220;;&#8221;这样的一个简单的静态字符串；但是，却不能修改该字符串，因为它生存于程序空间内。为了创建一个可操纵的字符串，你必须分配一个内存块，并且通过一 个函数（例如strdup()）来复制其内容。</p>
<table border="1" width="90%" align="center" bgcolor="#e7e9e9" bordercolor="#cccccc">
<tbody>
<tr>
<td>{<br />
char *str;<br />
str = strdup(&#8220;hello world&#8221;);<br />
if (!str) {<br />
fprintf(stderr， &#8220;Unable to allocate memory!&#8221;);<br />
}<br />
}</td>
</tr>
</tbody>
</table>
<p>由于后面我们将分析的各种原因，传统型内存管理函数（例如malloc()，free()，strdup()，realloc()，calloc()， 等等）几乎都不能直接为PHP源代码所使用。<span id="more-4367"></span></p>
<p><strong>二、 释放内存</strong></p>
<p>在几乎所有的平台上，内存管理都是通 过一种请求和释放模式实现的。首先，一个应用程序请求它下面的层(通常指&#8221;操作系统&#8221;)：&#8221;我想使用一些内存空间&#8221;。如果存在可用的空间，操作系统就会把 它提供给该程序并且打上一个标记以便不会再把这部分内存分配给其它程序。<br />
当应用程序使用完这部分内存，它应该被返回到OS；这样以来，它就能够被 继续分配给其它程序。如果该程序不返回这部分内存，那么OS无法知道是否这块内存不再使用并进而再分配给另一个进程。如果一个内存块没有释放，并且所有者 应用程序丢失了它，那么，我们就说此应用程序&#8221;存在漏洞&#8221;，因为这部分内存无法再为其它程序可用。</p>
<p>在一个典型的客户端应用程序中，较 小的不太经常的内存泄漏有时能够为OS所&#8221;容忍&#8221;，因为在这个进程稍后结束时该泄漏内存会被隐式返回到OS。这并没有什么，因为OS知道它把该内存分配给 了哪个程序，并且它能够确信当该程序终止时不再需要该内存。</p>
<p>而对于长时间运行的服务器守护程序，包括象Apache这样的web服务 器和扩展php模块来说，进程往往被设计为相当长时间一直运行。因为OS不能清理内存使用，所以，任何程序的泄漏-无论是多么小-都将导致重复操作并最终 耗尽所有的系统资源。</p>
<p>现在，我们不妨考虑用户空间内的stristr()函数；为了使用大小写不敏感的搜索来查找一个字符串，它实际 上创建了两个串的各自的一个小型副本，然后执行一个更传统型的大小写敏感的搜索来查找相对的偏移量。然而，在定位该字符串的偏移量之后，它不再使用这些小 写版本的字符串。如果它不释放这些副本，那么，每一个使用stristr()的脚本在每次调用它时都将泄漏一些内存。最后，web服务器进程将拥有所有的 系统内存，但却不能够使用它。</p>
<p>你可以理直气壮地说，理想的解决方案就是编写良好、干净的、一致的代码。这当然不错；但是，在一个象 PHP解释器这样的环境中，这种观点仅对了一半。</p>
<p><strong>三、 错误处理</strong></p>
<p>为了实现&#8221;跳出&#8221;对用户空间脚本 及其依赖的扩展函数的一个活动请求，需要使用一种方法来完全&#8221;跳出&#8221;一个活动请求。这是在Zend引擎内实现的：在一个请求的开始设置一个&#8221;跳出&#8221;地址， 然后在任何die()或exit()调用或在遇到任何关键错误(E_ERROR)时执行一个longjmp()以跳转到该&#8221;跳出&#8221;地址。</p>
<p>尽管这个&#8221;跳出&#8221;进程能够简化程序执行的流程，但是，在绝大多数情况下，这会意味着将会跳过资源清除代码部分(例如free()调用)并最终导致出现内 存漏洞。现在，让我们来考虑下面这个简化版本的处理函数调用的引擎代码：</p>
<table border="1" width="90%" align="center" bgcolor="#e7e9e9" bordercolor="#cccccc">
<tbody>
<tr>
<td>void call_function(const char *fname， int fname_len TSRMLS_DC){<br />
zend_function *fe;<br />
char *lcase_fname;<br />
/* PHP函数名是大小写不敏感的，<br />
*为了 简化在函数表中对它们的定位，<br />
*所有函数名都隐含地翻译为小写的<br />
*/<br />
lcase_fname =  estrndup(fname， fname_len);<br />
zend_str_tolower(lcase_fname，  fname_len);<br />
if (zend_hash_find(EG(function_table)，lcase_fname，  fname_len + 1， (void **)&amp;fe) == FAILURE) {<br />
zend_execute(fe-＞op_array TSRMLS_CC);<br />
} else {<br />
php_error_docref(NULL TSRMLS_CC， E_ERROR，&#8221;Call to undefined function:  %s()&#8221;， fname);<br />
}<br />
efree(lcase_fname);<br />
}</td>
</tr>
</tbody>
</table>
<p>当执行到php_error_docref()这一行时，内部错误处理器就会明白该错误级别是critical，并相应地调用longjmp()来中断 当前程序流程并离开call_function()函数，甚至根本不会执行到efree(lcase_fname)这一行。你可能想把efree()代码 行移动到zend_error()代码行的上面；但是，调用这个call_function()例程的代码行会怎么样呢？fname本身很可能就是一个分 配的字符串，并且，在它被错误消息处理使用完之前，你根本不能释放它。</p>
<p>注意，这个php_error_docref()函数是 trigger_error()函数的一个内部等价实现。它的第一个参数是一个将被添加到docref的可选的文档引用。第三个参数可以是任何我们熟悉的 E_*家族常量，用于指示错误的严重程度。第四个参数（最后一个）遵循printf()风格的格式化和变量参数列表式样。</p>
<p><strong>四、 Zend内存管理器</p>
<p></strong> 在上面的&#8221;跳出&#8221;请求期间解决内存泄漏的方案之一是：使用Zend内存 管理(ZendMM)层。引擎的这一部分非常类似于操作系统的内存管理行为-分配内存给调用程序。区别在于，它处于进程空间中非常低的位置而且是&#8221;请求感 知&#8221;的；这样以来，当一个请求结束时，它能够执行与OS在一个进程终止时相同的行为。也就是说，它会隐式地释放所有的为该请求所占用的内存。图1展示了 ZendMM与OS以及PHP进程之间的关系。</p>
<table width="90%" align="center">
<tbody>
<tr>
<td>
<div><img src="http://dev.yesky.com/imagelist/06/43/t9j17nqxpq2w.jpg" border="1" alt="" /><br />
图 1.Zend内存管理器代替系统调用来实现针对每一种请求的内存分配。</div>
</td>
</tr>
</tbody>
</table>
<p>除了提供隐式内存清除功能之外，ZendMM还能够根据php.ini中memory_limit的设置控制每一种内存请求的用法。如果一个脚本试图请求 比系统中可用内存更多的内存，或大于它每次应该请求的最大量，那么，ZendMM将自动地发出一个E_ERROR消息并且启动相应的&#8221;跳出&#8221;进程。这种方 法的一个额外优点在于，大多数内存分配调用的返回值并不需要检查，因为如果失败的话将会导致立即跳转到引擎的退出部分。</p>
<p>把PHP内部 代码和OS的实际的内存管理层&#8221;钩&#8221;在一起的原理并不复杂：所有内部分配的内存都要使用一组特定的可选函数实现。例如，PHP代码不是使用 malloc(16)来分配一个16字节内存块而是使用了emalloc(16)。除了实现实际的内存分配任务外，ZendMM还会使用相应的绑定请求类 型来标志该内存块；这样以来，当一个请求&#8221;跳出&#8221;时，ZendMM可以隐式地释放它。</p>
<p>经常情况下，内存一般都需要被分配比单个请求持 续时间更长的一段时间。这种类型的分配（因其在一次请求结束之后仍然存在而被称为&#8221;永久性分配&#8221;），可以使用传统型内存分配器来实现，因为这些分配并不会 添加ZendMM使用的那些额外的相应于每种请求的信息。然而有时，直到运行时刻才会确定是否一个特定的分配需要永久性分配，因此ZendMM导出了一组 帮助宏，其行为类似于其它的内存分配函数，但是使用最后一个额外参数来指示是否为永久性分配。</p>
<p>如果你确实想实现一个永久性分配，那么 这个参数应该被设置为1；在这种情况下，请求是通过传统型malloc()分配器家族进行传递的。然而，如果运行时刻逻辑认为这个块不需要永久性分配；那 么，这个参数可以被设置为零，并且调用将会被调整到针对每种请求的内存分配器函数。</p>
<p>例 如，pemalloc(buffer_len，1)将映射到malloc(buffer_len)，而pemalloc(buffer_len，0)将被 使用下列语句映射到emalloc(buffer_len)：</p>
<table border="1" width="90%" align="center" bgcolor="#e7e9e9" bordercolor="#cccccc">
<tbody>
<tr>
<td>#define in Zend/zend_alloc.h:<br />
#define pemalloc(size， persistent)  ((persistent)?malloc(size): emalloc(size))</td>
</tr>
</tbody>
</table>
<p>所有这些在ZendMM中提供的分配器函数都能够从下表中找到其更传统的对应实现。</p>
<p>表格1展示了ZendMM支持下的每一个分配器 函数以及它们的e/pe对应实现：</p>
<p>表格1.传统型相对于PHP特定的分配器。</p>
<table border="1" cellspacing="0" cellpadding="0" width="90%" align="center">
<tbody>
<tr>
<td>分配器函数</td>
<td>e/pe对应实现</td>
</tr>
<tr>
<td>void *malloc(size_t count);</td>
<td>void *emalloc(size_t count);void *pemalloc(size_t count，char  persistent);</td>
</tr>
<tr>
<td>void *calloc(size_t count);</td>
<td>void *ecalloc(size_t count);void *pecalloc(size_t count，char  persistent);</td>
</tr>
<tr>
<td>void *realloc(void *ptr，size_t count);</td>
<td>void *erealloc(void *ptr，size_t count);<br />
void *perealloc(void  *ptr，size_t count，char persistent);</td>
</tr>
<tr>
<td>void *strdup(void *ptr);</td>
<td>void *estrdup(void *ptr);void *pestrdup(void *ptr，char persistent);</td>
</tr>
<tr>
<td>void free(void *ptr);</td>
<td>void efree(void *ptr);<br />
void pefree(void *ptr，char persistent);</td>
</tr>
</tbody>
</table>
<p>你可能会注意到，即使是pefree()函数也要求使用永久性标志。这是因为在调用pefree()时，它实际上并不知道是否ptr是一种永久性分配。 针对一个非永久性分配调用free()能够导致双倍的空间释放，而针对一种永久性分配调用efree()有可能会导致一个段错误，因为内存管理器会试图查 找并不存在的管理信息。因此，你的代码需要记住它分配的数据结构是否是永久性的。</p>
<p>除了分配器函数核心部分外，还存在其它一些非常方 便的ZendMM特定的函数，例如：</p>
<table border="1" width="90%" align="center" bgcolor="#e7e9e9" bordercolor="#cccccc">
<tbody>
<tr>
<td>void *estrndup(void *ptr，int len);</td>
</tr>
</tbody>
</table>
<p>该函 数能够分配len+1个字节的内存并且从ptr处复制len个字节到最新分配的块。这个estrndup()函数的行为可以大致描述如下：</p>
<table border="1" width="90%" align="center" bgcolor="#e7e9e9" bordercolor="#cccccc">
<tbody>
<tr>
<td>void *estrndup(void *ptr， int len)<br />
{<br />
char *dst = emalloc(len +  1);<br />
memcpy(dst， ptr， len);<br />
dst[len] = 0;<br />
return dst;<br />
}</td>
</tr>
</tbody>
</table>
<p>在此，被隐式放置在缓冲区最后的NULL字节可以确保任何使用estrndup()实现字符串复制操作的函数都不需要担心会把结果缓冲区传递给一个例如 printf()这样的希望以为NULL为结束符的函数。当使用estrndup()来复制非字符串数据时，最后一个字节实质上都浪费了，但其中的利明显 大于弊。</p>
<table border="1" width="90%" align="center" bgcolor="#e7e9e9" bordercolor="#cccccc">
<tbody>
<tr>
<td>void *safe_emalloc(size_t size， size_t count， size_t addtl);<br />
void  *safe_pemalloc(size_t size， size_t count，size_t addtl，char persistent);</td>
</tr>
</tbody>
</table>
<p>这些函数分配的内存空间最终大小是((size*count)+addtl)。你可以会问：&#8221;为什么还要提供额外函数呢？为什么不使用一个 emalloc/pemalloc呢？&#8221;原因很简单：为了<a href="http://soft.yesky.com/security/" target="_blank"><span style="color: #255e9a;">安全</span></a>。尽管有时候可能性相当小，但是，正是这一&#8221;可能性相当小&#8221;的结果导致宿主平台的内存溢出。 这可能会导致分配负数个数的字节空间，或更有甚者，会导致分配一个小于调用程序要求大小的字节空间。而safe_emalloc()能够避免这种类型的陷 井-通过检查整数溢出并且在发生这样的溢出时显式地预以结束。</p>
<p>注意，并不是所有的内存分配例程都有一个相应的p*对等实现。例如，不 存在pestrndup()，并且在PHP 5.1版本前也不存在safe_pemalloc()。</p>
<p><strong>五、 引用计数</strong></p>
<p>慎重的内存分配与释放对于PHP（它是一种多请求进程）的长期性能有极其重大的影响；但是，这还仅是问题的一半。为了使一个每秒处理上千次点击的服务器 高效地运行，每一次请求都需要使用尽可能少的内存并且要尽可能减少不必要的数据复制操作。请考虑下列PHP代码片断：</p>
<table border="1" width="90%" align="center" bgcolor="#e7e9e9" bordercolor="#cccccc">
<tbody>
<tr>
<td>＜?php<br />
$a = &#8216;Hello World&#8217;;<br />
$b = $a;<br />
unset($a);<br />
?＞</td>
</tr>
</tbody>
</table>
<p>在第一次调用之后，只有一个变量被创建，并且一个12字节的内存块指派给它以便存储字符串&#8221;Hello  World&#8221;，还包括一个结尾处的NULL字符。现在，让我们来观察后面的两行：$b被置为与变量$a相同的值，然后变量$a被释放。</p>
<p>如果PHP因每次变量赋值都要复制变量内容的话，那么，对于上例中要复制的字符串还需要复制额外的12个字节，并且在数据复制期间还要进行另外的处理器 加载。这一行为乍看起来有点荒谬，因为当第三行代码出现时，原始变量被释放，从而使得整个数据复制显得完全不必要。其实，我们不妨再远一层考虑，让我们设 想当一个10MB大小的文件的内容被装载到两个变量中时会发生什么。这将会占用20MB的空间，此时，10已经足够了。引擎会把那么多的时间和内存浪费在 这样一种无用的努力上吗？</p>
<p>你应该知道，PHP的设计者早已深谙此理。</p>
<p>记住，在引擎中，变量名和它们的值实际上是 两个不同的概念。值本身是一个无名的zval*存储体（在本例中，是一个字符串值），它被通过zend_hash_add()赋给变量$a。如果两个变量 名都指向同一个值，会发生什么呢？</p>
<table border="1" width="90%" align="center" bgcolor="#e7e9e9" bordercolor="#cccccc">
<tbody>
<tr>
<td>{<br />
zval *helloval;<br />
MAKE_STD_ZVAL(helloval);<br />
ZVAL_STRING(helloval， &#8220;Hello World&#8221;， 1);<br />
zend_hash_add(EG(active_symbol_table)， &#8220;a&#8221;， sizeof(&#8220;a&#8221;)，&amp;helloval，  sizeof(zval*)， NULL);<br />
zend_hash_add(EG(active_symbol_table)， &#8220;b&#8221;，  sizeof(&#8220;b&#8221;)，&amp;helloval， sizeof(zval*)， NULL);<br />
}</td>
</tr>
</tbody>
</table>
<p>此时，你可以实际地观察$a或$b，并且会看到它们都包含字符串&#8221;Hello  World&#8221;。遗憾的是，接下来，你继续执行第三行代码&#8221;unset($a);&#8221;。此时，unset()并不知道$a变量指向的数据还被另一个变量所使 用，因此它只是盲目地释放掉该内存。任何随后的对变量$b的存取都将被分析为已经释放的内存空间并因此导致引擎崩溃。</p>
<p>这个问题可以借 助于zval（它有好几种形式）的第四个成员refcount加以解决。当一个变量被首次创建并赋值时，它的refcount被初始化为1，因为它被假定 仅由最初创建它时相应的变量所使用。当你的代码片断开始把helloval赋给$b时，它需要把refcount的值增加为2；这样以来，现在该值被两个 变量所引用：</p>
<table border="1" width="90%" align="center" bgcolor="#e7e9e9" bordercolor="#cccccc">
<tbody>
<tr>
<td>{<br />
zval *helloval;<br />
MAKE_STD_ZVAL(helloval);<br />
ZVAL_STRING(helloval， &#8220;Hello World&#8221;， 1);<br />
zend_hash_add(EG(active_symbol_table)， &#8220;a&#8221;， sizeof(&#8220;a&#8221;)，&amp;helloval，  sizeof(zval*)， NULL);<br />
ZVAL_ADDREF(helloval);<br />
zend_hash_add(EG(active_symbol_table)， &#8220;b&#8221;，  sizeof(&#8220;b&#8221;)，&amp;helloval，sizeof(zval*)，NULL);<br />
}</td>
</tr>
</tbody>
</table>
<p>现在，当unset()删除原变量的$a相应的副本时，它就能够从refcount参数中看到，还有另外其他人对该数据感兴趣；因此，它应该只是减少 refcount的计数值，然后不再管它。</p>
<p><strong>六、 写复制（Copy on Write）</p>
<p></strong> 通过refcounting来节约内存的确是不错的 主意，但是，当你仅想改变其中一个变量的值时情况会如何呢？为此，请考虑下面的代码片断：</p>
<table border="1" width="90%" align="center" bgcolor="#e7e9e9" bordercolor="#cccccc">
<tbody>
<tr>
<td>＜?php<br />
$a = 1;<br />
$b = $a;<br />
$b += 5;<br />
?＞</td>
</tr>
</tbody>
</table>
<p>通过上面的逻辑流程，你当然知道$a的值仍然等于1，而$b的值最后将是6。并且此时，你还知道，Zend在尽力节省内存-通过使$a和$b都引用相同 的zval（见第二行代码）。那么，当执行到第三行并且必须改变$b变量的值时，会发生什么情况呢？</p>
<p>回答是，Zend要查看 refcount的值，并且确保在它的值大于1时对之进行分离。在Zend引擎中，分离是破坏一个引用对的过程，正好与你刚才看到的过程相反：</p>
<table border="1" width="90%" align="center" bgcolor="#e7e9e9" bordercolor="#cccccc">
<tbody>
<tr>
<td>zval *get_var_and_separate(char *varname， int varname_len TSRMLS_DC)<br />
{<br />
zval **varval， *varcopy;<br />
if  (zend_hash_find(EG(active_symbol_table)，varname， varname_len + 1，  (void**)&amp;varval) == FAILURE) {<br />
/* 变量根本并不存在-失败而导致退出*/<br />
return NULL;<br />
}<br />
if ((*varval)-＞refcount ＜ 2) {<br />
/*  varname是唯一的实际引用，<br />
*不需要进行分离<br />
*/<br />
return *varval;<br />
}<br />
/*  否则，再复制一份zval*的值*/<br />
MAKE_STD_ZVAL(varcopy);<br />
varcopy = *varval;<br />
/* 复制任何在zval*内的已分配的结构*/<br />
zval_copy_ctor(varcopy);<br />
/*删除旧版本的varname<br />
*这将减少该过程中varval的refcount的值<br />
*/<br />
zend_hash_del(EG(active_symbol_table)， varname， varname_len + 1);<br />
/* 初始化新创建的值的引用计数，并把它依附到<br />
* varname变量<br />
*/<br />
varcopy-＞refcount = 1;<br />
varcopy-＞is_ref = 0;<br />
zend_hash_add(EG(active_symbol_table)， varname，  varname_len + 1，&amp;varcopy， sizeof(zval*)， NULL);<br />
/*返回新的zval* */<br />
return varcopy;<br />
}</td>
</tr>
</tbody>
</table>
<p>现在，既然引擎有一个仅为变量$b所拥有的 zval*（引擎能知道这一点），所以它能够把这个值转换成一个long型值并根据脚本的请求给它增加5。</p>
<p><strong>七、  写改变（change-on-write）</strong></p>
<p>引用计数概念的引入还导致了一个新的数据操作可能性，其形式从用户空间脚本管理器 看来与&#8221;引用&#8221;有一定关系。请考虑下列的用户空间代码片断：</p>
<table border="1" width="90%" align="center" bgcolor="#e7e9e9" bordercolor="#cccccc">
<tbody>
<tr>
<td>＜?php<br />
$a = 1;<br />
$b = &amp;$a;<br />
$b += 5;<br />
?＞</td>
</tr>
</tbody>
</table>
<p>在上面的PHP代码中，你能看出$a的值现在为6，尽管它一开始为1并且从未(直接)发生变化。之所以会发生这种情况是因为当引擎开始把$b的值增加5 时，它注意到$b是一个对$a的引用并且认为&#8221;我可以改变该值而不必分离它，因为我想使所有的引用变量都能看到这一改变&#8221;。</p>
<p>但是，引 擎是如何知道的呢？很简单，它只要查看一下zval结构的第四个和最后一个元素（is_ref）即可。这是一个简单的开/关位，它定义了该值是否实际上是 一个用户空间风格引用集的一部分。在前面的代码片断中，当执行第一行时，为$a创建的值得到一个refcount为1，还有一个is_ref值为0，因为 它仅为一个变量($a)所拥有并且没有其它变量对它产生写引用改变。在第二行，这个值的refcount元素被增加为2，除了这次is_ref元素被置为 1之外（因为脚本中包含了一个&#8221;&amp;&#8221;符号以指示是完全引用）。</p>
<p>最后，在第三行，引擎再一次取出与变量$b相关的值并且检查是 否有必要进行分离。这一次该值没有被分离，因为前面没有包括一个检查。下面是get_var_and_separate()函数中与refcount检查 有关的部分代码：</p>
<table border="1" width="90%" align="center" bgcolor="#e7e9e9" bordercolor="#cccccc">
<tbody>
<tr>
<td>if ((*varval)-＞is_ref || (*varval)-＞refcount ＜ 2) {<br />
/*  varname是唯一的实际引用，<br />
* 或者它是对其它变量的一个完全引用<br />
*任何一种方式：都没有进行分离<br />
*/<br />
return *varval;<br />
}</td>
</tr>
</tbody>
</table>
<p>这一次，尽管refcount为2，却没有 实现分离，因为这个值是一个完全引用。引擎能够自由地修改它而不必关心其它变量值的变化。</p>
<p><strong>八、 分离问题</p>
<p></strong> 尽管已经存在上面讨论到的复制和引用技术，但是还存在一些不能通过is_ref和 refcount操作来解决的问题。请考虑下面这个PHP代码块：</p>
<table border="1" width="90%" align="center" bgcolor="#e7e9e9" bordercolor="#cccccc">
<tbody>
<tr>
<td>＜?php<br />
$a = 1;<br />
$b = $a;<br />
$c = &amp;$a;<br />
?＞</td>
</tr>
</tbody>
</table>
<p>在此，你有一个需要与三个不同的变量相关联的值。其中，两个变量是使用了&#8221;change-on-write&#8221;完全引用方式，而第三个变量处于一种可分离 的&#8221;copy-on-write&#8221;（写复制）上下文中。如果仅使用is_ref和refcount来描述这种关系，有哪些值能够工作呢？</p>
<p>回答是：没有一个能工作。在这种情况下，这个值必须被复制到两个分离的zval*中，尽管两者都包含完全相同的数据(见图2)。</p>
<table width="90%" align="center">
<tbody>
<tr>
<td>
<div><img src="http://dev.yesky.com/imagelist/06/43/84832guxf30g.jpg" border="1" alt="" /><br />
图 2.引用时强制分离</div>
</td>
</tr>
</tbody>
</table>
<p>同样，下列代码块将引起相同的冲突并且强迫该值分离出 一个副本(见图3)。</p>
<table width="90%" align="center">
<tbody>
<tr>
<td>
<div><img src="http://dev.yesky.com/imagelist/06/43/e01ss48f6bk1.jpg" border="1" alt="" /><br />
图 3.复制时强制分离</div>
</td>
</tr>
</tbody>
</table>
<table border="1" width="90%" align="center" bgcolor="#e7e9e9" bordercolor="#cccccc">
<tbody>
<tr>
<td>＜?php<br />
$a = 1;<br />
$b = &amp;$a;<br />
$c = $a;<br />
?＞</td>
</tr>
</tbody>
</table>
<p>注意，在这里的两种情况下，$b都与原始的zval对象相关联，因为在分离发生时引擎无法知道介于到该操作当中的第三个变量的名字。</p>
<p><strong>九、 总结</strong></p>
<p>PHP是一种托管语言。从普通用户角度来看，这种仔细地控制资源和内存的方式意味着更为容易地进行原型开 发并导致出现更少的冲突。然而，当我们深入&#8221;内里&#8221;之后，一切的承诺似乎都不复存在，最终还要依赖于真正有责任心的开发者来维持整个运行时刻环境的一致 性。</p>
<p><a href="http://dev.yesky.com/web/50/2636050.shtml" target="_blank">查 看本文来源</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.haohtml.com/index.php/archives/4367/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
