Tommy 碎碎念
https://blog.teatime.com.tw/
Tommy Wu's blog
tommy
2024-03-19T15:29:03Z
-
讓你的 php socket 程式支援 SOCKS5 與 HTTP CONNECT Proxy
https://blog.teatime.com.tw/1/post/438
<p>最近因為有些程式所在的環境, 對外連線有些麻煩, 所以... 就想加上 proxy 的支援, 而目前最常用的 proxy, 大概就是 <a href="http://en.wikipedia.org/wiki/SOCKS" target="_blank">SOCKS5</a> 或 HTTP Proxy 了.</p><p>一般 <a href="http://php.net/" target="_blank">php</a> 的程式, 對於 socket 的處理, 通常都是使用 <a href="http://php.net/manual/en/function.fsockopen.php" target="_blank">fsockopen()</a> 來處理. 而上頭兩類的 proxy, 都是在一開始連線時, 處理一些 handshake 的動作之後, 就不用再做任何處理了, 後續的動作與你直接連線都一樣. 所以... 我們只要寫一個 function, 用來取代 fsockopen(), 就可以簡單的加上 proxy 的支援了.</p><p>首先, 是對於 SOCKS 的部份:</p><pre class="php"><div class="insertcode"><pre class="php" style="font-family: monospace"> <span class="kw2">private</span> <span class="kw2">function</span> _proxy_socks5_open<span class="br0">(</span><span class="re0">$host</span><span class="sy0">,</span> <span class="re0">$port</span><span class="sy0">,</span> <span class="re0">$errno</span><span class="sy0">,</span> <span class="re0">$errstr</span><span class="sy0">,</span> <span class="re0">$timeout</span><span class="br0">)</span><br /> <span class="br0">{</span><br /> <span class="co1">// already define proxy host and port</span><br /> <span class="kw1">if</span> <span class="br0">(</span><span class="re0">$this</span><span class="sy0">-></span><span class="me1">proxy_host</span> <span class="sy0">===</span> <span class="kw4">false</span> <span class="sy0">||</span> <span class="re0">$this</span><span class="sy0">-></span><span class="me1">proxy_port</span> <span class="sy0">===</span> <span class="kw4">false</span><span class="br0">)</span><br /> <span class="kw1">return</span> <span class="kw4">false</span><span class="sy0">;</span><br /> <br /> <span class="co1">// connect to proxy server</span><br /> <span class="re0">$this</span><span class="sy0">-></span>_debug_print<span class="br0">(</span><span class="st0">"SOCKS: Trying to "</span><span class="sy0">.</span><span class="re0">$this</span><span class="sy0">-></span><span class="me1">proxy_host</span><span class="sy0">.</span><span class="st0">":"</span><span class="sy0">.</span><span class="re0">$this</span><span class="sy0">-></span><span class="me1">proxy_port</span><span class="sy0">.</span><span class="st0">" ...<span class="es1">\n</span>"</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="re0">$sock</span> <span class="sy0">=</span> <span class="sy0">@</span><a href="http://www.php.net/fsockopen"><span class="kw3">fsockopen</span></a><span class="br0">(</span><span class="re0">$this</span><span class="sy0">-></span><span class="me1">proxy_host</span><span class="sy0">,</span> <span class="re0">$this</span><span class="sy0">-></span><span class="me1">proxy_port</span><span class="sy0">,</span> <span class="re0">$errno</span><span class="sy0">,</span> <span class="re0">$errstr</span><span class="sy0">,</span> <span class="re0">$timeout</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="kw1">if</span> <span class="br0">(</span><span class="re0">$sock</span> <span class="sy0">===</span> <span class="kw4">false</span><span class="br0">)</span> <span class="br0">{</span><br /> <span class="re0">$this</span><span class="sy0">-></span>_debug_print<span class="br0">(</span><span class="st0">"SOCKS: fsockopen() "</span><span class="sy0">.</span><span class="re0">$errstr</span><span class="sy0">.</span><span class="st0">" ("</span><span class="sy0">.</span><span class="re0">$errno</span><span class="sy0">.</span><span class="st0">")<span class="es1">\n</span>"</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="kw1">return</span> <span class="kw4">false</span><span class="sy0">;</span><br /> <span class="br0">}</span><br /> <span class="re0">$this</span><span class="sy0">-></span>_debug_print<span class="br0">(</span><span class="st0">"SOCKS: Connected<span class="es1">\n</span>"</span><span class="br0">)</span><span class="sy0">;</span><br /> <br /> <span class="co1">// we have the proxy user and password or not</span><br /> <span class="kw1">if</span> <span class="br0">(</span><span class="re0">$this</span><span class="sy0">-></span><span class="me1">proxy_user</span> <span class="sy0">!==</span> <span class="kw4">false</span> <span class="sy0">&&</span> <span class="re0">$this</span><span class="sy0">-></span><span class="me1">proxy_pass</span> <span class="sy0">!==</span> <span class="kw4">false</span><span class="br0">)</span><br /> <span class="re0">$method</span> <span class="sy0">=</span> <span class="nu12">0x02</span><span class="sy0">;</span><br /> <span class="kw1">else</span><br /> <span class="re0">$method</span> <span class="sy0">=</span> <span class="nu12">0x00</span><span class="sy0">;</span><br /> <span class="co1">// sending version/method to proxy server</span><br /> <span class="kw1">if</span> <span class="br0">(</span><a href="http://www.php.net/fwrite"><span class="kw3">fwrite</span></a><span class="br0">(</span><span class="re0">$sock</span><span class="sy0">,</span> <a href="http://www.php.net/pack"><span class="kw3">pack</span></a><span class="br0">(</span><span class="st0">"C3"</span><span class="sy0">,</span> 0x05<span class="sy0">,</span> 0x01<span class="sy0">,</span> <span class="re0">$method</span><span class="br0">)</span><span class="br0">)</span> <span class="sy0">===</span> <span class="kw4">false</span><span class="br0">)</span> <span class="br0">{</span><br /> <a href="http://www.php.net/fclose"><span class="kw3">fclose</span></a><span class="br0">(</span><span class="re0">$sock</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="re0">$this</span><span class="sy0">-></span>_debug_print<span class="br0">(</span><span class="st0">"SOCKS: fwrite() error for version/method<span class="es1">\n</span>"</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="kw1">return</span> <span class="kw4">false</span><span class="sy0">;</span><br /> <span class="br0">}</span><br /> <span class="co1">// get response from proxy server</span><br /> <span class="re0">$buffer</span> <span class="sy0">=</span> <a href="http://www.php.net/fread"><span class="kw3">fread</span></a><span class="br0">(</span><span class="re0">$sock</span><span class="sy0">,</span> 1024<span class="br0">)</span><span class="sy0">;</span><br /> <span class="re0">$response</span> <span class="sy0">=</span> <a href="http://www.php.net/unpack"><span class="kw3">unpack</span></a><span class="br0">(</span><span class="st0">"Cversion/Cmethod"</span><span class="sy0">,</span> <span class="re0">$buffer</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="kw1">if</span> <span class="br0">(</span><span class="sy0">!</span><span class="br0">(</span><a href="http://www.php.net/isset"><span class="kw3">isset</span></a><span class="br0">(</span><span class="re0">$response</span><span class="br0">[</span><span class="st_h">'version'</span><span class="br0">]</span><span class="br0">)</span> <span class="sy0">&&</span> <a href="http://www.php.net/isset"><span class="kw3">isset</span></a><span class="br0">(</span><span class="re0">$response</span><span class="br0">[</span><span class="st_h">'method'</span><span class="br0">]</span><span class="br0">)</span> <span class="sy0">&&</span> <span class="re0">$response</span><span class="br0">[</span><span class="st_h">'version'</span><span class="br0">]</span> <span class="sy0">==</span> 0x05 <span class="sy0">&&</span> <span class="re0">$response</span><span class="br0">[</span><span class="st_h">'method'</span><span class="br0">]</span> <span class="sy0">==</span> <span class="re0">$method</span><span class="br0">)</span><span class="br0">)</span> <span class="br0">{</span><br /> <a href="http://www.php.net/fclose"><span class="kw3">fclose</span></a><span class="br0">(</span><span class="re0">$sock</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="re0">$this</span><span class="sy0">-></span>_debug_print<span class="br0">(</span><span class="st0">"SOCKS: unknown response (version/method): "</span><span class="sy0">.</span><a href="http://www.php.net/var_export"><span class="kw3">var_export</span></a><span class="br0">(</span><span class="re0">$response</span><span class="sy0">,</span> <span class="kw4">true</span><span class="br0">)</span><span class="sy0">.</span><span class="st0">"<span class="es1">\n</span>"</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="kw1">return</span> <span class="kw4">false</span><span class="sy0">;</span><br /> <span class="br0">}</span><br /> <br /> <span class="kw1">if</span> <span class="br0">(</span><span class="re0">$method</span> <span class="sy0">==</span> <span class="nu12">0x02</span><span class="br0">)</span> <span class="br0">{</span><br /> <span class="co1">// proxy server request username and password</span><br /> <span class="kw1">if</span> <span class="br0">(</span><a href="http://www.php.net/fwrite"><span class="kw3">fwrite</span></a><span class="br0">(</span><span class="re0">$sock</span><span class="sy0">,</span> <a href="http://www.php.net/pack"><span class="kw3">pack</span></a><span class="br0">(</span><span class="st0">"CC"</span><span class="sy0">,</span> 0x01<span class="sy0">,</span> <a href="http://www.php.net/strlen"><span class="kw3">strlen</span></a><span class="br0">(</span><span class="re0">$this</span><span class="sy0">-></span><span class="me1">proxy_user</span><span class="br0">)</span><span class="br0">)</span><span class="sy0">.</span><span class="re0">$this</span><span class="sy0">-></span><span class="me1">proxy_user</span><span class="sy0">.</span><br /> <a href="http://www.php.net/pack"><span class="kw3">pack</span></a><span class="br0">(</span><span class="st0">"C"</span><span class="sy0">,</span> <a href="http://www.php.net/strlen"><span class="kw3">strlen</span></a><span class="br0">(</span><span class="re0">$this</span><span class="sy0">-></span><span class="me1">proxy_pass</span><span class="br0">)</span><span class="br0">)</span><span class="sy0">.</span><span class="re0">$this</span><span class="sy0">-></span><span class="me1">proxy_pass</span><span class="br0">)</span> <span class="sy0">===</span> <span class="kw4">false</span><span class="br0">)</span> <span class="br0">{</span><br /> <a href="http://www.php.net/fclose"><span class="kw3">fclose</span></a><span class="br0">(</span><span class="re0">$sock</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="re0">$this</span><span class="sy0">-></span>_debug_print<span class="br0">(</span><span class="st0">"SOCKS: fwrite() error for username/password<span class="es1">\n</span>"</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="kw1">return</span> <span class="kw4">false</span><span class="sy0">;</span><br /> <span class="br0">}</span><br /> <span class="re0">$buffer</span> <span class="sy0">=</span> <a href="http://www.php.net/fread"><span class="kw3">fread</span></a><span class="br0">(</span><span class="re0">$sock</span><span class="sy0">,</span> 1024<span class="br0">)</span><span class="sy0">;</span><br /> <span class="re0">$response</span> <span class="sy0">=</span> <a href="http://www.php.net/unpack"><span class="kw3">unpack</span></a><span class="br0">(</span><span class="st0">"Cversion/Cstatus"</span><span class="sy0">,</span> <span class="re0">$buffer</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="kw1">if</span> <span class="br0">(</span><span class="sy0">!</span><span class="br0">(</span><a href="http://www.php.net/isset"><span class="kw3">isset</span></a><span class="br0">(</span><span class="re0">$response</span><span class="br0">[</span><span class="st_h">'status'</span><span class="br0">]</span><span class="br0">)</span> <span class="sy0">&&</span> <span class="re0">$response</span><span class="br0">[</span><span class="st_h">'status'</span><span class="br0">]</span> <span class="sy0">==</span> 0x00<span class="br0">)</span><span class="br0">)</span> <span class="br0">{</span><br /> <a href="http://www.php.net/fclose"><span class="kw3">fclose</span></a><span class="br0">(</span><span class="re0">$sock</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="re0">$this</span><span class="sy0">-></span>_debug_print<span class="br0">(</span><span class="st0">"SOCKS: auth failed<span class="es1">\n</span>"</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="kw1">return</span> <span class="kw4">false</span><span class="sy0">;</span><br /> <span class="br0">}</span><br /> <span class="co1">// pass the username/password check</span><br /> <span class="br0">}</span><br /> <span class="co1">// DNS perform in proxy or not</span><br /> <span class="kw1">if</span> <span class="br0">(</span><span class="re0">$this</span><span class="sy0">-></span><span class="me1">proxy_dns</span><span class="br0">)</span><br /> <span class="re0">$conn_str</span> <span class="sy0">=</span> <a href="http://www.php.net/pack"><span class="kw3">pack</span></a><span class="br0">(</span><span class="st0">"C5"</span><span class="sy0">,</span> 0x05<span class="sy0">,</span> 0x01<span class="sy0">,</span> 0x00<span class="sy0">,</span> 0x03<span class="sy0">,</span> <a href="http://www.php.net/strlen"><span class="kw3">strlen</span></a><span class="br0">(</span><span class="re0">$host</span><span class="br0">)</span><span class="br0">)</span><span class="sy0">.</span><span class="re0">$host</span><span class="sy0">.</span><a href="http://www.php.net/pack"><span class="kw3">pack</span></a><span class="br0">(</span><span class="st0">"n"</span><span class="sy0">,</span> <span class="re0">$port</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="kw1">else</span><br /> <span class="re0">$conn_str</span> <span class="sy0">=</span> <a href="http://www.php.net/pack"><span class="kw3">pack</span></a><span class="br0">(</span><span class="st0">"C4Nn"</span><span class="sy0">,</span> 0x05<span class="sy0">,</span> 0x01<span class="sy0">,</span> 0x00<span class="sy0">,</span> 0x01<span class="sy0">,</span> <a href="http://www.php.net/ip2long"><span class="kw3">ip2long</span></a><span class="br0">(</span><a href="http://www.php.net/gethostbyname"><span class="kw3">gethostbyname</span></a><span class="br0">(</span><span class="re0">$host</span><span class="br0">)</span><span class="br0">)</span><span class="sy0">,</span> <span class="re0">$port</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="co1">// connect it</span><br /> <span class="kw1">if</span> <span class="br0">(</span><a href="http://www.php.net/fwrite"><span class="kw3">fwrite</span></a><span class="br0">(</span><span class="re0">$sock</span><span class="sy0">,</span> <span class="re0">$conn_str</span><span class="br0">)</span> <span class="sy0">===</span> <span class="kw4">false</span><span class="br0">)</span> <span class="br0">{</span><br /> <a href="http://www.php.net/fclose"><span class="kw3">fclose</span></a><span class="br0">(</span><span class="re0">$sock</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="re0">$this</span><span class="sy0">-></span>_debug_print<span class="br0">(</span><span class="st0">"SOCKS: fwrite() error<span class="es1">\n</span>"</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="kw1">return</span> <span class="kw4">false</span><span class="sy0">;</span><br /> <span class="br0">}</span><br /> <span class="re0">$buffer</span> <span class="sy0">=</span> <a href="http://www.php.net/fread"><span class="kw3">fread</span></a><span class="br0">(</span><span class="re0">$sock</span><span class="sy0">,</span> 1024<span class="br0">)</span><span class="sy0">;</span><br /> <span class="re0">$response</span> <span class="sy0">=</span> <a href="http://www.php.net/unpack"><span class="kw3">unpack</span></a><span class="br0">(</span><span class="st0">"Cversion/Cresult/Creg/Ctype/Lip/Sport"</span><span class="sy0">,</span> <span class="re0">$buffer</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="kw1">if</span> <span class="br0">(</span><a href="http://www.php.net/isset"><span class="kw3">isset</span></a><span class="br0">(</span><span class="re0">$response</span><span class="br0">[</span><span class="st_h">'version'</span><span class="br0">]</span><span class="br0">)</span> <span class="sy0">&&</span> <a href="http://www.php.net/isset"><span class="kw3">isset</span></a><span class="br0">(</span><span class="re0">$response</span><span class="br0">[</span><span class="st_h">'result'</span><span class="br0">]</span><span class="br0">)</span> <span class="sy0">&&</span> <span class="re0">$response</span><span class="br0">[</span><span class="st_h">'version'</span><span class="br0">]</span> <span class="sy0">==</span> 0x05 <span class="sy0">&&</span> <span class="re0">$response</span><span class="br0">[</span><span class="st_h">'result'</span><span class="br0">]</span> <span class="sy0">==</span> <span class="nu12">0x00</span><span class="br0">)</span> <span class="br0">{</span><br /> <span class="co1">// yes, we already connect it via proxy</span><br /> <span class="re0">$this</span><span class="sy0">-></span>_debug_print<span class="br0">(</span><span class="st0">"SOCKS: OK<span class="es1">\n</span>"</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="kw1">return</span> <span class="re0">$sock</span><span class="sy0">;</span><br /> <span class="br0">}</span><br /> <a href="http://www.php.net/fclose"><span class="kw3">fclose</span></a><span class="br0">(</span><span class="re0">$sock</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="re0">$this</span><span class="sy0">-></span>_debug_print<span class="br0">(</span><span class="st0">"SOCKS: error<span class="es1">\n</span>"</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="kw1">return</span> <span class="kw4">false</span><span class="sy0">;</span><br /> <span class="br0">}</span></pre></div></pre><p>在這個函式中, 連線到 proxy server, 再依據需求送出登入的帳號密碼, 成功後就把 socket handle 回傳, 若失敗就傳回 false.</p><p>接著是 http proxy 的部份:</p><pre class="php"><div class="insertcode"><pre class="php" style="font-family: monospace"> <span class="kw2">private</span> <span class="kw2">function</span> _proxy_http_open<span class="br0">(</span><span class="re0">$host</span><span class="sy0">,</span> <span class="re0">$port</span><span class="sy0">,</span> <span class="re0">$errno</span><span class="sy0">,</span> <span class="re0">$errstr</span><span class="sy0">,</span> <span class="re0">$timeout</span><span class="br0">)</span><br /> <span class="br0">{</span><br /> <span class="co1">// already define proxy host and port</span><br /> <span class="kw1">if</span> <span class="br0">(</span><span class="re0">$this</span><span class="sy0">-></span><span class="me1">proxy_host</span> <span class="sy0">===</span> <span class="kw4">false</span> <span class="sy0">||</span> <span class="re0">$this</span><span class="sy0">-></span><span class="me1">proxy_port</span> <span class="sy0">===</span> <span class="kw4">false</span><span class="br0">)</span><br /> <span class="kw1">return</span> <span class="kw4">false</span><span class="sy0">;</span><br /> <br /> <span class="co1">// connect to proxy server</span><br /> <span class="re0">$this</span><span class="sy0">-></span>_debug_print<span class="br0">(</span><span class="st0">"HTTP: Trying to "</span><span class="sy0">.</span><span class="re0">$this</span><span class="sy0">-></span><span class="me1">proxy_host</span><span class="sy0">.</span><span class="st0">":"</span><span class="sy0">.</span><span class="re0">$this</span><span class="sy0">-></span><span class="me1">proxy_port</span><span class="sy0">.</span><span class="st0">" ...<span class="es1">\n</span>"</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="re0">$sock</span> <span class="sy0">=</span> <span class="sy0">@</span><a href="http://www.php.net/fsockopen"><span class="kw3">fsockopen</span></a><span class="br0">(</span><span class="re0">$this</span><span class="sy0">-></span><span class="me1">proxy_host</span><span class="sy0">,</span> <span class="re0">$this</span><span class="sy0">-></span><span class="me1">proxy_port</span><span class="sy0">,</span> <span class="re0">$errno</span><span class="sy0">,</span> <span class="re0">$errstr</span><span class="sy0">,</span> <span class="re0">$timeout</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="kw1">if</span> <span class="br0">(</span><span class="re0">$sock</span> <span class="sy0">===</span> <span class="kw4">false</span><span class="br0">)</span> <span class="br0">{</span><br /> <span class="re0">$this</span><span class="sy0">-></span>_debug_print<span class="br0">(</span><span class="st0">"HTTP: fsockopen() "</span><span class="sy0">.</span><span class="re0">$errstr</span><span class="sy0">.</span><span class="st0">" ("</span><span class="sy0">.</span><span class="re0">$errno</span><span class="sy0">.</span><span class="st0">")<span class="es1">\n</span>"</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="kw1">return</span> <span class="kw4">false</span><span class="sy0">;</span><br /> <span class="br0">}</span><br /> <span class="re0">$this</span><span class="sy0">-></span>_debug_print<span class="br0">(</span><span class="st0">"HTTP: Connected<span class="es1">\n</span>"</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="re0">$conn_str</span> <span class="sy0">=</span> <span class="st0">"CONNECT "</span><span class="sy0">.</span><span class="re0">$host</span><span class="sy0">.</span><span class="st0">":"</span><span class="sy0">.</span><span class="re0">$port</span><span class="sy0">.</span><span class="st0">" HTTP/1.1<span class="es1">\r</span><span class="es1">\n</span>Host: "</span><span class="sy0">.</span><span class="re0">$host</span><span class="sy0">.</span><span class="st0">":"</span><span class="sy0">.</span><span class="re0">$port</span><span class="sy0">.</span><span class="st0">"<span class="es1">\r</span><span class="es1">\n</span>User-Agent: ftp.cls.php<span class="es1">\r</span><span class="es1">\n</span><span class="es1">\r</span><span class="es1">\n</span>"</span><span class="sy0">;</span><br /> <span class="re0">$this</span><span class="sy0">-></span>_debug_print<span class="br0">(</span><span class="st0">"HTTP: send => '<span class="es4">$conn_str</span>'<span class="es1">\n</span>"</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="kw1">if</span> <span class="br0">(</span><a href="http://www.php.net/fwrite"><span class="kw3">fwrite</span></a><span class="br0">(</span><span class="re0">$sock</span><span class="sy0">,</span> <span class="re0">$conn_str</span><span class="br0">)</span> <span class="sy0">===</span> <span class="kw4">false</span><span class="br0">)</span> <span class="br0">{</span><br /> <a href="http://www.php.net/fclose"><span class="kw3">fclose</span></a><span class="br0">(</span><span class="re0">$sock</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="re0">$this</span><span class="sy0">-></span>_debug_print<span class="br0">(</span><span class="st0">"HTTP: fwrite() error<span class="es1">\n</span>"</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="kw1">return</span> <span class="kw4">false</span><span class="sy0">;</span><br /> <span class="br0">}</span><br /> <span class="re0">$buffer</span> <span class="sy0">=</span> <a href="http://www.php.net/fgets"><span class="kw3">fgets</span></a><span class="br0">(</span><span class="re0">$sock</span><span class="sy0">,</span> 1024<span class="br0">)</span><span class="sy0">;</span><br /> <span class="re0">$response</span> <span class="sy0">=</span> <a href="http://www.php.net/rtrim"><span class="kw3">rtrim</span></a><span class="br0">(</span><span class="re0">$buffer</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="re0">$this</span><span class="sy0">-></span>_debug_print<span class="br0">(</span><span class="st0">"HTTP: data => '"</span><span class="sy0">.</span><a href="http://www.php.net/rtrim"><span class="kw3">rtrim</span></a><span class="br0">(</span><span class="re0">$buffer</span><span class="br0">)</span><span class="sy0">.</span><span class="st0">"'<span class="es1">\n</span>"</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="co1">// read following header/body</span><br /> <span class="re0">$auth_array</span> <span class="sy0">=</span> <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">(</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="re0">$auth_header</span> <span class="sy0">=</span> <span class="st_h">''</span><span class="sy0">;</span><br /> <span class="re0">$content_length</span> <span class="sy0">=</span> <span class="nu0">0</span><span class="sy0">;</span><br /> <span class="kw1">while</span> <span class="br0">(</span><span class="sy0">!</span><a href="http://www.php.net/feof"><span class="kw3">feof</span></a><span class="br0">(</span><span class="re0">$sock</span><span class="br0">)</span><span class="br0">)</span> <span class="br0">{</span><br /> <span class="re0">$buffer</span> <span class="sy0">=</span> <a href="http://www.php.net/fgets"><span class="kw3">fgets</span></a><span class="br0">(</span><span class="re0">$sock</span><span class="sy0">,</span> 1024<span class="br0">)</span><span class="sy0">;</span><br /> <span class="re0">$this</span><span class="sy0">-></span>_debug_print<span class="br0">(</span><span class="st0">"HTTP: header => '"</span><span class="sy0">.</span><a href="http://www.php.net/rtrim"><span class="kw3">rtrim</span></a><span class="br0">(</span><span class="re0">$buffer</span><span class="br0">)</span><span class="sy0">.</span><span class="st0">"'<span class="es1">\n</span>"</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="kw1">if</span> <span class="br0">(</span><a href="http://www.php.net/substr"><span class="kw3">substr</span></a><span class="br0">(</span><span class="re0">$buffer</span><span class="sy0">,</span> <span class="nu0">0</span><span class="sy0">,</span> <span class="nu0">1</span><span class="br0">)</span> <span class="sy0">==</span> <span class="st_h">' '</span> <span class="sy0">&&</span> <span class="re0">$auth_header</span> <span class="sy0">!==</span> <span class="st_h">''</span><span class="br0">)</span> <span class="br0">{</span><br /> <span class="re0">$auth_header</span> <span class="sy0">.=</span> <a href="http://www.php.net/rtrim"><span class="kw3">rtrim</span></a><span class="br0">(</span><span class="re0">$buffer</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="kw1">continue</span><span class="sy0">;</span><br /> <span class="br0">}</span><br /> <span class="co1">// end of header</span><br /> <span class="kw1">if</span> <span class="br0">(</span><span class="re0">$buffer</span> <span class="sy0">===</span> <span class="st0">"<span class="es1">\r</span><span class="es1">\n</span>"</span><span class="br0">)</span><br /> <span class="kw1">break</span><span class="sy0">;</span><br /> <span class="kw1">if</span> <span class="br0">(</span><a href="http://www.php.net/strncasecmp"><span class="kw3">strncasecmp</span></a><span class="br0">(</span><span class="re0">$buffer</span><span class="sy0">,</span> <span class="st_h">'Proxy-Authenticate:'</span><span class="sy0">,</span> <span class="nu0">19</span><span class="br0">)</span> <span class="sy0">==</span> <span class="nu0">0</span><span class="br0">)</span> <span class="br0">{</span><br /> <span class="co1">// Proxy-Authenticate: Digest realm="TeaTime Squid Proxy Server", nonce="Cjz/UAAAAADQEPuX/H8AAGmnlR0AAAAA", qop="auth", stale=false</span><br /> <span class="kw1">if</span> <span class="br0">(</span><span class="re0">$auth_header</span> <span class="sy0">!==</span> <span class="st_h">''</span><span class="br0">)</span><br /> <span class="re0">$auth_array</span><span class="br0">[</span><span class="br0">]</span> <span class="sy0">=</span> <span class="re0">$auth_header</span><span class="sy0">;</span><br /> <span class="re0">$auth_header</span> <span class="sy0">=</span> <a href="http://www.php.net/rtrim"><span class="kw3">rtrim</span></a><span class="br0">(</span><span class="re0">$buffer</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="br0">}</span><br /> <span class="kw1">if</span> <span class="br0">(</span><a href="http://www.php.net/strncasecmp"><span class="kw3">strncasecmp</span></a><span class="br0">(</span><span class="re0">$buffer</span><span class="sy0">,</span> <span class="st_h">'Content-Length:'</span><span class="sy0">,</span> <span class="nu0">15</span><span class="br0">)</span> <span class="sy0">==</span> <span class="nu0">0</span><span class="br0">)</span> <span class="br0">{</span><br /> <span class="co1">// Content-Length: 3123</span><br /> <span class="re0">$content_length</span> <span class="sy0">=</span> <a href="http://www.php.net/trim"><span class="kw3">trim</span></a><span class="br0">(</span><a href="http://www.php.net/substr"><span class="kw3">substr</span></a><span class="br0">(</span><span class="re0">$buffer</span><span class="sy0">,</span> 15<span class="br0">)</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="br0">}</span><br /> <span class="br0">}</span><br /> <span class="kw1">if</span> <span class="br0">(</span><span class="re0">$auth_header</span> <span class="sy0">!==</span> <span class="st_h">''</span><span class="br0">)</span><br /> <span class="re0">$auth_array</span><span class="br0">[</span><span class="br0">]</span> <span class="sy0">=</span> <span class="re0">$auth_header</span><span class="sy0">;</span><br /> <span class="re0">$body</span> <span class="sy0">=</span> <span class="st_h">''</span><span class="sy0">;</span><br /> <span class="kw1">if</span> <span class="br0">(</span><span class="re0">$content_length</span> <span class="sy0">!=</span> 0<span class="br0">)</span> <span class="br0">{</span><br /> <span class="kw1">while</span> <span class="br0">(</span><span class="re0">$content_length</span> <span class="sy0">></span> 0<span class="br0">)</span> <span class="br0">{</span><br /> <span class="re0">$data</span> <span class="sy0">=</span> <a href="http://www.php.net/fread"><span class="kw3">fread</span></a><span class="br0">(</span><span class="re0">$sock</span><span class="sy0">,</span> <span class="re0">$content_length</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="re0">$body</span> <span class="sy0">.=</span> <span class="re0">$data</span><span class="sy0">;</span><br /> <span class="re0">$content_length</span> <span class="sy0">=</span> <span class="re0">$content_length</span> <span class="sy0">-</span> <a href="http://www.php.net/strlen"><span class="kw3">strlen</span></a><span class="br0">(</span><span class="re0">$data</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="br0">}</span><br /> <span class="re0">$this</span><span class="sy0">-></span>_debug_print<span class="br0">(</span><span class="st0">"HTTP: body => '"</span><span class="sy0">.</span><span class="re0">$body</span><span class="sy0">.</span><span class="st0">"'<span class="es1">\n</span>"</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="br0">}</span><br /> <a href="http://www.php.net/fclose"><span class="kw3">fclose</span></a><span class="br0">(</span><span class="re0">$sock</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="kw1">if</span> <span class="br0">(</span><a href="http://www.php.net/strtolower"><span class="kw3">strtolower</span></a><span class="br0">(</span><a href="http://www.php.net/substr"><span class="kw3">substr</span></a><span class="br0">(</span><span class="re0">$response</span><span class="sy0">,</span> <span class="nu0">0</span><span class="sy0">,</span> <span class="nu0">7</span><span class="br0">)</span><span class="br0">)</span> <span class="sy0">!=</span> <span class="st_h">'http/1.'</span><span class="br0">)</span> <span class="br0">{</span><br /> <span class="re0">$this</span><span class="sy0">-></span>_debug_print<span class="br0">(</span><span class="st0">"HTTP: error<span class="es1">\n</span>"</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="kw1">return</span> <span class="kw4">false</span><span class="sy0">;</span><br /> <span class="br0">}</span><br /> <span class="re0">$code</span> <span class="sy0">=</span> <a href="http://www.php.net/substr"><span class="kw3">substr</span></a><span class="br0">(</span><span class="re0">$response</span><span class="sy0">,</span> 9<span class="sy0">,</span> 3<span class="br0">)</span><span class="sy0">;</span><br /> <span class="kw1">if</span> <span class="br0">(</span><span class="re0">$code</span><span class="br0">[</span><span class="nu0">0</span><span class="br0">]</span> <span class="sy0">==</span> <span class="st_h">'2'</span><span class="br0">)</span> <span class="br0">{</span><br /> <span class="co1">// yes, we already connect it via proxy</span><br /> <span class="re0">$this</span><span class="sy0">-></span>_debug_print<span class="br0">(</span><span class="st0">"HTTP: OK<span class="es1">\n</span>"</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="kw1">return</span> <span class="re0">$sock</span><span class="sy0">;</span><br /> <span class="br0">}</span><br /> <span class="kw1">if</span> <span class="br0">(</span><span class="re0">$code</span> <span class="sy0">!=</span> <span class="st0">"407"</span> <span class="sy0">&&</span> <span class="re0">$code</span> <span class="sy0">!=</span> <span class="st0">"401"</span><span class="br0">)</span> <span class="br0">{</span><br /> <span class="re0">$this</span><span class="sy0">-></span>_debug_print<span class="br0">(</span><span class="st0">"HTTP: error<span class="es1">\n</span>"</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="kw1">return</span> <span class="kw4">false</span><span class="sy0">;</span><br /> <span class="br0">}</span><br /> <span class="co1">// need auth here</span><br /> <span class="kw1">if</span> <span class="br0">(</span><span class="re0">$this</span><span class="sy0">-></span><span class="me1">proxy_user</span> <span class="sy0">===</span> <span class="kw4">false</span> <span class="sy0">||</span> <span class="re0">$this</span><span class="sy0">-></span><span class="me1">proxy_pass</span> <span class="sy0">===</span> <span class="kw4">false</span><span class="br0">)</span> <span class="br0">{</span><br /> <span class="re0">$this</span><span class="sy0">-></span>_debug_print<span class="br0">(</span><span class="st0">"HTTP: error<span class="es1">\n</span>"</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="kw1">return</span> <span class="kw4">false</span><span class="sy0">;</span><br /> <span class="br0">}</span><br /> <span class="kw1">if</span> <span class="br0">(</span><a href="http://www.php.net/count"><span class="kw3">count</span></a><span class="br0">(</span><span class="re0">$auth_array</span><span class="br0">)</span> <span class="sy0">==</span> <span class="nu0">0</span><span class="br0">)</span> <span class="br0">{</span><br /> <span class="co1">// no Proxy-Authenticate:</span><br /> <span class="re0">$this</span><span class="sy0">-></span>_debug_print<span class="br0">(</span><span class="st0">"HTTP: error<span class="es1">\n</span>"</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="kw1">return</span> <span class="kw4">false</span><span class="sy0">;</span><br /> <span class="br0">}</span><br /> <span class="kw1">foreach</span> <span class="br0">(</span><span class="re0">$auth_array</span> <span class="kw1">as</span> <span class="re0">$auth_header</span><span class="br0">)</span> <span class="br0">{</span><br /> <span class="re0">$this</span><span class="sy0">-></span>_debug_print<span class="br0">(</span><span class="st0">"HTTP: auth_header => '<span class="es4">$auth_header</span>'<span class="es1">\n</span>"</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="re0">$auth_data</span> <span class="sy0">=</span> <a href="http://www.php.net/trim"><span class="kw3">trim</span></a><span class="br0">(</span><a href="http://www.php.net/substr"><span class="kw3">substr</span></a><span class="br0">(</span><span class="re0">$auth_header</span><span class="sy0">,</span> 19<span class="br0">)</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="kw1">if</span> <span class="br0">(</span><a href="http://www.php.net/strncasecmp"><span class="kw3">strncasecmp</span></a><span class="br0">(</span><span class="re0">$auth_data</span><span class="sy0">,</span> <span class="st_h">'Digest '</span><span class="sy0">,</span> <span class="nu0">7</span><span class="br0">)</span> <span class="sy0">==</span> <span class="nu0">0</span><span class="br0">)</span> <span class="br0">{</span><br /> <span class="co1">// method Digest</span><br /> <span class="re0">$token</span> <span class="sy0">=</span> <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">(</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="re0">$data</span> <span class="sy0">=</span> <a href="http://www.php.net/explode"><span class="kw3">explode</span></a><span class="br0">(</span><span class="st0">","</span><span class="sy0">,</span> <a href="http://www.php.net/substr"><span class="kw3">substr</span></a><span class="br0">(</span><span class="re0">$auth_data</span><span class="sy0">,</span> 7<span class="br0">)</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="kw1">foreach</span> <span class="br0">(</span><span class="re0">$data</span> <span class="kw1">as</span> <span class="re0">$v</span><span class="br0">)</span> <span class="br0">{</span><br /> <span class="re0">$item</span> <span class="sy0">=</span> <a href="http://www.php.net/explode"><span class="kw3">explode</span></a><span class="br0">(</span><span class="st0">"="</span><span class="sy0">,</span> <span class="re0">$v</span><span class="sy0">,</span> 2<span class="br0">)</span><span class="sy0">;</span><br /> <span class="re0">$name</span> <span class="sy0">=</span> <a href="http://www.php.net/trim"><span class="kw3">trim</span></a><span class="br0">(</span><span class="re0">$item</span><span class="br0">[</span>0<span class="br0">]</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="re0">$value</span> <span class="sy0">=</span> <a href="http://www.php.net/trim"><span class="kw3">trim</span></a><span class="br0">(</span><span class="re0">$item</span><span class="br0">[</span>1<span class="br0">]</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="kw1">if</span> <span class="br0">(</span><span class="re0">$value</span><span class="br0">[</span><span class="nu0">0</span><span class="br0">]</span> <span class="sy0">==</span> <span class="st_h">'"'</span><span class="br0">)</span><br /> <span class="re0">$value</span> <span class="sy0">=</span> <a href="http://www.php.net/substr"><span class="kw3">substr</span></a><span class="br0">(</span><span class="re0">$value</span><span class="sy0">,</span> 1<span class="sy0">,</span> <a href="http://www.php.net/strlen"><span class="kw3">strlen</span></a><span class="br0">(</span><span class="re0">$value</span><span class="br0">)</span> <span class="sy0">-</span> 2<span class="br0">)</span><span class="sy0">;</span><br /> <span class="re0">$token</span><span class="br0">[</span><span class="re0">$name</span><span class="br0">]</span> <span class="sy0">=</span> <span class="re0">$value</span><span class="sy0">;</span><br /> <span class="br0">}</span><br /> <span class="kw1">if</span> <span class="br0">(</span><span class="sy0">!</span><a href="http://www.php.net/array_key_exists"><span class="kw3">array_key_exists</span></a><span class="br0">(</span><span class="st0">"nonce"</span><span class="sy0">,</span> <span class="re0">$token</span><span class="br0">)</span><span class="br0">)</span> <span class="br0">{</span><br /> <span class="co1">// nonce not found</span><br /> <span class="re0">$this</span><span class="sy0">-></span>_debug_print<span class="br0">(</span><span class="st0">"HTTP: error (nonce not found)<span class="es1">\n</span>"</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="kw1">continue</span><span class="sy0">;</span><br /> <span class="br0">}</span><br /> <span class="kw1">if</span> <span class="br0">(</span><span class="sy0">!</span><a href="http://www.php.net/array_key_exists"><span class="kw3">array_key_exists</span></a><span class="br0">(</span><span class="st0">"realm"</span><span class="sy0">,</span> <span class="re0">$token</span><span class="br0">)</span><span class="br0">)</span> <span class="br0">{</span><br /> <span class="co1">// realm not found</span><br /> <span class="re0">$this</span><span class="sy0">-></span>_debug_print<span class="br0">(</span><span class="st0">"HTTP: error (realm not found)<span class="es1">\n</span>"</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="kw1">continue</span><span class="sy0">;</span><br /> <span class="br0">}</span><br /> <span class="co1">// HA1 = md5(username:realm:password)</span><br /> <span class="co1">// if qop = auth or no qop</span><br /> <span class="co1">// HA2 = md5(method:digestURI)</span><br /> <span class="co1">// if qop = auth-int</span><br /> <span class="co1">// HA2 = md5(method:digestURI:md5(body))</span><br /> <span class="co1">// if qop = auth or auth-int</span><br /> <span class="co1">// response = md5(HA1:nonce:nonceCount:clientNonce:qop:HA2)</span><br /> <span class="co1">// if no qop</span><br /> <span class="co1">// response = md5(HA1:nonce:HA2)</span><br /> <span class="re0">$clientNonce</span> <span class="sy0">=</span> <span class="st_h">''</span><span class="sy0">;</span><br /> <span class="re0">$ha1</span> <span class="sy0">=</span> <a href="http://www.php.net/md5"><span class="kw3">md5</span></a><span class="br0">(</span><span class="re0">$this</span><span class="sy0">-></span><span class="me1">proxy_user</span><span class="sy0">.</span><span class="st0">":"</span><span class="sy0">.</span><span class="re0">$token</span><span class="br0">[</span><span class="st0">"realm"</span><span class="br0">]</span><span class="sy0">.</span><span class="st0">":"</span><span class="sy0">.</span><span class="re0">$this</span><span class="sy0">-></span><span class="me1">proxy_pass</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="kw1">if</span> <span class="br0">(</span><span class="sy0">!</span><a href="http://www.php.net/array_key_exists"><span class="kw3">array_key_exists</span></a><span class="br0">(</span><span class="st0">"qop"</span><span class="sy0">,</span> <span class="re0">$token</span><span class="br0">)</span><span class="br0">)</span> <span class="br0">{</span><br /> <span class="re0">$ha2</span> <span class="sy0">=</span> <a href="http://www.php.net/md5"><span class="kw3">md5</span></a><span class="br0">(</span><span class="st0">"CONNECT:"</span><span class="sy0">.</span><span class="re0">$host</span><span class="sy0">.</span><span class="st0">":"</span><span class="sy0">.</span><span class="re0">$port</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="re0">$response</span> <span class="sy0">=</span> <a href="http://www.php.net/md5"><span class="kw3">md5</span></a><span class="br0">(</span><span class="re0">$ha1</span><span class="sy0">.</span><span class="st0">":"</span><span class="sy0">.</span><span class="re0">$token</span><span class="br0">[</span><span class="st0">"nonce"</span><span class="br0">]</span><span class="sy0">.</span><span class="st0">":"</span><span class="sy0">.</span><span class="re0">$ha2</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="br0">}</span><br /> <span class="kw1">else</span> <span class="br0">{</span><br /> <span class="re0">$qop_array</span> <span class="sy0">=</span> <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">(</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="kw1">foreach</span> <span class="br0">(</span><a href="http://www.php.net/explode"><span class="kw3">explode</span></a><span class="br0">(</span><span class="st0">","</span><span class="sy0">,</span> <span class="re0">$token</span><span class="br0">[</span><span class="st0">"qop"</span><span class="br0">]</span><span class="br0">)</span> <span class="kw1">as</span> <span class="re0">$v</span><span class="br0">)</span> <span class="br0">{</span><br /> <span class="re0">$qop_array</span><span class="br0">[</span><span class="br0">]</span> <span class="sy0">=</span> <a href="http://www.php.net/strtolower"><span class="kw3">strtolower</span></a><span class="br0">(</span><a href="http://www.php.net/trim"><span class="kw3">trim</span></a><span class="br0">(</span><span class="re0">$v</span><span class="br0">)</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="br0">}</span><br /> <span class="kw1">if</span> <span class="br0">(</span><a href="http://www.php.net/in_array"><span class="kw3">in_array</span></a><span class="br0">(</span><span class="st0">"auth"</span><span class="sy0">,</span> <span class="re0">$qop_array</span><span class="br0">)</span><span class="br0">)</span> <span class="br0">{</span><br /> <span class="re0">$qop</span> <span class="sy0">=</span> <span class="st0">"auth"</span><span class="sy0">;</span><br /> <span class="re0">$ha2</span> <span class="sy0">=</span> <a href="http://www.php.net/md5"><span class="kw3">md5</span></a><span class="br0">(</span><span class="st0">"CONNECT:"</span><span class="sy0">.</span><span class="re0">$host</span><span class="sy0">.</span><span class="st0">":"</span><span class="sy0">.</span><span class="re0">$port</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="br0">}</span><br /> <span class="kw1">else</span> <span class="kw1">if</span> <span class="br0">(</span><a href="http://www.php.net/in_array"><span class="kw3">in_array</span></a><span class="br0">(</span><span class="st0">"auth-int"</span><span class="sy0">,</span> <span class="re0">$qop_array</span><span class="br0">)</span><span class="br0">)</span> <span class="br0">{</span><br /> <span class="re0">$qop</span> <span class="sy0">=</span> <span class="st0">"auth-int"</span><span class="sy0">;</span><br /> <span class="re0">$ha2</span> <span class="sy0">=</span> <a href="http://www.php.net/md5"><span class="kw3">md5</span></a><span class="br0">(</span><span class="st0">"CONNECT:"</span><span class="sy0">.</span><span class="re0">$host</span><span class="sy0">.</span><span class="st0">":"</span><span class="sy0">.</span><span class="re0">$port</span><span class="sy0">.</span><span class="st0">":"</span><span class="sy0">.</span><span class="re0">$body</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="br0">}</span><br /> <span class="kw1">else</span> <span class="br0">{</span><br /> <span class="co1">// noknown qop</span><br /> <span class="re0">$this</span><span class="sy0">-></span>_debug_print<span class="br0">(</span><span class="st0">"HTTP: error (unknown qop: "</span><span class="sy0">.</span><span class="re0">$token</span><span class="br0">[</span><span class="st0">"qop"</span><span class="br0">]</span><span class="sy0">.</span><span class="st0">")<span class="es1">\n</span>"</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="kw1">continue</span><span class="sy0">;</span><br /> <span class="br0">}</span><br /> <span class="re0">$clientNonce</span> <span class="sy0">=</span> <a href="http://www.php.net/sprintf"><span class="kw3">sprintf</span></a><span class="br0">(</span><span class="st0">"<span class="es6">%08x</span>"</span><span class="sy0">,</span> <a href="http://www.php.net/time"><span class="kw3">time</span></a><span class="br0">(</span><span class="br0">)</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="re0">$response</span> <span class="sy0">=</span> <a href="http://www.php.net/md5"><span class="kw3">md5</span></a><span class="br0">(</span><span class="re0">$ha1</span><span class="sy0">.</span><span class="st0">":"</span><span class="sy0">.</span><span class="re0">$token</span><span class="br0">[</span><span class="st0">"nonce"</span><span class="br0">]</span><span class="sy0">.</span><span class="st0">":00000001:"</span><span class="sy0">.</span><span class="re0">$clientNonce</span><span class="sy0">.</span><span class="st0">":"</span><span class="sy0">.</span><span class="re0">$qop</span><span class="sy0">.</span><span class="st0">":"</span><span class="sy0">.</span><span class="re0">$ha2</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="br0">}</span><br /> <span class="re0">$proxy_header</span> <span class="sy0">=</span> <span class="st0">"Digest username=<span class="es1">\"</span>"</span><span class="sy0">.</span><span class="re0">$this</span><span class="sy0">-></span><span class="me1">proxy_user</span><span class="sy0">.</span><span class="st0">"<span class="es1">\"</span>, realm=<span class="es1">\"</span>"</span><span class="sy0">.</span><span class="re0">$token</span><span class="br0">[</span><span class="st0">"realm"</span><span class="br0">]</span><span class="sy0">.</span><span class="st0">"<span class="es1">\"</span>, nonce=<span class="es1">\"</span>"</span><span class="sy0">.</span><span class="re0">$token</span><span class="br0">[</span><span class="st0">"nonce"</span><span class="br0">]</span><span class="sy0">.</span><span class="st0">"<span class="es1">\"</span>, uri=<span class="es1">\"</span>"</span><span class="sy0">.</span><span class="re0">$host</span><span class="sy0">.</span><span class="st0">":"</span><span class="sy0">.</span><span class="re0">$port</span><span class="sy0">.</span><span class="st0">"<span class="es1">\"</span>, response=<span class="es1">\"</span>"</span><span class="sy0">.</span><span class="re0">$response</span><span class="sy0">.</span><span class="st0">"<span class="es1">\"</span>"</span><span class="sy0">;</span><br /> <span class="kw1">if</span> <span class="br0">(</span><span class="re0">$clientNonce</span> <span class="sy0">!==</span> <span class="st_h">''</span><span class="br0">)</span><br /> <span class="re0">$proxy_header</span> <span class="sy0">.=</span> <span class="st0">", qop="</span><span class="sy0">.</span><span class="re0">$qop</span><span class="sy0">.</span><span class="st0">", nc=00000001, cnonce=<span class="es1">\"</span>"</span><span class="sy0">.</span><span class="re0">$clientNonce</span><span class="sy0">.</span><span class="st0">"<span class="es1">\"</span>"</span><span class="sy0">;</span><br /> <span class="co1">// Proxy-Authorization: Digest username="tommy", realm="TeaTime Squid Proxy Server", nonce="h0n/UAAAAABQTgaY/H8AAFj8wDEAAAAA", uri="/phpsysinfo/index.php?disp=dynamic", response="e63732269c77d70b344f8dd650d6f753", qop=auth, nc=00000001, cnonce="557152171b138196"</span><br /> <br /> <span class="co1">// connect to proxy server</span><br /> <span class="re0">$this</span><span class="sy0">-></span>_debug_print<span class="br0">(</span><span class="st0">"HTTP: Trying to "</span><span class="sy0">.</span><span class="re0">$this</span><span class="sy0">-></span><span class="me1">proxy_host</span><span class="sy0">.</span><span class="st0">":"</span><span class="sy0">.</span><span class="re0">$this</span><span class="sy0">-></span><span class="me1">proxy_port</span><span class="sy0">.</span><span class="st0">" ...<span class="es1">\n</span>"</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="re0">$sock</span> <span class="sy0">=</span> <span class="sy0">@</span><a href="http://www.php.net/fsockopen"><span class="kw3">fsockopen</span></a><span class="br0">(</span><span class="re0">$this</span><span class="sy0">-></span><span class="me1">proxy_host</span><span class="sy0">,</span> <span class="re0">$this</span><span class="sy0">-></span><span class="me1">proxy_port</span><span class="sy0">,</span> <span class="re0">$errno</span><span class="sy0">,</span> <span class="re0">$errstr</span><span class="sy0">,</span> <span class="re0">$timeout</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="kw1">if</span> <span class="br0">(</span><span class="re0">$sock</span> <span class="sy0">===</span> <span class="kw4">false</span><span class="br0">)</span> <span class="br0">{</span><br /> <span class="re0">$this</span><span class="sy0">-></span>_debug_print<span class="br0">(</span><span class="st0">"HTTP: fsockopen() "</span><span class="sy0">.</span><span class="re0">$errstr</span><span class="sy0">.</span><span class="st0">" ("</span><span class="sy0">.</span><span class="re0">$errno</span><span class="sy0">.</span><span class="st0">")<span class="es1">\n</span>"</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="kw1">continue</span><span class="sy0">;</span><br /> <span class="br0">}</span><br /> <span class="re0">$this</span><span class="sy0">-></span>_debug_print<span class="br0">(</span><span class="st0">"HTTP: Connected<span class="es1">\n</span>"</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="re0">$conn_str</span> <span class="sy0">=</span> <span class="st0">"CONNECT "</span><span class="sy0">.</span><span class="re0">$host</span><span class="sy0">.</span><span class="st0">":"</span><span class="sy0">.</span><span class="re0">$port</span><span class="sy0">.</span><span class="st0">" HTTP/1.1<span class="es1">\r</span><span class="es1">\n</span>Host: "</span><span class="sy0">.</span><span class="re0">$host</span><span class="sy0">.</span><span class="st0">":"</span><span class="sy0">.</span><span class="re0">$port</span><span class="sy0">.</span><span class="st0">"<span class="es1">\r</span><span class="es1">\n</span>Proxy-Authorization: "</span><span class="sy0">.</span><span class="re0">$proxy_header</span><span class="sy0">.</span><span class="st0">"<span class="es1">\r</span><span class="es1">\n</span>User-Agent: ftp.cls.php<span class="es1">\r</span><span class="es1">\n</span><span class="es1">\r</span><span class="es1">\n</span>"</span><span class="sy0">;</span><br /> <span class="re0">$this</span><span class="sy0">-></span>_debug_print<span class="br0">(</span><span class="st0">"HTTP: send => '<span class="es4">$conn_str</span>'<span class="es1">\n</span>"</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="kw1">if</span> <span class="br0">(</span><a href="http://www.php.net/fwrite"><span class="kw3">fwrite</span></a><span class="br0">(</span><span class="re0">$sock</span><span class="sy0">,</span> <span class="re0">$conn_str</span><span class="br0">)</span> <span class="sy0">===</span> <span class="kw4">false</span><span class="br0">)</span> <span class="br0">{</span><br /> <a href="http://www.php.net/fclose"><span class="kw3">fclose</span></a><span class="br0">(</span><span class="re0">$sock</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="re0">$this</span><span class="sy0">-></span>_debug_print<span class="br0">(</span><span class="st0">"HTTP: fwrite() error<span class="es1">\n</span>"</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="kw1">continue</span><span class="sy0">;</span><br /> <span class="br0">}</span><br /> <span class="re0">$buffer</span> <span class="sy0">=</span> <a href="http://www.php.net/fgets"><span class="kw3">fgets</span></a><span class="br0">(</span><span class="re0">$sock</span><span class="sy0">,</span> 1024<span class="br0">)</span><span class="sy0">;</span><br /> <span class="re0">$response</span> <span class="sy0">=</span> <a href="http://www.php.net/rtrim"><span class="kw3">rtrim</span></a><span class="br0">(</span><span class="re0">$buffer</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="re0">$this</span><span class="sy0">-></span>_debug_print<span class="br0">(</span><span class="st0">"HTTP: data => '"</span><span class="sy0">.</span><a href="http://www.php.net/rtrim"><span class="kw3">rtrim</span></a><span class="br0">(</span><span class="re0">$buffer</span><span class="br0">)</span><span class="sy0">.</span><span class="st0">"'<span class="es1">\n</span>"</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="co1">// read following header/body</span><br /> <span class="re0">$content_length</span> <span class="sy0">=</span> <span class="nu0">0</span><span class="sy0">;</span><br /> <span class="kw1">while</span> <span class="br0">(</span><span class="sy0">!</span><a href="http://www.php.net/feof"><span class="kw3">feof</span></a><span class="br0">(</span><span class="re0">$sock</span><span class="br0">)</span><span class="br0">)</span> <span class="br0">{</span><br /> <span class="re0">$buffer</span> <span class="sy0">=</span> <a href="http://www.php.net/fgets"><span class="kw3">fgets</span></a><span class="br0">(</span><span class="re0">$sock</span><span class="sy0">,</span> 1024<span class="br0">)</span><span class="sy0">;</span><br /> <span class="re0">$this</span><span class="sy0">-></span>_debug_print<span class="br0">(</span><span class="st0">"HTTP: header => '"</span><span class="sy0">.</span><a href="http://www.php.net/rtrim"><span class="kw3">rtrim</span></a><span class="br0">(</span><span class="re0">$buffer</span><span class="br0">)</span><span class="sy0">.</span><span class="st0">"'<span class="es1">\n</span>"</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="co1">// end of header</span><br /> <span class="kw1">if</span> <span class="br0">(</span><span class="re0">$buffer</span> <span class="sy0">===</span> <span class="st0">"<span class="es1">\r</span><span class="es1">\n</span>"</span><span class="br0">)</span><br /> <span class="kw1">break</span><span class="sy0">;</span><br /> <span class="kw1">if</span> <span class="br0">(</span><a href="http://www.php.net/strncasecmp"><span class="kw3">strncasecmp</span></a><span class="br0">(</span><span class="re0">$buffer</span><span class="sy0">,</span> <span class="st_h">'Content-Length:'</span><span class="sy0">,</span> <span class="nu0">15</span><span class="br0">)</span> <span class="sy0">==</span> <span class="nu0">0</span><span class="br0">)</span> <span class="br0">{</span><br /> <span class="co1">// Content-Length: 3123</span><br /> <span class="re0">$content_length</span> <span class="sy0">=</span> <a href="http://www.php.net/trim"><span class="kw3">trim</span></a><span class="br0">(</span><a href="http://www.php.net/substr"><span class="kw3">substr</span></a><span class="br0">(</span><span class="re0">$buffer</span><span class="sy0">,</span> 15<span class="br0">)</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="br0">}</span><br /> <span class="br0">}</span><br /> <span class="kw1">if</span> <span class="br0">(</span><span class="re0">$content_length</span> <span class="sy0">!=</span> 0<span class="br0">)</span> <span class="br0">{</span><br /> <span class="re0">$xbody</span> <span class="sy0">=</span> <span class="st_h">''</span><span class="sy0">;</span><br /> <span class="kw1">while</span> <span class="br0">(</span><span class="re0">$content_length</span> <span class="sy0">></span> 0<span class="br0">)</span> <span class="br0">{</span><br /> <span class="re0">$data</span> <span class="sy0">=</span> <a href="http://www.php.net/fread"><span class="kw3">fread</span></a><span class="br0">(</spa</span></pre></div></pre>
程式設計
PHP
2013-01-29T10:47:42Z
tommy
-
限制 phpBB3 的驗證碼只輸入前四碼
https://blog.teatime.com.tw/1/post/411
<p>基本上, 這個修改與<a href="http://blog.teatime.com.tw/1/post/378" target="_blank">之前改給 SMF 用的</a>是同一個, 只是針對 <a href="http://www.phpbb.com/" target="_blank">phpBB3</a> 來改.</p><pre class="diff"><div class="insertcode"><pre class="diff" style="font-family: monospace">diff -Nur phpBB3.orig//includes/captcha/plugins/captcha_abstract.php phpBB3/includes/captcha/plugins/captcha_abstract.php<br /><span class="re3">--- phpBB3.orig//includes/captcha/plugins/captcha_abstract.php <span class="nu0">2012</span>-01-01 <span class="nu0">23</span>:00:<span class="nu0">17.000000000</span> +0800</span><br /><span class="re4">+++ phpBB3/includes/captcha/plugins/captcha_abstract.php <span class="nu0">2012</span>-01-<span class="nu0">18</span> <span class="nu0">12</span>:<span class="nu0">17</span>:<span class="nu0">38.838436361</span> +0800</span><br /><span class="re6">@@ -<span class="nu0">326</span>,<span class="nu0">7</span> +<span class="nu0">326</span>,<span class="nu0">10</span> @@</span><br /> <br /> function check_code<span class="br0">(</span><span class="br0">)</span><br /> <span class="br0">{</span><br /><span class="re7">- return <span class="br0">(</span>strcasecmp<span class="br0">(</span>$this->code, $this->confirm_code<span class="br0">)</span> === 0<span class="br0">)</span>;</span><br /><span class="re8">+ //return <span class="br0">(</span>strcasecmp<span class="br0">(</span>$this->code, $this->confirm_code<span class="br0">)</span> === 0<span class="br0">)</span>;</span><br /><span class="re8">+ // we only need first <span class="nu0">4</span> letters, if we got more, reject it</span><br /><span class="re8">+ if <span class="br0">(</span>strlen<span class="br0">(</span>$this->confirm_code<span class="br0">)</span> != 4<span class="br0">)</span> return false;</span><br /><span class="re8">+ return <span class="br0">(</span>strcasecmp<span class="br0">(</span>substr<span class="br0">(</span>$this->code, 0, 4<span class="br0">)</span>, $this->confirm_code<span class="br0">)</span> === 0<span class="br0">)</span>;</span><br /> <span class="br0">}</span><br /> <br /> function delete_code<span class="br0">(</span><span class="br0">)</span><br />diff -Nur phpBB3.orig//includes/constants.php phpBB3/includes/constants.php<br /><span class="re3">--- phpBB3.orig//includes/constants.php <span class="nu0">2012</span>-01-01 <span class="nu0">23</span>:00:<span class="nu0">17.000000000</span> +0800</span><br /><span class="re4">+++ phpBB3/includes/constants.php <span class="nu0">2012</span>-01-<span class="nu0">18</span> <span class="nu0">12</span>:<span class="nu0">20</span>:<span class="nu0">43.563129711</span> +0800</span><br /><span class="re6">@@ -<span class="nu0">205</span>,<span class="nu0">7</span> +<span class="nu0">205</span>,<span class="nu0">7</span> @@</span><br /> @define<span class="br0">(</span>'CHMOD_EXECUTE', 1<span class="br0">)</span>;<br /> <br /> // Captcha code length<br /><span class="re7">-define<span class="br0">(</span>'CAPTCHA_MIN_CHARS', 4<span class="br0">)</span>;</span><br /><span class="re8">+define<span class="br0">(</span>'CAPTCHA_MIN_CHARS', 6<span class="br0">)</span>;</span><br /> define<span class="br0">(</span>'CAPTCHA_MAX_CHARS', 7<span class="br0">)</span>;<br /> <br /> // Additional constants<br />diff -Nur phpBB3.orig//language/en/common.php phpBB3/language/en/common.php<br /><span class="re3">--- phpBB3.orig//language/en/common.php <span class="nu0">2012</span>-01-<span class="nu0">18</span> <span class="nu0">12</span>:<span class="nu0">10</span>:<span class="nu0">36.848677118</span> +0800</span><br /><span class="re4">+++ phpBB3/language/en/common.php <span class="nu0">2012</span>-01-01 <span class="nu0">23</span>:00:<span class="nu0">17.000000000</span> +0800</span><br /><span class="re6">@@ -<span class="nu0">123</span>,<span class="nu0">8</span> +<span class="nu0">123</span>,<span class="nu0">8</span> @@</span><br /> 'COLOUR_SWATCH' => 'Colour swatch',<br /> 'COMMA_SEPARATOR' => ', ', // Used in pagination of ACP & prosilver, use localised comma if appropriate, eg: Ideographic or Arabic<br /> 'CONFIRM' => 'Confirm',<br /><span class="re7">- 'CONFIRM_CODE' => 'Confirmation code <span class="br0">(</span>first <span class="nu0">4</span> letters<span class="br0">)</span>',</span><br /><span class="re7">- 'CONFIRM_CODE_EXPLAIN' => 'Enter the code exactly as it appears <span class="br0">(</span>first <span class="nu0">4</span> letters<span class="br0">)</span>. All letters are case insensitive.',</span><br /><span class="re8">+ 'CONFIRM_CODE' => 'Confirmation code',</span><br /><span class="re8">+ 'CONFIRM_CODE_EXPLAIN' => 'Enter the code exactly as it appears. All letters are case insensitive.',</span><br /> 'CONFIRM_CODE_WRONG' => 'The confirmation code you entered was incorrect.',<br /> 'CONFIRM_OPERATION' => 'Are you sure you wish to carry out this operation?',<br /> 'CONGRATULATIONS' => 'Congratulations to',<br />diff -Nur phpBB3.orig//language/zh_cmn_hant/common.php phpBB3/language/zh_cmn_hant/common.php<br /><span class="re3">--- phpBB3.orig//language/zh_cmn_hant/common.php <span class="nu0">2012</span>-01-<span class="nu0">18</span> <span class="nu0">12</span>:<span class="nu0">10</span>:<span class="nu0">01.745087469</span> +0800</span><br /><span class="re4">+++ phpBB3/language/zh_cmn_hant/common.php <span class="nu0">2012</span>-01-<span class="nu0">18</span> <span class="nu0">12</span>:08:<span class="nu0">56.437944350</span> +0800</span><br /><span class="re6">@@ -<span class="nu0">123</span>,<span class="nu0">8</span> +<span class="nu0">123</span>,<span class="nu0">8</span> @@</span><br /> 'COLOUR_SWATCH' => '顏色取樣',<br /> 'COMMA_SEPARATOR' => ',',<br /> 'CONFIRM' => '確認',<br /><span class="re7">- 'CONFIRM_CODE' => '確認代碼',</span><br /><span class="re7">- 'CONFIRM_CODE_EXPLAIN' => '請正確輸入它所顯示的代碼,不必區分大小寫。',</span><br /><span class="re8">+ 'CONFIRM_CODE' => '確認代碼<span class="br0">(</span>前四碼<span class="br0">)</span>',</span><br /><span class="re8">+ 'CONFIRM_CODE_EXPLAIN' => '請正確輸入它所顯示的代碼<span class="br0">(</span>前四碼<span class="br0">)</span>,不必區分大小寫。',</span><br /> 'CONFIRM_CODE_WRONG' => '您輸入的確認代碼有誤。',<br /> 'CONFIRM_OPERATION' => '您確認要執行這個操作嗎?',<br /> 'CONGRATULATIONS' => '恭喜您',</pre></div></pre><p>修改後, 建議把產生的圖檔改成 "簡單" 的那一個, 因為反正 bot 都看的懂, 沒必要弄那麼複雜, 反而讓人很難看懂. </p>
Patch
phpBB
PHP
2012-01-18T12:35:18Z
tommy
-
修正 phpmsnclass 在 big-endian 機器上無法正常登入的問題
https://blog.teatime.com.tw/1/post/410
<p>看來以前沒有人用 <a href="http://code.google.com/p/phpmsnclass" target="_blank">phpmsnclass</a> 這東西在 big-endian 的機器上頭.... 直到昨天有人問我他在登入時一直出現 <a href="http://msnpiki.msnfanatic.com/index.php/Reference:Error_List#911" target="_blank">911</a> 的錯誤, 加了一些除錯訊息之後, 終於發現 <a href="http://php.net/manual/en/function.pack.php" target="_blank">pack()</a> 的結果與在 x86/x64 上的結果不一樣. 造成 login 所需要的 BLOB 資料運算錯誤.</p><p>因為我只有 x86 的機器, 所以... 自然都用 little-endian 的方式來處理, 所以 pack() 傳入的參數是 'L' (依據 machine 來決定 unsigned long 的儲存方式)... 不過, 在 big-endian 結果就不同了.</p><p>所以我們應該在這地方使用 'V' (用 little-endian 的方式處理 unsigned long) 才處理, 這樣不管在 little-endian 或 big-endian 的機器都可以正常使用.</p><p>有需要的, 請自行到 Google code 去抓 r61 或之後的版本. </p>
程式設計
PHP
2012-01-17T10:18:27Z
tommy
-
ZendGuardLoader autoload segmentation fault for method_exits()
https://blog.teatime.com.tw/1/post/404
<p>這是早上那個 <a href="http://gallery.menalto.com/" target="_blank">Gallery</a> 3 與 <a href="http://www.zend.com/en/products/guard/" target="_blank">ZendGuardLoader</a> 一起使用時的問題, 寫了一個小的 test case, 可以重製這個錯誤.</p><p>Class File => a.php</p><pre class="php"><div class="insertcode"><pre class="php" style="font-family: monospace"><span class="kw2"><?php</span><br /><span class="kw2">class</span> a <span class="br0">{</span><br /> static <span class="kw2">public</span> <span class="kw2">function</span> my_fun<span class="br0">(</span><span class="br0">)</span><br /> <span class="br0">{</span><br /> <span class="kw1">return</span> <span class="kw4">true</span><span class="sy0">;</span><br /> <span class="br0">}</span><br /><span class="br0">}</span><br /><span class="sy1">?></span></pre></div></pre><p>Test File => t.php</p><pre class="php"><div class="insertcode"><pre class="php" style="font-family: monospace"><span class="kw2"><?php</span><br /> <br /><span class="kw2">class</span> T <span class="br0">{</span><br /> static <span class="kw2">public</span> <span class="kw2">function</span> auto_load<span class="br0">(</span><span class="re0">$class</span><span class="br0">)</span> <span class="br0">{</span><br /> <span class="kw1">echo</span> <span class="st0">"looking for <span class="es4">$class</span><span class="es1">\n</span>"</span><span class="sy0">;</span><br /> <span class="re0">$n</span> <span class="sy0">=</span> <span class="st_h">''</span><span class="sy0">.</span><span class="re0">$class</span><span class="sy0">.</span><span class="st_h">'.php'</span><span class="sy0">;</span><br /> <span class="kw1">if</span> <span class="br0">(</span><a href="http://www.php.net/file_exists"><span class="kw3">file_exists</span></a><span class="br0">(</span><span class="re0">$n</span><span class="br0">)</span><span class="br0">)</span> <span class="br0">{</span><br /> <span class="kw1">echo</span> <span class="st0">"loading from file: <span class="es4">$n</span><span class="es1">\n</span>"</span><span class="sy0">;</span><br /> <span class="kw1">require_once</span><span class="br0">(</span><span class="re0">$n</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="kw1">return</span> <span class="kw4">true</span><span class="sy0">;</span><br /> <span class="br0">}</span><br /> <span class="kw1">return</span> <span class="kw4">false</span><span class="sy0">;</span><br /> <span class="br0">}</span><br /><span class="br0">}</span><br /> <br /><a href="http://www.php.net/spl_autoload_register"><span class="kw3">spl_autoload_register</span></a><span class="br0">(</span><a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">(</span><span class="st_h">'T'</span><span class="sy0">,</span> <span class="st_h">'auto_load'</span><span class="br0">)</span><span class="br0">)</span><span class="sy0">;</span><br /> <br /><span class="co1">// this one work</span><br /> <span class="re0">$class</span> <span class="sy0">=</span> <span class="st_h">'a'</span><span class="sy0">;</span><br /> <span class="kw1">if</span> <span class="br0">(</span><a href="http://www.php.net/method_exists"><span class="kw3">method_exists</span></a><span class="br0">(</span><span class="re0">$class</span><span class="sy0">,</span> <span class="st_h">'my_fun'</span><span class="br0">)</span><span class="br0">)</span><br /> <span class="kw1">echo</span> <span class="st0">"<span class="es4">$class</span>.my_fun() exists<span class="es1">\n</span>"</span><span class="sy0">;</span><br /> <span class="kw1">else</span><br /> <span class="kw1">echo</span> <span class="st0">"<span class="es4">$class</span>.my_fun() not exists<span class="es1">\n</span>"</span><span class="sy0">;</span><br /> <br /><span class="co1">// this got segmentation fault</span><br /> <span class="re0">$class</span> <span class="sy0">=</span> <span class="st_h">'MY_CLASS_1000'</span><span class="sy0">;</span><br /> <span class="kw1">if</span> <span class="br0">(</span><a href="http://www.php.net/method_exists"><span class="kw3">method_exists</span></a><span class="br0">(</span><span class="re0">$class</span><span class="sy0">,</span> <span class="st_h">'my_fun'</span><span class="br0">)</span><span class="br0">)</span><br /> <span class="kw1">echo</span> <span class="st0">"<span class="es4">$class</span>.my_fun() exists<span class="es1">\n</span>"</span><span class="sy0">;</span><br /> <span class="kw1">else</span><br /> <span class="kw1">echo</span> <span class="st0">"<span class="es4">$class</span>.my_fun() not exists<span class="es1">\n</span>"</span><span class="sy0">;</span><br /><a href="http://www.php.net/spl_autoload_unregister"><span class="kw3">spl_autoload_unregister</span></a><span class="br0">(</span><a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">(</span><span class="st_h">'T'</span><span class="sy0">,</span> <span class="st_h">'auto_load'</span><span class="br0">)</span><span class="br0">)</span><span class="sy0">;</span><br /> <br /><span class="sy1">?></span></pre></div></pre><p>正常沒有載入 ZendGuardLoader 時的結果:</p><pre class="bash"><div class="insertcode"><pre class="bash" style="font-family: monospace">mail:<span class="sy0">/</span>tmp<span class="co0"># php -v</span><br />PHP 5.3.8-<span class="nu0">1</span> with Suhosin-Patch <span class="br0">(</span>cli<span class="br0">)</span> <span class="br0">(</span>built: Nov <span class="nu0">23</span> <span class="nu0">2011</span> <span class="nu0">18</span>:<span class="nu0">25</span>:<span class="nu0">58</span><span class="br0">)</span><br />Copyright <span class="br0">(</span>c<span class="br0">)</span> <span class="nu0">1997</span>-<span class="nu0">2011</span> The PHP Group<br />Zend Engine v2.3.0, Copyright <span class="br0">(</span>c<span class="br0">)</span> <span class="nu0">1998</span>-<span class="nu0">2011</span> Zend Technologies<br /> with Suhosin v0.9.32.1, Copyright <span class="br0">(</span>c<span class="br0">)</span> <span class="nu0">2007</span>-<span class="nu0">2010</span>, by SektionEins GmbH<br />mail:<span class="sy0">/</span>tmp<span class="co0"># php -Cq t.php</span><br />looking <span class="kw1">for</span> a<br />loading from <span class="kw2">file</span>: a.php<br />a.my_fun<span class="br0">(</span><span class="br0">)</span> exists<br />looking <span class="kw1">for</span> MY_CLASS_1000<br />MY_CLASS_1000.my_fun<span class="br0">(</span><span class="br0">)</span> not exists<br />mail:<span class="sy0">/</span>tmp<span class="co0">#</span></pre></div></pre><p>載入 ZendGuardLoader 時的結果:</p><pre class="bash"><div class="insertcode"><pre class="bash" style="font-family: monospace">mail:<span class="sy0">/</span>tmp<span class="co0"># php -v</span><br />PHP 5.3.8-<span class="nu0">1</span> with Suhosin-Patch <span class="br0">(</span>cli<span class="br0">)</span> <span class="br0">(</span>built: Nov <span class="nu0">23</span> <span class="nu0">2011</span> <span class="nu0">18</span>:<span class="nu0">25</span>:<span class="nu0">58</span><span class="br0">)</span><br />Copyright <span class="br0">(</span>c<span class="br0">)</span> <span class="nu0">1997</span>-<span class="nu0">2011</span> The PHP Group<br />Zend Engine v2.3.0, Copyright <span class="br0">(</span>c<span class="br0">)</span> <span class="nu0">1998</span>-<span class="nu0">2011</span> Zend Technologies<br /> with Zend Guard Loader v3.3, Copyright <span class="br0">(</span>c<span class="br0">)</span> <span class="nu0">1998</span>-<span class="nu0">2010</span>, by Zend Technologies<br /> with Suhosin v0.9.32.1, Copyright <span class="br0">(</span>c<span class="br0">)</span> <span class="nu0">2007</span>-<span class="nu0">2010</span>, by SektionEins GmbH<br />mail:<span class="sy0">/</span>tmp<span class="co0"># php -Cq t.php</span><br />looking <span class="kw1">for</span> a<br />loading from <span class="kw2">file</span>: a.php<br />a.my_fun<span class="br0">(</span><span class="br0">)</span> exists<br />looking <span class="kw1">for</span> MY_CLASS_1000<br />looking <span class="kw1">for</span> MY_CLASS_1000<br />looking <span class="kw1">for</span> 80fbdj487sxn5<br />Segmentation fault<br />mail:<span class="sy0">/</span>tmp<span class="co0">#</span></pre></div></pre><p>在載入 ZendGuardLoader 之後, 會對一個不存在的 class 執行 autoload 函式兩次 (應該算三次吧), 然後會跟著一個亂數名的 class 再執行 autoload 函式一次.... 接著就 segmentation fault 了. </p><p>有了這個簡單的 case, 就丟給 Zend 去分析了 (奇怪, 怎麼我開一個新的 support case 都會不成功?... 最後只好丟他們的討論區去), 希望有好消息.</p>
PHP
2011-12-20T21:23:53Z
tommy
-
ZendGuardLoader + Gallery3 = segmentation fault?
https://blog.teatime.com.tw/1/post/403
<p>如果你在有使用 <a href="http://www.zend.com/en/products/guard/" target="_blank">Zend Guard</a> Loader 的網站中架設 <a href="http://gallery.menalto.com/" target="_blank">Gallery</a> 3 的話, 在跑完 install 的畫面之後, 你就會發現你的 Gallery 3 永遠都出現一個空白畫面. 這問題... 有人<a href="http://sourceforge.net/apps/trac/gallery/ticket/1749" target="_blank">在 Gallery 那邊問</a>, 想當然的.... 得到一個不是我們的問題的答案 (如果我是作者, 我也會這樣回答的), 也有人在 <a href="http://forums.zend.com/viewtopic.php?t=11953&f=57" target="_blank">Zend 那邊問</a>, 結果與我以前問 Zend 問題的經驗一樣.... 完全沒有任何作用.</p><p>解決方法, 其實很簡單, 那就是不要用 ZendGuardLoader.so 就好了 (別罵了, 我也知道這是什麼屁方法....). </p><p>原則上, 這是 ZendGaurdLoader 的問題, 由於這東西是人家賣的某產品的要用到的 loader, 並不是什麼 open source 的東西, 自然... 沒人會知道這東西是怎麼做的, 也沒有辦法自行去修改, 所以.... 有問題的請儘量去找 <a href="http://www.zend.com/en/" target="_blank">Zend</a> 這家公司吧. 不過... 雖然這家公司算是 <a href="http://www.php.net/" target="_blank">PHP</a> 這東西的核心公司 (要說是 PHP 的爸爸也可以), 不過... 我懷疑目前他們到底有多少懂 PHP 底層的開發人員在負責 Zend Guard 這東西, 光一個支援 PHP 5.3 的版本, 可以在一年多後還看不到影子 (別的類似產品的公司, 早就提供這個支援了), 好不容易終於生出了 ZendGuard 5.5 及相關的 loader 可以支援 PHP 5.3, 不過.... 看起來發生 segmentation fault 的情形並不算少數. 所以.... 這問題人家反應至少有半年了, 沒什麼下聞看起來也還算正常吧 (反正沒期待就不會受傷害). </p><p>如果你一定要用到 ZendGaurdLoader.so, 那... 由於這玩意並不能動態的載入, 只能在一開始執行 PHP 時就決定要不要載入這類的模組, 所以.... 如果你是用 Apache 加上 php 使用 module 的方式執行的話, 那.... 無解, 請再弄一台機器, 把需要用到 ZendGuardLoader 的程式與在 ZendGaurdLoader 中會有問題的程式分開來跑吧.</p><p>如果不行.... 那看能不能改成 CGI 或 FPM 的方式來跑 PHP, 把這些 CGI/FPM 的 daemon 指定不同的 port 或 socket file, 然後指定使用不同的 php.ini (在這兒決定要不要載入 ZendGuardLoader.so), 最後... 把需要 ZendGaurdLoader 的往有支援的那一個送, 這樣至少同一台機器中, 可以各取所需.</p><p>如果還是不行.... 那, 就修改你的程式吧, 看能不能避掉這問題.... 以我碰到的例子 (就是 Galley 3 這程式), 通常... 這問題發生在 <a href="http://www.php.net/manual/en/function.spl-autoload-register.php" target="_blank">autoload</a> 的處理上頭, 當搭配 autoload 使用時, 如果要去判斷一個 class 或其中某個 method 是否存在時 (就是使用 <a href="http://www.php.net/manual/en/function.class-exists.php" target="_blank">class_exists()</a> 或 <a href="http://www.php.net/manual/en/function.method-exists.php" target="_blank">method_exists()</a> 去判斷), 這類的程式會做一個 autoload 的動作, 嘗試去載入相關的定義檔.... 但是如果真的沒有那個檔案存在, 在沒有 ZendGaurdLoader 時, 會去執行一次 spl_autoload_register() 的 function, 然後就回覆 false. 但是... 如果有 ZendGuardLoader 時, 會對同一個 class 或 method 去執行那個 autoload 的 function, 且第三次傳入的 class 名稱是一個亂數, 然後.... 程式就會出現 segmentation fault 就掛了.</p><p>要避免這問題, 一個就是大幅改寫程式, 儘量不要用 autoload 的方式處理. (我知道很難... 比重寫還麻煩)</p><p>另一個是偷吃步.... 在 autoload 處理時, 如果那個 class 的定義檔案是不存在的, 就產生一個 dummy 的 class 給系統 (反正不存在表示之後也不會用到), 讓系統以為有這個 class (只是沒有任何 property 與 method), 這樣就可以避開這個 bug.</p><p>以 Gallery 3 來說:</p><pre class="diff"><div class="insertcode"><pre class="diff" style="font-family: monospace">--- gallery3.orig/system/core/Kohana.php 2011-05-25 12:04:04.000000000 +0800<br /><span class="re4">+++ gallery3/system/core/Kohana.php <span class="nu0">2011</span>-<span class="nu0">12</span>-<span class="nu0">20</span> <span class="nu0">21</span>:<span class="nu0">59</span>:<span class="nu0">20.901236982</span> +0800</span><br /><span class="re6">@@ -<span class="nu0">698</span>,<span class="nu0">6</span> +<span class="nu0">698</span>,<span class="nu0">26</span> @@</span><br /> else<br /> <span class="br0">{</span><br /> // The class could not be found<br /><span class="re8">+ // twu2 begin</span><br /><span class="re8">+ // avoid segmentation fault in Zend Guard</span><br /><span class="re8">+ // because when ZendGuardLoader enable, it will try to load the same class again if it's not exist, then... it will try a random name, then segmentation fault</span><br /><span class="re8">+ // so we keep the name first, then if it try again</span><br /><span class="re8">+ // create a dummy class for it</span><br /><span class="re8">+ //</span><br /><span class="re8">+ // only check this if ZendGuardLoader exist</span><br /><span class="re8">+ if <span class="br0">(</span>extension_loaded<span class="br0">(</span>'Zend Guard Loader'<span class="br0">)</span><span class="br0">)</span> <span class="br0">{</span></span><br /><span class="re8">+ static $last_name = '';</span><br /><span class="re8">+</span><br /><span class="re8">+ // reject it first</span><br /><span class="re8">+ if <span class="br0">(</span>$last_name !== $class<span class="br0">)</span> <span class="br0">{</span></span><br /><span class="re8">+ $last_name = $class;</span><br /><span class="re8">+ return FALSE;</span><br /><span class="re8">+ <span class="br0">}</span></span><br /><span class="re8">+ // create dummy one if try again</span><br /><span class="re8">+ Kohana_Log::add<span class="br0">(</span>'debug', 'create dummy class: '.$class<span class="br0">)</span>;</span><br /><span class="re8">+ eval<span class="br0">(</span>"class $class <span class="br0">{</span> <span class="br0">}</span>"<span class="br0">)</span>;</span><br /><span class="re8">+ <span class="br0">}</span></span><br /><span class="re8">+ // twu2 end</span><br /> return FALSE;<br /> <span class="br0">}</span></pre></div></pre><p>這個改法, 可以在不存在該 class 定義時, 建一個空的 class 來用. 這樣子的處理, 就可以讓 Gallery 3 避開 ZendGuardLoader 的 bug 了. 不過... 最好的方法, 還是不要一起用吧.</p><p>PS. 上頭的改法, 原本直接產生的方式, 會造成 g2_import 不正常, 因為 g2_import 會載入的 class 並不放在 G3 這系統下, 所以... 解決方法是不去處理 G2 的 class (只能碰到一個就加一個), 或... 改成目前的方式, 反正出問題時, 會連續對同一個 class 做兩次這動作 (正常情形下, 不過有沒有都應該只做一次), 最後一個奇怪名字的 class 後才 segmentation fault. 所以... 就把名字記下來, 重複的第二次才去產生那個 dummy class, 這樣子看起來就正常了. (也許之後還會有問題.... 所以最好是分開來, 不要一起用吧, 把 ZendGuardLoader 用在只需要它的地方就好了)</p>
Gallery
PHP
2011-12-20T12:36:36Z
tommy
-
Nginx 對於 PHP 的錯誤轉向處理, fastcgi_intercept_errors 修正
https://blog.teatime.com.tw/1/post/402
<p>在一般靜態網頁的處理上頭, <a href="http://nginx.org/" target="_blank">nginx</a> 可以正常的顯示一些錯誤的訊息 (如 404 File not found 之類的訊息). 不過對於 <a href="http://www.php.net/" target="_blank">PHP</a> (其他用 fastcgi 方式跑的程式也一樣), 預設來說, 如果有什麼錯誤, 往往就看到空白的一個網頁. 而一般的 nginx 教學上頭, 對於這個問題的處理建議就是 <a href="http://wiki.nginx.org/HttpFcgiModule#fastcgi_intercept_errors" target="_blank">fastcgi_intercept_errors</a> on 的設定. 但... 這個方式並不是完美的.</p><p>首先在 fastcgi_intercept_errors off (預設值) 的情形下:</p><ul><li>如果 $uri 指到的那個 php 檔案不存在, nginx 會把這個檔案名轉給 php-fpm (或 cgi 程式) 去處理, 這時 PHP 會找不到該檔案, 會出現 No input file specified. 這個錯誤訊息. (http 的狀態碼是 404)</li><li>如果該 php 檔案存在, 但裡頭程式有問題 (打錯字之類), 如果 PHP 的 <a href="http://www.php.net/manual/en/errorfunc.configuration.php#ini.display-errors" target="_blank">display_errors</a> 是 true, 會顯示 PHP 的錯誤訊息 (http 的狀態碼是 200, 對 nginx 來說, 就是不認為有發生錯誤). 如果 dispaly_errors 是 false 時, 則會出現完全空白的畫面 (http 的狀態碼是 500).</li><li>如果 php 的檔案沒有錯誤, 程式本身是正常的, 但對於程式的處理上頭, 要把這情形回應給使用者, 告知是不正常的狀態, 例如很多的程式, 在某些情形下會在找不到資料時, 顯示自訂的 404 網頁, 但是 http 的狀態碼是 404 (就是先執行 <a href="http://www.php.net/manual/es/function.header.php" target="_blank">header</a> ('HTTP/1.1 404 File Not Found'); 然後再顯示網頁的內容. 這時, 使用者會看到該程式所顯示的畫面, 但是 http 的狀態碼是 404. (不光是 404 的處理, 其它的也一樣)</li></ul><p>對正常的網頁管理來看, 第一種情形, 我們希望能看到的是系統給的 404 錯誤的網頁, 而不是 php 的訊息. 而第二種情形, 我們希望在 display_errors 關閉的情形下, 能顯示系統的 500 錯誤的網頁, 而不光只是一個空白畫面. 第三種情形就是我們正常所希望的處理方式了.</p><p>而一般在 ngnix 上, 為了解決前面兩個情形所碰到的問題, 建議是把 fastcgi_intercept_errors 設成 on (必須在有設定 <a href="http://wiki.nginx.org/HttpCoreModule#error_page" target="_blank">error_page</a> 的時候才有作用), 這時:</p><ul><li>一樣會把不存在的 php 檔名轉給 php-fpm 處理, 而 php-fpm 一樣會回 No input file specified. 這個錯誤訊息 (http 的狀態碼是 404), 但是 nginx 在取得 404 的狀態之後, 並不是顯示 No input file specified. 而是轉給 error_page 所指定的 404 處理網頁.</li><li>在 display_errors 打開的情形下, 不認為有錯誤, 而直接顯示 php 的錯誤訊息. 但是在 display_errors 關閉的情形下, 同樣得到沒有任何訊息的 http 狀態碼 500, 這時, nginx 會把這個錯誤再轉給 error_page 所指定的 500 處理網頁去處理.</li><li>nginx 雖然收到要顯示的網頁內容, 但是因為 http 狀態碼是 404, 所以並不直接顯示該內容, 而是轉到 error_page 的 404 處理網頁去顯示. (我的理解應該是這樣, 可是實際上, 是看到 browser 的 file not found 網頁, 而不是 nginx 那邊提供的內容) </li></ul><p>所以.... 為了解決前兩種情形的問題, 改用 fastcgi_intercept_errors on 之後, 前兩者是正常的, 但是第三種情形就反而不正常了, 與我們想要的內容不一樣.</p><p>對於第一種情形, 我們可以在 fastcgi_intercept_errors off 的情形下, 改用 <a href="http://wiki.nginx.org/HttpCoreModule#try_files" target="_blank">try_files</a> 或 <a href="http://wiki.nginx.org/HttpRewriteModule#if" target="_blank">if</a> 來檢查該 php 檔案是否存在, 這時, 就可以直接回應 404 的錯誤, 而不會到 php-fpm 處理才發現沒有該檔案. 利用這樣的檢查, 在不管 fastcgi_intercept_errors 的設定的情形下, 都可以轉到正確的 404 錯誤網頁. </p><p>所以, 問題就剩下第二種與第三種情形了.</p><p>就目前的 nginx 功能來看, 看來只能兩種選擇一種來用, 一個正常, 另一個就會不正常. 無法讓 fastcgi_intercept_errors 只去處理 404 以外的錯誤. 我們希望的功能, 應該是 fastcgi_intercept_errors on 的修正, 也就是在 fastcgi_intercept_errors 應該只處理 404 之外的錯誤, 不要再針對 404 去處理.</p><p>因為找不到其它的解決方法 (有人有不改程式的方法嗎?), 所以, 只好動手自己加上<a href="http://trac.nginx.org/nginx/ticket/71" target="_blank">這功能的修正</a>:</p><pre class="diff"><div class="insertcode"><pre class="diff" style="font-family: monospace">diff -Nur nginx-1.1.11.orig/src/http/modules/ngx_http_fastcgi_module.c nginx-1.1.11/src/http/modules/ngx_http_fastcgi_module.c<br /><span>--- nginx-1.1.11.orig/src/http/modules/ngx_http_fastcgi_module.c <span>2011</span>-<span>12</span>-09 <span>21</span>:<span>32</span>:<span>51.000000000</span> +0800</span><br /><span>+++ nginx-1.1.11/src/http/modules/ngx_http_fastcgi_module.c <span>2011</span>-<span>12</span>-<span>19</span> <span>13</span>:<span>52</span>:<span>43.431468931</span> +0800</span><br /><span>@@ -<span>287</span>,<span>6</span> +<span>287</span>,<span>16</span> @@</span><br /> offsetof<span>(</span>ngx_http_fastcgi_loc_conf_t, upstream.pass_request_body<span>)</span>,<br /> NULL <span>}</span>,<br /> <br /><span>+ // twu2 begin</span><br /><span>+ // option to skip <span>404</span> error</span><br /><span>+ <span>{</span> ngx_string<span>(</span>"fastcgi_intercept_error_skip_404"<span>)</span>,</span><br /><span>+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,</span><br /><span>+ ngx_conf_set_flag_slot,</span><br /><span>+ NGX_HTTP_LOC_CONF_OFFSET,</span><br /><span>+ offsetof<span>(</span>ngx_http_fastcgi_loc_conf_t, upstream.intercept_error_skip_404<span>)</span>,</span><br /><span>+ NULL <span>}</span>,</span><br /><span>+ // twu2 edn</span><br /><span>+</span><br /> <span>{</span> ngx_string<span>(</span>"fastcgi_intercept_errors"<span>)</span>,<br /> NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,<br /> ngx_conf_set_flag_slot,<br /><span>@@ -<span>2092</span>,<span>6</span> +<span>2102</span>,<span>10</span> @@</span><br /> conf->upstream.pass_headers = NGX_CONF_UNSET_PTR;<br /> <br /> conf->upstream.intercept_errors = NGX_CONF_UNSET;<br /><span>+ // twu2 begin</span><br /><span>+ // option to skip <span>404</span> error</span><br /><span>+ conf->upstream.intercept_error_skip_404 = NGX_CONF_UNSET;</span><br /><span>+ // twu2 end</span><br /> <br /> /* "fastcgi_cyclic_temp_file" is disabled */<br /> conf->upstream.cyclic_temp_file = <span>0</span>;<br /><span>@@ -<span>2332</span>,<span>6</span> +<span>2346</span>,<span>11</span> @@</span><br /> <br /> ngx_conf_merge_value<span>(</span>conf->upstream.intercept_errors,<br /> prev->upstream.intercept_errors, 0<span>)</span>;<br /><span>+ // twu2 begin</span><br /><span>+ // option to skip <span>404</span> error</span><br /><span>+ ngx_conf_merge_value<span>(</span>conf->upstream.intercept_errors,</span><br /><span>+ prev->upstream.intercept_errors, 0<span>)</span>;</span><br /><span>+ // twu2 end</span><br /> <br /> ngx_conf_merge_ptr_value<span>(</span>conf->catch_stderr, prev->catch_stderr, NULL<span>)</span>;<br /> <br />diff -Nur nginx-1.1.11.orig/src/http/ngx_http_upstream.c nginx-1.1.11/src/http/ngx_http_upstream.c<br /><span>--- nginx-1.1.11.orig/src/http/ngx_http_upstream.c <span>2011</span>-<span>12</span>-09 <span>21</span>:<span>19</span>:<span>57.000000000</span> +0800</span><br /><span>+++ nginx-1.1.11/src/http/ngx_http_upstream.c <span>2011</span>-<span>12</span>-<span>19</span> <span>13</span>:<span>49</span>:<span>21.476532705</span> +0800</span><br /><span>@@ -<span>1742</span>,<span>6</span> +<span>1742</span>,<span>12</span> @@</span><br /> return NGX_DECLINED;<br /> <span>}</span><br /> <br /><span>+ // twu2 begin</span><br /><span>+ // don't intercept <span>404</span> error <span>(</span>it will be processed by upstream<span>)</span></span><br /><span>+ if <span>(</span>status == NGX_HTTP_NOT_FOUND && u->conf->intercept_error_skip_404<span>)</span></span><br /><span>+ return NGX_DECLINED;</span><br /><span>+ // twu2 end</span><br /><span>+</span><br /> clcf = ngx_http_get_module_loc_conf<span>(</span>r, ngx_http_core_module<span>)</span>;<br /> <br /> if <span>(</span>clcf->error_pages == NULL<span>)</span> <span>{</span><br />diff -Nur nginx-1.1.11.orig/src/http/ngx_http_upstream.h nginx-1.1.11/src/http/ngx_http_upstream.h<br /><span>--- nginx-1.1.11.orig/src/http/ngx_http_upstream.h <span>2011</span>-<span>12</span>-09 <span>21</span>:<span>19</span>:<span>57.000000000</span> +0800</span><br /><span>+++ nginx-1.1.11/src/http/ngx_http_upstream.h <span>2011</span>-<span>12</span>-<span>19</span> <span>13</span>:<span>50</span>:<span>22.147014289</span> +0800</span><br /><span>@@ -<span>148</span>,<span>6</span> +<span>148</span>,<span>10</span> @@</span><br /> <br /> ngx_flag_t ignore_client_abort;<br /> ngx_flag_t intercept_errors;<br /><span>+ // twu2 begin</span><br /><span>+ // add an option to skip intercept <span>404</span> error</span><br /><span>+ ngx_flag_t intercept_error_skip_404;</span><br /><span>+ // twu2 end</span><br /> ngx_flag_t cyclic_temp_file;<br /> <br /> ngx_path_t *temp_path;</pre></div></pre><p>經過這個修正之後, 我們只要在 nginx.conf 中設定</p><pre class="apache"><div class="insertcode"><pre class="apache" style="font-family: monospace"> fastcgi_intercept_errors <span>on</span>;<br /> fastcgi_intercept_error_skip_404 <span>on</span>;</pre></div></pre><p>然後在 php 的處理之前加上檔案的存在檢查:</p><pre class="apache"><div class="insertcode"><pre class="apache" style="font-family: monospace"><strike>location ~ \.php$ {<br /> try_files $uri =<span>404</span>;</strike></pre></div></pre><p><strike>用 try_files 去檢查是否存在, 不存在就回傳 404.</strike></p><p>用 try_files 似乎會檢查不出來, 所以看來還是要用 if 來處理:</p><pre class="apache"><div class="insertcode"><pre class="apache" style="font-family: monospace"><span class="co1"># without path_info</span><br />location ~ ^(?<SCRIPT_NAME>/.*\.(php|suphp))$ {<br /> if (!-f $document_root$SCRIPT_NAME) {<br /> return <span class="nu0">404</span>;<br /> }</pre></div></pre><p>在 userdir 上頭, 由於目錄會改寫, 直接用 try_files 會有問題, 可以改成這樣:</p><pre class="apache"><div class="insertcode"><pre class="apache" style="font-family: monospace">location ~ ^/~(?<USER>.+?)(?<SCRIPT_NAME>/.+\.php)$ {<br /> root /home/$USER/public_html;<br /> if (!-f $document_root$SCRIPT_NAME) {<br /> return <span>404</span>;<br /> }</pre></div></pre><p>這樣子就可以達到我們要的功能了.</p><hr width="100%" size="2" /><p>補充一下, 上頭那個 php 的處理, 如果使用 try_files 在 PATH_INFO 的狀態時, 會造成 PATH_INFO 無法正常使用, 所以對於 PATH_FILE 的 php 處理, 要改成跟 userdir 一樣, 用 if 來處理才可以, 如:</p><pre class="apache"><div class="insertcode"><pre class="apache" style="font-family: monospace"><span class="co1"># with path_info</span><br />location ~ ^(?<SCRIPT_NAME>/.*\.(php|suphp))(?<PATH_INFO>.*)$ {<br /> <span class="co1"># use try_files here will make PATH_INFO not work, so use if</span><br /> <span class="co1">#try_files $uri =404;</span><br /> if (!-f $document_root$SCRIPT_NAME) {<br /> return <span class="nu0">404</span>;<br /> }</pre></div></pre><p>改成這樣, 有用到 PATH_INFO 的程式就正常了. </p>
PHP
Nginx
2011-12-19T17:54:06Z
tommy
-
Gallery 3 的 Search 中文修正
https://blog.teatime.com.tw/1/post/401
<p>在 <a href="http://gallery.menalto.com/" target="_blank">Gallery</a> 3 的 <a href="http://codex.gallery2.org/Gallery3:Modules:search" target="_blank">Search 模組</a>中, 是透過 <a href="http://www.mysql.com/" target="_blank">MySQL</a> 的 <a href="http://dev.mysql.com/doc/refman/5.1/en/fulltext-search.html" target="_blank">full-text search</a> 方式來處理, 不過... 這個方式對於 CJK 之類的文字, 由於無法分辨詞的斷點, 是無法正常運作的. 這個修改, 是把有非英文的 search, 改成 like 來處理 (東西一多, 也許效能會很差, 所以... 如果你的系統這樣子改之後, 找東西變很慢的話, 就不要用了).</p><pre class="diff"><div class="insertcode"><pre class="diff" style="font-family: monospace">diff -Nur gallery3.orig/modules/search/helpers/search.php gallery3/modules/search/helpers/search.php<br /><span class="re3">--- gallery3.orig/modules/search/helpers/search.php <span class="nu0">2011</span>-05-<span class="nu0">25</span> <span class="nu0">12</span>:04:<span class="nu0">04.000000000</span> +0800</span><br /><span class="re4">+++ gallery3/modules/search/helpers/search.php <span class="nu0">2011</span>-<span class="nu0">12</span>-<span class="nu0">16</span> <span class="nu0">15</span>:<span class="nu0">10</span>:<span class="nu0">51.490772461</span> +0800</span><br /><span class="re6">@@ -<span class="nu0">36</span>,<span class="nu0">6</span> +<span class="nu0">36</span>,<span class="nu0">14</span> @@</span><br /> <br /> static function search<span class="br0">(</span>$q, $limit, $offset<span class="br0">)</span> <span class="br0">{</span><br /> $db = Database::instance<span class="br0">(</span><span class="br0">)</span>;<br /><span class="re8">+ // twu2 begin</span><br /><span class="re8">+ // mysql full-text search is not work for CJK, so we won't do it</span><br /><span class="re8">+ $not_ascii = false;</span><br /><span class="re8">+ $x = preg_replace<span class="br0">(</span>'/<span class="br0">[</span>\x80-\xFFFFFF<span class="br0">]</span>/', '', $q<span class="br0">)</span>;</span><br /><span class="re8">+ if <span class="br0">(</span>$x !== $q<span class="br0">)</span></span><br /><span class="re8">+ $not_ascii = true; </span><br /><span class="re8">+ else</span><br /><span class="re8">+ // twu2 end</span><br /> $q = $db->escape<span class="br0">(</span>$q<span class="br0">)</span>;<br /> <br /> if <span class="br0">(</span>!identity::active_user<span class="br0">(</span><span class="br0">)</span>->admin<span class="br0">)</span> <span class="br0">{</span><br /><span class="re6">@@ -<span class="nu0">47</span>,<span class="nu0">6</span> +<span class="nu0">55</span>,<span class="nu0">34</span> @@</span><br /> $access_sql = "";<br /> <span class="br0">}</span><br /> <br /><span class="re8">+ // twu2 begin</span><br /><span class="re8">+ if <span class="br0">(</span>$not_ascii<span class="br0">)</span> <span class="br0">{</span></span><br /><span class="re8">+ $data_filter = '';</span><br /><span class="re8">+ $items = explode<span class="br0">(</span>' ', $q<span class="br0">)</span>;</span><br /><span class="re8">+ foreach <span class="br0">(</span>$items as $v<span class="br0">)</span> <span class="br0">{</span></span><br /><span class="re8">+ $s = rtrim<span class="br0">(</span>$v, '*'<span class="br0">)</span>;</span><br /><span class="re8">+ if <span class="br0">(</span>$s === ''<span class="br0">)</span> continue;</span><br /><span class="re8">+ $s = str_replace<span class="br0">(</span>'%', '\%', $s<span class="br0">)</span>;</span><br /><span class="re8">+ $s = str_replace<span class="br0">(</span>'_', '\_', $s<span class="br0">)</span>;</span><br /><span class="re8">+ $s = $db->escape<span class="br0">(</span>$s<span class="br0">)</span>;</span><br /><span class="re8">+ if <span class="br0">(</span>$data_filter == ''<span class="br0">)</span></span><br /><span class="re8">+ $data_filter = "<span class="br0">(</span><span class="br0">{</span>search_records<span class="br0">}</span>.`data` LIKE '%$s%'<span class="br0">)</span>";</span><br /><span class="re8">+ else</span><br /><span class="re8">+ $data_filter .= " OR <span class="br0">(</span><span class="br0">{</span>search_records<span class="br0">}</span>.`data` LIKE '%$s%'<span class="br0">)</span>";</span><br /><span class="re8">+ <span class="br0">}</span> </span><br /><span class="re8">+ if <span class="br0">(</span>$data_filter == ''<span class="br0">)</span></span><br /><span class="re8">+ $data_filter = "<span class="br0">(</span><span class="br0">{</span>search_records<span class="br0">}</span>.`id` IS NULL<span class="br0">)</span>";</span><br /><span class="re8">+ $query =</span><br /><span class="re8">+ "SELECT SQL_CALC_FOUND_ROWS <span class="br0">{</span>items<span class="br0">}</span>.*, " .</span><br /><span class="re8">+ " <span class="nu0">1</span> AS `score` " .</span><br /><span class="re8">+ "FROM <span class="br0">{</span>items<span class="br0">}</span> JOIN <span class="br0">{</span>search_records<span class="br0">}</span> ON <span class="br0">(</span><span class="br0">{</span>items<span class="br0">}</span>.`id` = <span class="br0">{</span>search_records<span class="br0">}</span>.`item_id`<span class="br0">)</span> " .</span><br /><span class="re8">+ "WHERE <span class="br0">(</span>$data_filter<span class="br0">)</span> " .</span><br /><span class="re8">+ $access_sql .</span><br /><span class="re8">+ "ORDER BY `name` DESC " .</span><br /><span class="re8">+ "LIMIT $limit OFFSET $offset";</span><br /><span class="re8">+ <span class="br0">}</span></span><br /><span class="re8">+ else </span><br /><span class="re8">+ // twu2 end</span><br /> $query =<br /> "SELECT SQL_CALC_FOUND_ROWS <span class="br0">{</span>items<span class="br0">}</span>.*, " .<br /> " MATCH<span class="br0">(</span><span class="br0">{</span>search_records<span class="br0">}</span>.`data`<span class="br0">)</span> AGAINST <span class="br0">(</span>'$q'<span class="br0">)</span> AS `score` " .</pre></div></pre><p>這樣子改, 是可以找到資料.... 資料少的時候,速度應該也不會有問題. 等以後資料多的時候, 再看看會不會有什麼重大的效能影響吧. </p>
Gallery
PHP
2011-12-16T15:13:00Z
tommy
-
Lifetype 模組: gallery
https://blog.teatime.com.tw/1/post/400
<p>這個是以前寫給 <a href="http://www.lifetype.net/" target="_blank">LifeType</a> 使用的 gallery 模組的修改版本, 與之前版本的差異就是可以選擇不使用 Gallery 的 embed 方式來存取. (這時相簿的連結會直接轉到 <a href="http://gallery.menalto.com/" target="_blank">Gallery</a> 的網頁)</p><p>檔案放這兒: <a href="http://www.teatime.com.tw/~tommy/files/lifetype/lifetype_gallery.tgz">http://www.teatime.com.tw/~tommy/files/lifetype/lifetype_gallery.tgz</a> </p><p>需要的就自己抓回去用吧.</p><p> </p>
LifeType
PHP
2011-12-16T12:54:18Z
tommy
-
Lifetype 模組: minislideshow
https://blog.teatime.com.tw/1/post/399
<p>這是給 <a href="http://www.lifetype.net/" target="_blank">LifeType</a> 用的 <a href="http://www.flashyourweb.com/article.php?story=mini_slideshow" target="_blank">minislideshow</a> plugin, 可以加上一個區塊顯示 minislideshow 的內容.</p><p>檔案放這兒: <a href="http://www.teatime.com.tw/~tommy/files/lifetype/lifetype_minislideshow.tgz" target="_blank">http://www.teatime.com.tw/~tommy/files/lifetype/lifetype_minislideshow.tgz</a> </p><p>要用的就自己抓回去用吧, 安裝的方式參考裡面的 README 或自己慢慢試吧. </p>
LifeType
PHP
2011-12-16T12:49:30Z
tommy
-
Gallery 3 模組: imageblock2
https://blog.teatime.com.tw/1/post/398
<p>這個模組修改自 <a href="http://gallery.menalto.com/" target="_blank">Gallery</a> 3 的 <a href="http://codex.gallery2.org/Gallery3:Modules:imageblockex" target="_blank">imageblockex</a> 模組.</p><p>因為 imageblockex 有部份的功能無法滿足我的需求:</p><ul><li>RSS Type 選擇 Current Album 會造成程式無法正常運作 (就是寫錯了, 某個變數沒有傳入).</li><li><a href="http://www.flashyourweb.com/article.php?story=mini_slideshow" target="_blank">minislideshow</a> 的參數有些不滿意. (當然我改了之後, 也許別人拿去用也會不滿意)</li><li>沒有支援 flash 時就看不到東西 (改成靜態的隨機圖片)</li><li>選擇要不要用 minislideshow (變成跟原本的 image_block 類似, 不過仍可以依據 RSS Type 來取得資料) </li><li>加上之前<a href="http://blog.teatime.com.tw/1/post/393" target="_blank">修正的 RSS 亂數選擇參數</a>.</li></ul><p>使用的方式可以參考 imageblockex 的說明.</p><p>檔案放這兒: <a href="http://www.teatime.com.tw/~tommy/files/gallery/imageblock2.tgz" target="_blank">http://www.teatime.com.tw/~tommy/files/gallery/imageblock2.tgz</a> </p><p>有需要的自己抓回去用吧. </p>
Gallery
PHP
2011-12-16T12:18:53Z
tommy