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

<channel>
	<title>Geek is a Lift-Style.</title>
	<atom:link href="http://www.taiwangeek.com/feed" rel="self" type="application/rss+xml" />
	<link>http://www.taiwangeek.com</link>
	<description>Time has a wonderful way of showing us what really matters.</description>
	<lastBuildDate>Mon, 23 May 2011 07:18:17 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.2</generator>
		<item>
		<title>Gatorhost pdo don&#8217;t support sqlite3</title>
		<link>http://www.taiwangeek.com/2011-05/gatorhost-pdo-dont-support-sqlite3.html</link>
		<comments>http://www.taiwangeek.com/2011-05/gatorhost-pdo-dont-support-sqlite3.html#comments</comments>
		<pubDate>Mon, 23 May 2011 07:08:48 +0000</pubDate>
		<dc:creator>tung</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[原創]]></category>
		<category><![CDATA[gatorhost]]></category>
		<category><![CDATA[pdo_sqlite]]></category>
		<category><![CDATA[sqlite3]]></category>

		<guid isPermaLink="false">http://www.taiwangeek.com/?p=6432</guid>
		<description><![CDATA[Greetings,
The sqlite PDO extension appears to be loaded properly. However, it appears that the extension supports sqlite2, but not sqlite3. Currently, I see the use of sqlite3 in your scripts. You will need to use sqlite2 instead in order for them to work properly. I apologize for the inconvenience.

Please feel free to ask if you need anything else at all.]]></description>
			<content:encoded><![CDATA[<p>As title </p>
<blockquote><p>
Greetings,<br />
The sqlite PDO extension appears to be loaded properly. However, it appears that the extension supports sqlite2, but not sqlite3. Currently, I see the use of sqlite3 in your scripts. You will need to use sqlite2 instead in order for them to work properly. I apologize for the inconvenience.</p>
<p>Please feel free to ask if you need anything else at all.
</p></blockquote>
<p>But I got a solution ~~<br />
1.</p>
<pre class="brush:shell">
cp -rf /opt/php53/lib/php/extensions/no-debug-non-zts-20090626/* ext/
</pre>
<p>2.conpile the pdo_sqlite.so by your self convert the ext/pdo_sqlite.so</p>
<p>3. change extension_dir in php.ini to the .so file you made.</p>
<pre class="brush:shell">
extension_dir = "/home/xxx/ext"
</pre>
<p>yes all done~~<br />
Something come from here (http://forums.hostgator.com/php-5-3-support-t100928.html)<br />
Hello,</p>
<p>We currently offer PHP 5.3 support on our shared servers as an addition with PHP 5.2.  In order to utilize PHP 5.3 on your domain, place the following code inside the document roots .htaccess file:</p>
<div style="margin: 5px 20px 20px;">
<div class="smallfont" style="margin-bottom: 2px;">Code:</div>
<pre class="alt2" dir="ltr" style="margin: 0px; padding: 6px; border: 1px inset; width: 520px; height: 50px; text-align: left; overflow: auto;">Action application/x-hg-php53 /cgi-sys/php53
AddType application/x-httpd-php53 .php</pre>
</div>
<p>
Thanks Richard for the below information:</p>
<div style="margin: 5px 20px 20px;">
<div class="smallfont" style="margin-bottom: 2px;">Quote:</div>
<table width="100%" border="0" cellpadding="6" cellspacing="0">
<tbody>
<tr>
<td class="alt2" style="border: 1px inset;">
<p>				CAUTION: For those who use the cPanel &#8220;QuickConfig&#8221; feature, it should be noted that it works by putting a php.ini copy into the /home/username/ folder and setting the suPHP_ConfigPath in your primary .htaccess file to point to that copy.</p>
<p>Because the &#8220;QuickConfig&#8221; php.ini copy is originally based on the php.ini file that is installed as part of the server&#8217;s setup for its default PHP version, there may be serious problems if the user subsequently decides to use some other PHP version. The php.ini copy pointed to by the suPHP_ConfigPath that &#8220;QuickConfig&#8221; sets may contain configuration paths, extensions and other settings that are not suitable for a PHP version that is chosen thereafter. It may even be missing some settings required by the newer version entirely.</p>
<p>As just one of many examples of problems that can thus arise, the PHP 5.3 option discussed by GatorJacob as the topic of this thread differs from PHP 5.2 in the server path that is used for its extension modules &#8211;<br />
PHP 5.2: extension_dir = &#8220;/usr/local/lib/php/extensions/no-debug-non-zts-20060613&#8243;<br />
PHP 5.3: extension_dir = &#8220;/opt/php53/lib/php/extensions/no-debug-non-zts-20090626&#8243;</p>
<p>So, if you&#8217;ve used cPanel&#8217;s &#8220;QuickConfig&#8221; to set up or modify your PHP configuration, get rid of its php.ini copy and the suPHP_ConfigPath pointer to it that &#8220;QuickConfig&#8221; puts in your primary .htaccess file before implementing any PHP version change!</p>
</td>
</tr>
</tbody>
</table>
</div>
<p>Here is a generic fix for the TZ issue</p>
<p>PHP Code:</p>
<div style="margin: 5px 20px 20px;">
<div class="smallfont" style="margin-bottom: 2px;">Code:</div>
<pre class="alt2" dir="ltr" style="margin: 0px; padding: 6px; border: 1px inset; width: 520px; height: 98px; text-align: left; overflow: auto;">// Force PHP 5.3.0+ to take time zone information from OS
if (version_compare(phpversion(), '5.3.0', '&gt;='))
{
    @date_default_timezone_set(date_default_timezone_get());
}</pre>
</div>
<p>Please do let us know if you see any problems</p>
]]></content:encoded>
			<wfw:commentRss>http://www.taiwangeek.com/2011-05/gatorhost-pdo-dont-support-sqlite3.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>[xgettext ]when charset=CHARSET</title>
		<link>http://www.taiwangeek.com/2011-05/xgettext-when-charsetcharset.html</link>
		<comments>http://www.taiwangeek.com/2011-05/xgettext-when-charsetcharset.html#comments</comments>
		<pubDate>Fri, 13 May 2011 10:39:35 +0000</pubDate>
		<dc:creator>tung</dc:creator>
				<category><![CDATA[Linux like]]></category>
		<category><![CDATA[xgettext]]></category>

		<guid isPermaLink="false">http://www.taiwangeek.com/?p=6429</guid>
		<description><![CDATA[Damm~~bug! Need to use sed to replace CHARSET~ xgettext --language=php --from-code=utf-8 --output="/defraction-light-red/defraction-light-red.po" -D /defraction-light-red/*.php sed --in-place /defraction-light-red/defraction-light-red.po --expression=s/charset=CHARSET/charset=UTF-8/]]></description>
			<content:encoded><![CDATA[<p>Damm~~bug!</p>
<p>Need to use sed to replace <b>CHARSET</b>~</p>
<pre class="brush:shell">
xgettext --language=php --from-code=utf-8 --output="/defraction-light-red/defraction-light-red.po" -D /defraction-light-red/*.php
sed --in-place /defraction-light-red/defraction-light-red.po --expression=s/charset=CHARSET/charset=UTF-8/
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.taiwangeek.com/2011-05/xgettext-when-charsetcharset.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Amazon EC2神兵 &#8211; scalr</title>
		<link>http://www.taiwangeek.com/2011-04/amazon-ec2%e7%a5%9e%e5%85%b5-scalr.html</link>
		<comments>http://www.taiwangeek.com/2011-04/amazon-ec2%e7%a5%9e%e5%85%b5-scalr.html#comments</comments>
		<pubDate>Fri, 29 Apr 2011 03:34:18 +0000</pubDate>
		<dc:creator>tung</dc:creator>
				<category><![CDATA[Featured]]></category>

		<guid isPermaLink="false">http://www.taiwangeek.com/?p=6421</guid>
		<description><![CDATA[身為台灣人 林北真的很難過 玩EC2的這麼少 分享的資料這麼的貧脊 大家都寫一些簡單的東西 哄一些初學者去玩&#8221;雲端&#8221; 可當你真的把網站放到EC2 你還是要面對架構的問題 否則雲端未必比你上一家租的VPS來得好用 現在讓林北來分享一些真正有料的 無碼的 重口味的東西吧 ps,這種東西 不是入門 是給真正的玩家看得 應該可以解救不少網管人員 scalr 開源的PHP專案 直接集佈署 監控 EC2於一身 連AIM都幫你開好了 還是燒燙燙的Nqinx+php唷 https://scalr.net/tour.html]]></description>
			<content:encoded><![CDATA[<p>身為台灣人 林北真的很難過 玩EC2的這麼少 分享的資料這麼的貧脊<br />
大家都寫一些簡單的東西 哄一些初學者去玩&#8221;雲端&#8221;</p>
<p>可當你真的把網站放到EC2 你還是要面對架構的問題 否則雲端未必比你上一家租的VPS來得好用</p>
<p>現在讓林北來分享一些真正有料的 無碼的 重口味的東西吧</p>
<p>ps,這種東西 不是入門 是給真正的玩家看得 應該可以解救不少網管人員</p>
<h3>scalr</h3>
<p>開源的PHP專案 直接集佈署 監控 EC2於一身 連AIM都幫你開好了 還是燒燙燙的Nqinx+php唷</p>
<p>https://scalr.net/tour.html</p>
<p><img src="https://scalr.net/site/images/screenshots/small/farm_map.png" alt="圖形化的Instance管理" /><br />
<img src="https://scalr.net/site/images/screenshots/small/stats.png" alt="系統資源監控" /><br />
<img src="https://scalr.net/site/images/screenshots/small/farm_edit.png" alt="一目了然的伺服器列表" /></p>
]]></content:encoded>
			<wfw:commentRss>http://www.taiwangeek.com/2011-04/amazon-ec2%e7%a5%9e%e5%85%b5-scalr.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>use curl to got Content-Disposition filename</title>
		<link>http://www.taiwangeek.com/2011-01/use-curl-to-got-content-disposition-filename.html</link>
		<comments>http://www.taiwangeek.com/2011-01/use-curl-to-got-content-disposition-filename.html#comments</comments>
		<pubDate>Mon, 10 Jan 2011 03:42:12 +0000</pubDate>
		<dc:creator>tung</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[php curl]]></category>
		<category><![CDATA[原創]]></category>

		<guid isPermaLink="false">http://www.taiwangeek.com/?p=5655</guid>
		<description><![CDATA[curl CURLOPT_BINARYTRANSFER can't not got Content-Disposition filename for u]]></description>
			<content:encoded><![CDATA[<pre class="brush:php">/*
* usage:
=================================================
$fn = CurlTool::downloadFile('http://aaabb.com/download.php?id=zzzaaa','./');
echo "Grab file path =",$fn,"\n";
var_dump(CurlTool::$attach_info);
*/
class CurlTool {
    public static $userAgents = array(
        'FireFox3' =&gt; 'Mozilla/5.0 (Windows; U; Windows NT 5.1; pl; rv:1.9) Gecko/2008052906 Firefox/3.0',
        'GoogleBot' =&gt; 'Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)',
        'IE7' =&gt; 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)',
        'Netscape' =&gt; 'Mozilla/4.8 [en] (Windows NT 6.0; U)',
        'Opera' =&gt; 'Opera/9.25 (Windows NT 6.0; U; en)'
        );
    public static $options = array(
        CURLOPT_USERAGENT =&gt; 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)',
        CURLOPT_AUTOREFERER =&gt; true,
        CURLOPT_COOKIEFILE =&gt; '',
        CURLOPT_FOLLOWLOCATION =&gt; true
        );
    public static $header = array();
    public static $attach_info = array();

    private static $proxyServers = array();
    private static $proxyCount = 0;
    private static $currentProxyIndex = 0;

    public static function addProxyServer($url) {
        self::$proxyServers[] = $url;
        ++self::$proxyCount;
    }

    public static function fetchContent($url, $verbose = false,$url_reffer=false) {
        if (($curl = curl_init($url)) == false) {
            throw new Exception("curl_init error for url $url.");
        }

        if (self::$proxyCount &gt; 0) {
            $proxy = self::$proxyServers[self::$currentProxyIndex++ % self::$proxyCount];
            curl_setopt($curl, CURLOPT_PROXY, $proxy);
            if ($verbose === true) {
                echo "Reading $url [Proxy: $proxy] ... ";
            }
        } else if ($verbose === true) {
            echo "Reading $url ... ";
        }

        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
        curl_setopt_array($curl, self::$options);
        if (is_string($url_reffer)) {
            curl_setopt($curl,CURLOPT_REFERER,$url_reffer);
        }
        $content = curl_exec($curl);
        if ($content === false) {
            throw new Exception("curl_exec error for url $url.");
        }
       	self::$header = curl_getinfo($curl);
        curl_close($curl);
        if ($verbose === true) {
            echo "Done.\n";
        }
        return $content;
    }

    public static function downloadFile($url, $fileName, $verbose = false) {
        if (($curl = curl_init($url)) == false) {
            throw new Exception("curl_init error for url $url.");
        }

        if (self::$proxyCount &gt; 0) {
            $proxy = self::$proxyServers[self::$currentProxyIndex++ % self::$proxyCount];
            curl_setopt($curl, CURLOPT_PROXY, $proxy);
            if ($verbose === true) {
                echo "Downloading $url [Proxy: $proxy] ... ";
            }
        } else if ($verbose === true) {
            echo "Downloading $url ... ";
        }

        curl_setopt_array($curl, self::$options);

        if (substr($fileName, -1) == '/') {
            $targetDir = $fileName;
            $fileName = tempnam(sys_get_temp_dir(), 'c_');
        }
        if (($fp = fopen($fileName, "wb")) === false) {
            throw new Exception("fopen error for filename $fileName");
        }
        curl_setopt($curl, CURLOPT_FILE, $fp);
		curl_setopt($curl,CURLOPT_HEADERFUNCTION,'self::get_att');
        curl_setopt($curl, CURLOPT_BINARYTRANSFER, true);
        if (curl_exec($curl) === false) {
            fclose($fp);
            unlink($fileName);
            throw new Exception("curl_exec error for url $url.");
        } elseif (isset($targetDir)) {
            $eurl = curl_getinfo($curl, CURLINFO_EFFECTIVE_URL);
            preg_match('#^.*/(.+)$#', $eurl, $match);
            fclose($fp);
            rename($fileName, "$targetDir{$match[1]}");
            $fileName = "$targetDir{$match[1]}";
        } else {
            fclose($fp);
        }
		self::$header = curl_getinfo($curl);
        curl_close($curl);
        if ($verbose === true) {
            echo "Done.\n";
        }
        return $fileName;
    }

	public static function get_att($ch, $header){
		if (preg_match("/Content-Length: (\d*)/i",$header,$matches)) {
			self::$attach_info['size'] = $matches[1];
		} elseif (preg_match('/Content-Disposition:.*?filename="(.*)"/i',$header,$matches)) {
			self::$attach_info['filename'] = $matches[1];
		} elseif (preg_match("/Content-Type: ([^; ]*)/i",$header,$matches)) {
			self::$attach_info['type'] = $matches[1];
		}
		//echo "$header";
		return strlen($header);
	}
    // activates POST and set post data
    public static function addPostData($data) {
        self::$options[CURLOPT_POST] = true;
        self::$options[CURLOPT_POSTFIELDS] = $data;
    }
}
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.taiwangeek.com/2011-01/use-curl-to-got-content-disposition-filename.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Advanced Windows Batch File Scripting</title>
		<link>http://www.taiwangeek.com/2010-09/advanced-windows-batch-file-scripting.html</link>
		<comments>http://www.taiwangeek.com/2010-09/advanced-windows-batch-file-scripting.html#comments</comments>
		<pubDate>Sun, 12 Sep 2010 19:54:03 +0000</pubDate>
		<dc:creator>tung</dc:creator>
				<category><![CDATA[Google Reader]]></category>
		<category><![CDATA[article]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[normal]]></category>
		<category><![CDATA[online]]></category>
		<category><![CDATA[ping]]></category>
		<category><![CDATA[portable]]></category>
		<category><![CDATA[thoughts]]></category>
		<category><![CDATA[time]]></category>
		<category><![CDATA[windows]]></category>

		<guid isPermaLink="false">http://www.taiwangeek.com/2010-09/advanced-windows-batch-file-scripting.html</guid>
		<description><![CDATA[ Shared by &#23567;&#33891; 這樣的一篇關於windows batch file技巧的文章 近年少見 推!! First off, this is a single windows .bat file that I have written to do advanced batch scripting the easy way, meaning it’s mostly a series of functions you can call from the script or within other functions for extremely modular code. Before you get all bent out of shape by my choice of words (“easy, modular”), when I say this is advanced I mean for Windows .bat files, one of the worlds worst scripting languages, but it works on all windows versions so it’s ideal for things like autorun, autoplay, custom startups, usb drives, etc.. ]]></description>
			<content:encoded><![CDATA[<blockquote>
<p><img src="http://www.taiwangeek.com/wp-content/uploads/2010/09/eca82c0e9atled-1.png-150x49.png" /></p>
<p>View post:<br />
<a  target="_blank" href="http://feeds.askapache.com/~r/apache/htaccess/~3/ikd29vXQPr4/advanced-batch-scripting.html" title="Advanced Windows Batch File Scripting">Advanced Windows Batch File Scripting</a>
</p></blockquote>
<p><!--/content--></p>
<blockquote><p>Shared by  &#23567;&#33891;<br />
<br />
這樣的一篇關於windows batch file技巧的文章 近年少見 推!!</p></blockquote>
<p><a  href="http://www.askapache.com/windows/advanced-batch-scripting.html/untitled-1/" rel="attachment wp-att-4618"><img src="http://www.taiwangeek.com/wp-content/uploads/2010/09/eca82c0e9atled-1.png.png" alt="Create an AT job to run as system in Notepad++ IDE" title="Create an AT job to run as system in Notepad++ IDE" width="993" height="326" /></a></p>
<p><a  href="http://www.taiwangeek.com/wp-content/uploads/2010/09/703143eb9cxample.png.png" class="thickbox no_icon" rel="gallery-1363" title="Windows Batch Programming Example"><img src="http://www.taiwangeek.com/wp-content/uploads/2010/09/cbe7e8724f116x45.png.png" alt="Windows Batch Programming Example" title="Windows Batch Programming Example" width="116" height="45" /></a>First off, this is a single windows <code>.bat</code> file that I have written to do advanced batch scripting the easy way, meaning it’s mostly a series of functions you can call from the script or within other functions for extremely modular code.  Before you get all bent out of shape by my choice of words (“easy, modular”), when I say this is advanced I mean for Windows .bat files, one of the worlds worst scripting languages, but it works on all windows versions so it’s ideal for things like autorun, autoplay, custom startups, usb drives, etc..  If you are looking for information on how to use and program windows .bat files to do anything cool, this is the right place!  I tried my best to mimic linux shell-scripting, so it’s likely different than other batch files you have seen.</p>
<h2>Batch File IDE and Script Source</h2>
<p><a  href="http://www.taiwangeek.com/wp-content/uploads/2010/09/eca82c0e9atled-1.png.png" class="thickbox no_icon" rel="gallery-1363" title="Create an AT job to run as system in Notepad++ IDE"><img src="http://www.taiwangeek.com/wp-content/uploads/2010/09/21a4a9edd8116x38.png.png" alt="Create an AT job to run as system in Notepad++ IDE" title="Create an AT job to run as system in Notepad++ IDE" width="116" height="38" /></a>My favorite tool (and I’ve tried sooo many) for editing most Windows files and especially .bat files is the free and open-source <a  href="http://notepad-plus-plus.org/">Notepad++</a>.  Set that up and you will have a color-syntax-highlighted editor for Batch Scripting that works very very well.</p>
<p><a  href="http://uploads.askapache.com/2010/09/advanced-batch-askapache.txt"><img src="http://www.taiwangeek.com/wp-content/uploads/2010/09/b669c23da4h-file.png.png" width="46" height="60" title="windows batch file featured" alt="Advanced Windows Batch File Scripting" /></a>The next thing to do is <a  href="http://uploads.askapache.com/2010/09/advanced-batch-askapache.txt">download the source code</a>, which includes comments and formatting I had to remove for this online article.  Then rename from <code>.txt</code> to <code>.bat</code> and open in your IDE/text-editor of choice.</p>
<h2>Quick Batch File Example</h2>
<p>This is a simple batch file named ping-check.bat that I use when rebooting remote servers.  The reboot is issued from an SSH session and causes the server to go down and then come back up.  When the server goes down the network goes down too so I fire this script up to continually ping the remote server until it responds, at which point I can ssh back in.</p>
<p>One of the first hacks for batch files is line 1, the PUSHD command cd’s the scripts working environment to the directory of the script itself.</p>
<pre class="brush: php;">@ECHO OFF &#038;&#038; PUSHD "%~dp0" &#038;&#038; SETLOCAL
 
CALL <img src='http://www.taiwangeek.com/wp-includes/images/smilies/icon_razz.gif' alt=':P' class='wp-smiley' /> INGCHECK "%~1"
 
nircmd.exe speak text "PING RECEIVED.  HOST BACK ONLINE" 7 60
ENDLOCAL &#038;&#038; POPD &#038;&#038; GOTO :EOF
  <img src='http://www.taiwangeek.com/wp-includes/images/smilies/icon_razz.gif' alt=':P' class='wp-smiley' /> INGCHECK
ECHO CHECKING %~1
ping.exe -n 1 %~1 -w 5000 | FIND /C "Reply from %~1" | FIND "1" >nul 2>&#038;1
IF ERRORLEVEL 1 CALL <img src='http://www.taiwangeek.com/wp-includes/images/smilies/icon_razz.gif' alt=':P' class='wp-smiley' /> INGCHECK "%~1" ELSE EXIT /B</pre>
<h2>Super-hero like even</h2>
<p>Just added this as an after thought, moving the main example further down this page.  This is an easier file to understand the scope of.  It effectively creates SSH-encrypted SOCK5 tunnels that stay connected and auto-reconnect if the link goes down.  I wanted to try and write a pure batch method to do that.   I wrote this to run automatically from a USB key so that I could keep my tools with me portably.  The thing of this script that is the most revolutionary is the method it uses to create auto-reconnecting <em>SSH-encrypted SOCKS5 tunnels</em> using the windows SYSTEM account to do it all in the background with plink.exe.  The hack to run it as a system account is by using the built-in <strong>AT</strong> command to run interactively, which lets you interactively do whatever you want as the builtin <code>NT AUTHORITY/SYSTEM</code> account.  The other part I am proud of with this is how lean I got the code, specifically how lean the function is that creates the at job to run every 5 minutes, while still doing connection-testing, all by parsing the cmd.exe processors builtin in DATE and TIME variables.  Do a google search for “windows batch file date and time” and you will appreciate just how lean this sucker is.</p>
<p>Almost forgot, check out the ways to keep a plink.exe (putty.exe for cmd.exe) SOCKS5 tunnel hidden and safe and continuously connected to a remote server in minimal lines od code.  This was a fun one to work on!  Enjoy (and remember this is just the warm-up example to glance at).</p>
<pre class="brush: php;">@ECHO OFF &#038;&#038; PUSHD "%~dp0" &#038;&#038; SETLOCAL &#038;&#038; SETLOCAL ENABLEDELAYEDEXPANSION &#038;&#038; SETLOCAL ENABLEEXTENSIONS
 
SET _CRYPTDRIVE=%~d0
SET PATH=%_CRYPTDRIVE%PP;%_CRYPTDRIVE%PPbin;%PATH%
SET _PUTTYBIN=%_CRYPTDRIVE%PPPputty.exe
 
SET _PSERVER=solar.power.com
SET _PPORT=22
SET _PSESSION=newclean-tunnel
 
SET _ADMINUSER=admin
SET _RUNUSER=life
 
REM SAY CHECKING PLINK OUT LOUD
CALL :SPEAK "Checking Putty"
ECHO "CHECKING PUTTY"
 
REM
IF NOT EXIST "%_CRYPTDRIVE%" (
  CALL :SPEAK "Crypt Not Mounted"
  AT|FOR /F "tokens=1" %%i IN (&#39;FIND /I "%~f0"&#39;) DO AT %%i /delete /yes >nul 2>&#038;1
  pskill.exe -t putty >nul 2>&#038;1
  pskill.exe -t thunderbird >nul 2>&#038;1
  pskill.exe -t ThunderbirdPortable >nul 2>&#038;1
  pskill.exe -t Firefox >nul 2>&#038;1
  pskill.exe -t FirefoxPortable >nul 2>&#038;1
  pskill.exe -t GC >nul 2>&#038;1
  EXIT
)
 
REM CREATE AT JOB TO RUN THIS SCRIPT EVERY 5 MINUTES
CALL :CREATEATJOB
 
pslist putty >nul 2>&#038;1
IF ERRORLEVEL 1 psexec.exe -i 0 -e -d -u %_RUNUSER% %_PUTTYBIN% -load %_PSESSION%
 
REM KILL MULTIPLE PSEXEC&#39;s
CALL :KILLDUPES "psexec.exe"
 
REM KILL MULTIPLE CMD.EXE&#39;s
CALL :KILLDUPES "cmd.exe"
 
REM REACHABLE SERVER CHECK
CALL <img src='http://www.taiwangeek.com/wp-includes/images/smilies/icon_razz.gif' alt=':P' class='wp-smiley' /> INGCHECK %_PSERVER%
 
REM CHECK FOR INACTIVE PUTTY
CALL <img src='http://www.taiwangeek.com/wp-includes/images/smilies/icon_razz.gif' alt=':P' class='wp-smiley' /> UTTYCHECK
 
REM CHECK PORT IS LISTENING (FOR SOCKISFIED TUNNEL)
CALL <img src='http://www.taiwangeek.com/wp-includes/images/smilies/icon_razz.gif' alt=':P' class='wp-smiley' /> ORTCHECK %_PPORT%
 
REM CALL :SPEAK "OK"
SLEEP 100 &#038;&#038; ECHO "OK" &#038;&#038; SLEEP 1 &#038;&#038; ENDLOCAL &#038;&#038; POPD &#038;&#038; EXIT
 
REM =======================================================================================
REM =   SPEAK - Speak text
REM =======================================================================================
:SPEAK
nircmd.exe speak text "%~1" 5 60
ECHO "%~1"
EXIT /B
 
REM =======================================================================================
REM =   RESTARTPLINK - Sleeps for %1 number of seconds
REM =======================================================================================
:RESTARTPLINK
CALL :SPEAK "%~1 ReSTARTing Plink"
REM runas /savecred /user:admin "%_PUTTYBIN% -load %_PSESSION%"
psexec.exe -i 0 -e -d -u %_RUNUSER% %_PUTTYBIN% -load %_PSESSION%
EXIT
EXIT /B
 
REM =======================================================================================
REM =   PORTCHECK - Check that Port is being used (for tunnels)
REM ======================================================================================= <img src='http://www.taiwangeek.com/wp-includes/images/smilies/icon_razz.gif' alt=':P' class='wp-smiley' /> ORTCHECK
netstat.exe -n -v -a -p TCP | FIND "ESTABLISHED" | FIND ":%~1" >nul 2>&#038;1
IF ERRORLEVEL 1 CALL :RESTARTPLINK "PORT CHECK FAILED"
EXIT /B
 
REM =======================================================================================
REM =   INACTIVEPUTTYCHECK - Check for inactive putty windows
REM ======================================================================================= <img src='http://www.taiwangeek.com/wp-includes/images/smilies/icon_razz.gif' alt=':P' class='wp-smiley' /> UTTYCHECK
tasklist.exe /V /NH /FI "WINDOWTITLE eq PuTTY (inactive)" 2>nul|FIND "INFO: " >nul 2>&#038;1
IF ERRORLEVEL 1 taskkill.exe /T /F /FI "WINDOWTITLE eq PuTTY (inactive)" >nul 2>&#038;1
 
:: MAKE SURE ONLY 1 putty is running that is connected to the remote server
netstat.exe -n -a -o -p TCP | FIND ":%_PPORT%" | FIND /C ":%_PPORT%" | FIND "1" >nul 2>&#038;1
IF ERRORLEVEL 1 (
  tasklist.exe /V /FO TABLE /NH /FI "IMAGENAME eq putty.exe" 2>nul | FIND /C "Running" | FIND "1" >nul 2>&#038;1
  IF ERRORLEVEL 1 (
    REM kill all running puttys (owned by system)
    FOR /F "usebackq tokens=2 skip=2" %%p IN (`tasklist.exe /V /FO TABLE /NH /FI "IMAGENAME eq putty.exe"`) DO taskkill.exe /F /PID %%p /T >nul 2>&#038;1
    CALL :RESTARTPLINK "EXTRA PUTTY FOUND"
  )
)
EXIT /B
 
REM =======================================================================================
REM =   PINGCHECK - PING address to make sure it is reachable
REM ======================================================================================= <img src='http://www.taiwangeek.com/wp-includes/images/smilies/icon_razz.gif' alt=':P' class='wp-smiley' /> INGCHECK
PING %~1 -n 1 -w 5000 | FIND "TTL=" >nul 2>&#038;1
IF ERRORLEVEL 1 (
  PING google.com -n 1 -w 500 | FIND "TTL=" >nul 2>&#038;1
  IF ERRORLEVEL 1 ( CALL :SPEAK "CHECK INTERNET CONNECTION" &#038;&#038; SLEEP 60 )

  PING google.com -n 1 -w 5000 | FIND "TTL=" >nul 2>&#038;1
  IF ERRORLEVEL 1 ( CALL :SPEAK "CHECK INTERNET CONNECTION" &#038;&#038; SLEEP 60 )
 
  PING google.com -n 1 -w 5000 | FIND "TTL=" >nul 2>&#038;1
  IF ERRORLEVEL 1 (
    CALL :SPEAK "KILL SOCKS PROGRAMS"
  SLEEP 100
  pskill.exe -t putty >nul 2>&#038;1
  pskill.exe -t thunderbird >nul 2>&#038;1
  pskill.exe -t ThunderbirdPortable >nul 2>&#038;1
  )
)
EXIT /B
 
REM =======================================================================================
REM =   KILLDUPES - kills duplicate processes, except for the one with lowest pid
REM =======================================================================================
:KILLDUPES
REM Check that more than 1 process is running
tasklist.exe /V /NH /FI "IMAGENAME eq %~1" /FI "USERNAME eq SYSTEM" 2>nul | FIND /C "K Running" | FIND "1" >nul 2>&#038;1
IF NOT ERRORLEVEL 1 EXIT /B
 
REM Create Filename in current dir (of this script)
SET _T=&#038;&#038;SET _T=!_T::=-!&#038;&#038;SET _T=%~dp0%!_T:~0,-2!log
 
REM Create the file in the same dir as this script named for date and sorted by PID
tasklist.exe /V /NH /FI "IMAGENAME eq %~1" /FI "USERNAME eq SYSTEM" 2>nul | SORT /+29 > "%_T%"

REM Check that the file was created or exit
IF NOT EXIST "%_T%" ( CALL :SPEAK "FILE CREATION FAILED" &#038;&#038; EXIT /B )

REM kill all the processes found except for 1, do not kill the process with the lowest pid number
FOR /F "tokens=2 skip=2" %%p IN (%_T%) DO taskkill.exe /F /PID %%p /T

REM erase the file
REM ERASE /Q "%_T%" >nul 2>&#038;1

REM check that the file was erased
REM IF EXIST "%_T%" ( CALL :SPEAK "ERASE FILE FAILED" &#038;&#038; EXIT /B )
 
EXIT /B
 
REM =======================================================================================
REM =   CREATEATJOB - runs job (START this file) every 5 minutes
REM =======================================================================================
:CREATEATJOB
:: delete all putty AT jobs
AT | FIND /C "%~f0" | FIND "1" >nul 2>&#038;1
IF ERRORLEVEL 1 ( AT|FOR /F "tokens=1" %%i IN (&#39;FIND /I "%~f0"&#39;) DO AT %%i /delete /yes >nul 2>&#038;1 )
SET /A H=!TIME:~0,2!&#038;&#038; SET M=!TIME:~3,2!
SET Y=%HM%&#038;&#038; SET /A M+=5
IF !M! GEQ 61 ( SET /A H+=1&#038;&#038;SET /A M-=61 )
IF !H! GEQ 24 SET /A H-=24
SET M=0!M!&#038;&#038; SET H=0!H!
:: create AT job
AT %H:~-2M:~-2% /INTERACTIVE %ComSpec% /E:ON /D /Q /C START /B /MIN %ComSpec% /E:ON /D /Q /C "%~f0" >nul
EXIT /B</pre>
<h2>Advanced Batch File</h2>
<p>This is the main batch file example which you can <a  href="http://uploads.askapache.com/2010/09/advanced-batch-askapache.txt">download here</a>.  Other than some minor changes this is the actual script I use at work when I logon to my PC.  The first thing it does is mount an encrypted TrueCrypt Drive where all of my files and settings are located.  It also starts a putty session named “1″ that I configured to start a few encrypted tunnels and socks proxies so that my email Thunderbird and Website IDE Dreamweaver and other network apps can communicate 100% encrypted and my real location becomes hidden (thanks socks!).</p>
<p>I might come back later and add comments if I get any kind of response for this article, and because it’s such a unique and low-traffic topic, I will try to answer any questions added with the comment form.</p>
<h2>Starting the Script</h2>
<p>The first line is of my own design and is perhaps the coolest hack in the script.  I use this 1 line to start pretty much all of my .bat files.</p>
<pre class="brush: php;">@ECHO OFF&#038;&#038; SETLOCAL&#038;&#038; PUSHD "%~dp0"&#038;&#038; SETLOCAL ENABLEDELAYEDEXPANSION&#038;&#038; SETLOCAL ENABLEEXTENSIONS&#038;&#038; SET V=5&#038;&#038; IF NOT "!V!"=="5" (ECHO DelayedExpansion Failed&#038;&#038; GOTO :EOF)</pre>
<h2>SCRIPT VARIABLES</h2>
<p>These are all local to this script thanks to the SETLOCAL above, so they won’t exist outside the scripts execution environment.</p>
<pre class="brush: php;">REM ** Various vars for output used by functions
SET P1=^^^>^^^>^^^>
SET P2=++
SET P3=::
SET L1=+==============================================================================================================+
SET L2=+--------------------------------------------------------------------------------------------------------------+
 
REM ** administrator username, unless changed for more security, its Administrator
SET ADMINUSER=admin
 
REM ** runuser is the username you use when running this script
SET RUNUSER=bill
 
REM ** Custom COMSPEC for running cmd.exe
SET _SCOM=%COMSPEC% /E:ON /F:ON /D /Q /T:0C /C
 
REM ** Custom START command
SET _START=START /WAIT /MIN /B %_SCOM%</pre>
<h2>MAIN PROGRAM EXECUTION</h2>
<p>This is where the main code starts, note how small it is thanks to the use of functions (labels/call/goto).  Read the comments in this area (start with :: or REM ) to see the extent of this script.  The gold is in the functions.</p>
<pre class="brush: php;">:: Only allow certain users to run this script or die (prevents global STARTup or service running it)
CALL :CHECKUSERVALID %RUNUSER% %ADMINUSER%
 
:: Mount the truecrypt container
CALL :CRYPTMOUNT "L" "%SYSTEMDRIVE%CRYPTLEONARDO" "%SYSTEMDRIVE%CRYPTLEONARDO_KEY"
 
:: Start Mozilla Firefox
CALL :RUNONE "C:Program FilesMozilla Firefoxfirefox.exe"
 
:: Start Thunderbird Portable
CALL :RUNONE "L:PPPputty.exe" "/MIN" -load 1
 
:: Start Thunderbird Portable
CALL :RUNONE "L:PTBThunderbirdPortable.exe" "/MIN"
 
:: Start Adobe Dreamweaver CS4
CALL :RUNONE "C:Program FilesAdobeAdobe Dreamweaver CS4Dreamweaver.exe" "/MIN"
 
:: Start LightScreen Portable
CALL :RUNONE "L:PLPLightscreenPortable.exe" /B /B
 
:: Start Google Chrome Portable ( GREAT to use for pandora/last.fm as its so low mem )
CALL :RUNONE "L:PGCGC.exe" "/NORMAL"
 
:: Start Adobe Photoshop CS4
CALL :RUNONE "%ProgramFiles%AdobeAdobe Photoshop CS4Photoshop.exe" "/MAX"</pre>
<h3>Exit Script</h3>
<p>This is the last line executed in the Main, it forces the script to exit cleanly at this point, otherwise the functions below would all get executed.  This is what allows the use of all the functions below.  I end all my scripts MAIN with this.</p>
<pre class="brush: php;">REM ** EXIT Script
CALL :MDYE "EOF" &#038;&#038; POPD &#038;&#038; ENDLOCAL &#038;&#038; GOTO :EOF</pre>
<h2>SCRIPT FUNCTIONS</h2>
<p>Now then, onto the MEAT of the script, all the functions.  These functions are designed for global use in other batch files, so that the only modification when you make a new batch is the above variables and main execution..  If you know much about batch files you will realize that creating these functions was a very painful process in some cases.. I freakin hate windows!  Anyway, enjoy!</p>
<h3>CRYPTMOUNT – mounts a truecrypt container and returns to CALLer. On fail, quit</h3>
<pre class="brush: php;">REM
REM     CALL :CRYPTMOUNT "%LEONARDO%" "%LEONARDO_FILE%" "%LEONARDO_KEY%"
REM     CALL :CRYPTMOUNT "L" "%SYSTEMDRIVE%CRYPTLEONARDO" "%SYSTEMDRIVE%CRYPTLEONARDO_KEY"
REM
REM :: print the settings
REM :: CALL :MP 3 "DRIVE: %DRIVE%"&#038;&#038;CALL :MP 3 " FILE: %FILE%"&#038;&#038;CALL :MP 3 "  KEY: %KEY%"&#038;&#038;CALL :MP 3 "  VOL: %VOL%"</pre>
<pre class="brush: php;">:CRYPTMOUNT
SET DRIVE=%~1&#038;&#038; SET FILE=%~2&#038;&#038; SET KEY=%~3&#038;&#038; SET VOL=!FILE:~0,3!
CALL :MP 1 "Mounting TrueCrypt on %DRIVE% from %FILE%"
 
:: Check for Truecrypt or die
CALL :EXISTORQUIT "%ProgramFiles%TrueCryptTrueCrypt.exe" &#038;&#038; CALL :EXISTORQUIT "%FILE%" &#038;&#038; CALL :EXISTORQUIT "%KEY%"
 
:: checks that MOUNTVOL works and the drive containing the truecrypt container file is present or dies
MOUNTVOL %VOL% /L 2>NUL | FIND "\?Volume" >NUL 2>&#038;1
IF ERRORLEVEL 1 CALL :MDYE "%VOL% NOT FOUND"
 
REM ** Converts G: to its \?Volume234234 equivalent for greater portability
FOR /F %%i IN (&#39;MOUNTVOL %VOL% /L&#39;) DO @SET VOL=%%i
 
:: IF the drive is already mounted then continue, otherwise try to mount
MOUNTVOL %DRIVEDRIVE% ALREADY MOUNTED" &#038;&#038; EXIT /B
) ELSE (
  START "Mounting TrueCrypt" /D"%ProgramFiles%TrueCrypt" /MIN /B TrueCrypt.exe /c n /b /q background /h n /k %KEY% /l %DRIVE% /p /v %VOL% &#038;&#038; SLEEP 10
)
 
:: try again in case of bad password and accidental keypress
MOUNTVOL %DRIVEProgramFiles%TrueCrypt" /MIN /B TrueCrypt.exe /c n /b /q background /h n /k %KEY% /l %DRIVE% /p /v %VOL% &#038;&#038; SLEEP 10)
 
:: IF it still doesnt exist then quit
MOUNTVOL %DRIVEFILE% on %DRIVE%"
 
CALL :MF &#038;&#038; ENDLOCAL &#038;&#038; EXIT /B
EXIT /B</pre>
<h3>RUNONE – Starts one instance of executable after verifying it exists and is not already running.</h3>
<pre class="brush: php;">REM     %~1 is location of executatable
REM     %~2 is optional (unless %~3 is used) START parameters
REM     %~3 is optional parameters for executable
REM
REM     CALL :RUNONE "L:PLPLightscreenPortable.exe" "/MAX" "/HIDE"</pre>
<pre class="brush: php;">:RUNONE
SETLOCAL
CALL :MP 1 "Starting %~n1"
 
:: SLEEP FOR NICENESS, LOCAL VARS _P2 and _P3
SLEEP 2 &#038;&#038; SETLOCAL
 
SET P=%~1
ECHO %P%|FIND " " >NUL 2>&#038;1
IF NOT ERRORLEVEL 1 ( PUSHD "%~dp1" &#038;&#038; SET P=%~nx1 )
 
:: SET _P2 TO DEFAULT TO "/MIN" IF EMPTY
SET _P2=/MIN
IF NOT " %~2" == " " SET _P2=%~2
IF NOT " %~3" == " " SET _P3=%~3
IF NOT " %~4" == " " SET _P4=%~4
 
:: CHECK THAT EXECUTABLE EXISTS
CALL :EXISTORQUIT "%~1"
 
REM ECHO START %_P2% /D"%~dp1" %P% %_P3% %_P4%&#038;&#038; PAUSE&#038;&#038;
:: CHECK FOR EXISTING PROCESSNAME ( %~n1 is file name without ext, %~nx1 is the file name and extension. )
pslist.exe /e %~n1 >NUL 2>&#038;1
IF ERRORLEVEL 1 (START %_P2% /D"%~dp1" %P% %_P3% %_P4% ) ELSE (CALL :MP 2 "%~n1 already running!" )
 
ENDLOCAL &#038;&#038; EXIT /B</pre>
<h3>ADMINRUNONE – Runs %1 with admin rights IF neccessary</h3>
<pre class="brush: php;">:ADMINRUNONE
CALL :MP 3 "Exec %~1 as %ADMINUSER%"
 
:: Check that file exists
CALL :EXISTORQUIT "%~1"
 
:: test for rights to the task scheduler
:: %SYSTEMDRIVE%WINDOWSsystem32cmd.exe /E:ON /D /Q /T:0C /C START /WAIT /MIN /B %SYSTEMDRIVE%WINDOWSsystem32cmd.exe /E:ON /D /Q /T:0C /C %~1
AT >NUL 2>&#038;1
IF ERRORLEVEL 1 (
  RUNAS /noprofile /user:%USERDOMAIN%%ADMINUSER% "%~1"
) ELSE (
  %COMSPEC% /E:ON /D /Q /T:0C /C "%~1"
)
SLEEP 2 &#038;&#038; CALL :MF &#038;&#038; EXIT /B</pre>
<h3>CHECKUSERVALID – checks that defined username equals %ADMINUSER% or %RUNUSER%, then returns to CALLer</h3>
<pre class="brush: php;">:CHECKUSERVALID
:: EXIT IF USERNAME IS NOT DEFINED, CATCHES SYSTEM ACCOUNTS TRYING TO RUN WHEN IN GLOBAL STARTUP
IF NOT DEFINED USERNAME EXIT
 
SETLOCAL
SET UP=no
SET _P1= %~1
SET _P2= %~2
IF NOT "%_P1%" == " " ( IF /I "%~1" == "%USERNAME%" SET UP=yes)
IF NOT "%_P1%" == " " ( IF /I "%~1" == "%USERNAME%" SET UP=yes)
IF NOT "%_P1%" == " " ( IF /I "%~1" == "%USERNAME%" SET UP=yes)
IF /I "bill" == "%USERNAME%" SET UP=yes
IF /I "newbill" == "%USERNAME%" SET UP=yes
IF /I "max" == "%USERNAME%" SET UP=yes
IF /I NOT "%UP%" == "yes" EXIT
ENDLOCAL
EXIT /B</pre>
<h3>SETPROMPT – sets prompt, then returns to CALLer</h3>
<pre class="brush: php;">REM =   user@MACHINE C:DRPEPPERSCRIPTS
REM =   > REG /?</pre>
<pre class="brush: php;">:SETPROMPT
set PROMPT=$_%USERNAME%@%USERDOMAIN%$S$P$_$M$G &#038;&#038; EXIT /B</pre>
<h3>BEEP – beeps once, then returns to CALLer</h3>
<p>The character after the echo is the actual BEL char, so unless you have my source file, you will need to copy a literal BEL char here to make it beep.</p>
<pre class="brush: php;">:BEEP
@ECHO # &#038;&#038; EXIT /B</pre>
<h3>MSETCOLOR – SET colors for screen, then returns to CALLer</h3>
<pre class="brush: php;">REM
REM     0 = Black       8 = Gray
REM     1 = Blue        9 = Light Blue
REM     2 = Green       A = Light Green
REM     3 = Aqua        B = Light Aqua
REM     4 = Red         C = Light Red
REM     5 = Purple      D = Light Purple
REM     6 = Yellow      E = Light Yellow
REM     7 = White       F = Bright White
REM</pre>
<pre class="brush: php;">:MSETCOLOR
COLOR %~1 &#038;&#038; EXIT /B</pre>
<h3>MSETCONSOLE – sets the cols and lines of current screen buffer, then returns to CALLer</h3>
<pre class="brush: php;">:MSETCONSOLE
MODE CON COLS=%~1 LINES=%~2 &#038;&#038; EXIT /B</pre>
<h3>PARAMTEST – tests params, then returns to CALLer</h3>
<pre class="brush: php;"> <img src='http://www.taiwangeek.com/wp-includes/images/smilies/icon_razz.gif' alt=':P' class='wp-smiley' /> ARAMTEST
ECHO. &#038;&#038; CALL :MP 1 "PARAMTEST CALLED WITH: %*" &#038;&#038; ECHO %L1%
SET _P= %~1
IF NOT "%_P%" == " " ( ECHO %%1          = %1 &#038;&#038; ECHO %%~f1        = %~f1 &#038;&#038; ECHO %%~d1        = %~d1 &#038;&#038; ECHO %%~p1        = %~p1
  ECHO %%~n1        = %~n1 &#038;&#038; ECHO %%~x1        = %~x1 &#038;&#038; ECHO %%~s1        = %~s1 &#038;&#038; ECHO %%~dp1       = %~dp1
  ECHO %%~nx1       = %~nx1 &#038;&#038; ECHO %%~$PATH:1   = %~$PATH:1 &#038;&#038; ECHO %%~dp$PATH:1 = %~dp$PATH:1 &#038;&#038; ECHO %L1% )
SET _P= %~2
IF NOT "%_P%" == " " ( ECHO %%2          = %2 &#038;&#038; ECHO %%~f2        = %~f2 &#038;&#038; ECHO %%~d2        = %~d2 &#038;&#038; ECHO %%~p2        = %~p2
  ECHO %%~n2        = %~n2 &#038;&#038; ECHO %%~x2        = %~x2 &#038;&#038; ECHO %%~s2        = %~s2 &#038;&#038; ECHO %%~dp2       = %~dp2
  ECHO %%~nx2       = %~nx2 &#038;&#038; ECHO %%~$PATH:2   = %~$PATH:2 &#038;&#038; ECHO %%~dp$PATH:2 = %~dp$PATH:2 &#038;&#038; ECHO %L1% )
SET _P= %~3
IF NOT "%_P%" == " " ( ECHO %%3          = %3 &#038;&#038; ECHO %%~f3        = %~f3 &#038;&#038; ECHO %%~d3        = %~d3 &#038;&#038; ECHO %%~p3        = %~p3
  ECHO %%~n3        = %~n3 &#038;&#038; ECHO %%~x3        = %~x3 &#038;&#038; ECHO %%~s3        = %~s3 &#038;&#038; ECHO %%~dp3       = %~dp3
  ECHO %%~nx3       = %~nx3 &#038;&#038; ECHO %%~$PATH:3   = %~$PATH:3 &#038;&#038; ECHO %%~dp$PATH:3 = %~dp$PATH:3 &#038;&#038; ECHO %L1% )
SET _P= %~4
IF NOT "%_P%" == " " ( ECHO %%4          = %4 &#038;&#038; ECHO %%~f4        = %~f4 &#038;&#038; ECHO %%~d4        = %~d4 &#038;&#038; ECHO %%~p4        = %~p4
  ECHO %%~n4        = %~n4 &#038;&#038; ECHO %%~x4        = %~x4 &#038;&#038; ECHO %%~s4        = %~s4 &#038;&#038; ECHO %%~dp4       = %~dp4
  ECHO %%~nx4       = %~nx4 &#038;&#038; ECHO %%~$PATH:4   = %~$PATH:4 &#038;&#038; ECHO %%~dp$PATH:4 = %~dp$PATH:4 &#038;&#038; ECHO %L1% )
SET _P= %~5
IF NOT "%_P%" == " " ( ECHO %%5          = %5 &#038;&#038; ECHO %%~f5        = %~f5 &#038;&#038; ECHO %%~d5        = %~d5 &#038;&#038; ECHO %%~p5        = %~p5
  ECHO %%~n5        = %~n5 &#038;&#038; ECHO %%~x5        = %~x5 &#038;&#038; ECHO %%~s5        = %~s5 &#038;&#038; ECHO %%~dp5       = %~dp5
  ECHO %%~nx5       = %~nx5 &#038;&#038; ECHO %%~$PATH:5   = %~$PATH:5 &#038;&#038; ECHO %%~dp$PATH:5 = %~dp$PATH:5 &#038;&#038; ECHO %L1% )
SET _P= %~6
IF NOT "%_P%" == " " ( ECHO %%6          = %6 &#038;&#038; ECHO %%~f6        = %~f6 &#038;&#038; ECHO %%~d6        = %~d6 &#038;&#038; ECHO %%~p6        = %~p6
  ECHO %%~n6        = %~n6 &#038;&#038; ECHO %%~x6        = %~x6 &#038;&#038; ECHO %%~s6        = %~s6 &#038;&#038; ECHO %%~dp6       = %~dp6
  ECHO %%~nx6       = %~nx6 &#038;&#038; ECHO %%~$PATH:6   = %~$PATH:6 &#038;&#038; ECHO %%~dp$PATH:6 = %~dp$PATH:6 &#038;&#038; ECHO %L1% )
SET _P= %~7
IF NOT "%_P%" == " " ( ECHO %%7          = %7 &#038;&#038; ECHO %%~f7        = %~f7 &#038;&#038; ECHO %%~d7        = %~d7 &#038;&#038; ECHO %%~p7        = %~p7
  ECHO %%~n7        = %~n7 &#038;&#038; ECHO %%~x7        = %~x7 &#038;&#038; ECHO %%~s7        = %~s7 &#038;&#038; ECHO %%~dp7       = %~dp7
  ECHO %%~nx7       = %~nx7 &#038;&#038; ECHO %%~$PATH:7   = %~$PATH:7 &#038;&#038; ECHO %%~dp$PATH:7 = %~dp$PATH:7 &#038;&#038; ECHO %L1% )
SLEEP 3
CALL :MF
EXIT /B</pre>
<h3>PARAMTESTHELP – show params help, then returns to CALLer</h3>
<pre class="brush: php;"> <img src='http://www.taiwangeek.com/wp-includes/images/smilies/icon_razz.gif' alt=':P' class='wp-smiley' /> ARAMTESTHELP
ECHO %%~1 Expands %%1 and removes any surrounding quotation marks
ECHO %%~f1 Expands %%1 to a fully qualified path name.
ECHO %%~d1 Expands %%1 to a drive letter.
ECHO %%~p1 Expands %%1 to a path.
ECHO %%~n1 Expands %%1 to a file name.
ECHO %%~x1 Expands %%1 to a file extension.
ECHO %%~s1 Expanded path contains short names only.
ECHO %%~a1 Expands %%1 to file attributes.
ECHO %%~t1 Expands %%1 to date and time of file.
ECHO %%~z1 Expands %%1 to size of file.
ECHO %%~dp1 Expands %%1 to a drive letter and path.
ECHO %%~nx1 Expands %%1 to a file name and extension.
ECHO %%~ftza1 Expands %%1 to a dir-like output line.
ECHO %%~$PATH:1 Searches the dirs in PATH expanding %%1 to fully qualified name of first found. If var name isn't defined or the files not found, expands to empty string.
ECHO %%~dp$PATH:1 Searches the directories listed in the PATH environment variable for %%1 and expands to the drive letter and path of the first one found.
CALL :MF
EXIT /B</pre>
<h3>EXAMINEFILE – FINDs useful strings in file, then returns to CALLer</h3>
<pre class="brush: php;">:EXAMINEFILE
CALL :MP 1 "Examine File %~1"
CALL :EXISTORQUIT "%~1"
STRINGS "%~1" | FINDSTR /R /C:"A-ZA-Z="
CALL :MF
EXIT /B</pre>
<h3>ADMINSHELL – sets prompt, then returns to CALLer</h3>
<pre class="brush: php;">:ADMINSHELL
CALL :MP 1 "Creating Admin Shell"
CALL :EXISTORQUIT "%SYSTEMROOT%system32runas.exe"
START %SYSTEMROOT%system32runas.exe /profile /savecred /user:%ADMINUSER% "%COMSPEC% /T:0C /E:ON /F:ON /K cmd.exe /K cd C:CRYPTBIN"
CALL :MF
EXIT /B</pre>
<h3>EXISTORQUIT – checks %~1 exists, IF it does returns to CALLer, otherwise, quit</h3>
<pre class="brush: php;">:EXISTORQUIT
:: CALL :MP 1 "Checking for %~1"
IF NOT EXIST "%~1" CALL :MDYE "%~1 NOT FOUND"
EXIT /B</pre>
<h3>RR – IF file %1 EXISTs then :MT “Removing %1″ then :MF, then ( or IF %1 not EXISTs)  returns to CALLer</h3>
<pre class="brush: php;">:RR
CALL :MP 1 "Removing %~1"
IF EXIST "%~1" ERASE /q "%~1"
CALL :MF &#038;&#038; EXIT /B</pre>
<h3>LOCKDOWN  – locks workstation, then returns to CALLer (pointless)</h3>
<pre class="brush: php;">:LOCKDOWN
RUNDLL32 USER32.DLL,LockWorkStation &#038;&#038; EXIT /B</pre>
<h3>SHUTDOWNIN – initiates shutdown, then returns to CALLer (pointless)</h3>
<pre class="brush: php;">REM shutdown /a aborts</pre>
<pre class="brush: php;">:SHUTDOWNIN
SHUTDOWN -r -t "%~1" &#038;&#038; EXIT /B</pre>
<h3>LISTSERVICES – lists services, then returns to CALLer</h3>
<pre class="brush: php;">:LISTSERVICES
SC query state= all type= all | FOR /F "tokens=2" %%i IN ('FIND /I "SERVICE_NAME"') DO @ECHO %%i
SC query | FOR /F "tokens=2" %%i IN ('FIND /I "SERVICE_NAME"') DO @ECHO %%i
EXIT /B</pre>
<h3>TASKS – Advanced Tasklisting</h3>
<pre class="brush: php;">:TASKS
SET _P=%~1
SET _PP= %~1
IF "%_PP%" == " " EXIT /B
 
REM SORTABLES
IF /I "%_P%" == "pid" ( tasklist.exe /V /NH | SORT /+29 &#038;&#038; EXIT /B )
IF /I "%_P%" == "size" ( tasklist.exe /V /NH | SORT /+59 &#038;&#038; EXIT /B )
IF /I "%_P%" == "user" ( tasklist.exe /V /NH | SORT /+89 &#038;&#038; EXIT /B )
IF /I "%_P%" == "time" ( tasklist.exe /V /NH | SORT /+138 &#038;&#038; EXIT /B )
IF /I "%_P%" == "window" ( tasklist.exe /V /NH | SORT /+152 &#038;&#038; EXIT /B )
 
REM FILTERS
IF /I "%_P%" == "image" ( tasklist.exe /V /NH /FI "IMAGENAME eq %~2" &#038;&#038; EXIT /B )
IF /I "%_P%" == "username" ( tasklist.exe /V /NH /FI "USERNAME eq %~2" &#038;&#038; EXIT /B )
IF /I "%_P%" == "running" ( tasklist.exe /V /NH /FI "STATUS eq Running" &#038;&#038; EXIT /B )
IF /I "%_P%" == "status" ( tasklist.exe /V /NH /FI "STATUS eq %~2" &#038;&#038; EXIT /B )
CALL :MF
EXIT /B</pre>
<h3>SPEAK – Speak text</h3>
<pre class="brush: php;">:SPEAK
REM ECHO "%~1"
nircmd.exe speak text "%~1" 5 60 &#038;&#038; EXIT /B</pre>
<h3>MF – SLEEPs for 1 second, then prints out completed message, followed by 2 blank lines, then returns to CALLer</h3>
<pre class="brush: php;">:MF
SLEEP 1 &#038;&#038; ECHO  COMPLETED &#038;&#038; ECHO. &#038;&#038; ECHO. &#038;&#038; EXIT /B</pre>
<h3>MM – prints blank line, L1, changes title of the interpreter window to %~1, prints >>> %~1…, L2, blank line, then returns to CALLer</h3>
<pre class="brush: php;">:MM
SLEEP 1 &#038;&#038; ECHO. &#038;&#038; ECHO %L1% &#038;&#038; title +++ %~1... &#038;&#038; ECHO %P1% %~1... &#038;&#038; ECHO %L2% &#038;&#038; ECHO. &#038;&#038; EXIT /B</pre>
<h3>MT – prints blank line, L1, changes title of the interpreter window to %~1, prints >>> %~1…, L2, blank line, then returns to CALLer</h3>
<pre class="brush: php;">:MT
CALL :MM "%~1" &#038;&#038; CALL :SPEAK "%~1" &#038;&#038; EXIT /B</pre>
<h3>MP – Print Output, then returns to CALLer</h3>
<pre class="brush: php;">:MP
IF "%~1" == "1" ECHO %P1% %~2 &#038;&#038; EXIT /B
IF "%~1" == "2" ECHO %P2% %~2 &#038;&#038; ECHO. &#038;&#038; EXIT /B
IF "%~1" == "3" ECHO %P3% %~2 &#038;&#038; EXIT /B
EXIT /B</pre>
<h3>MP3 – ECHO %~1, speak %~1 with nircmd.exe, then returns to CALLer</h3>
<pre class="brush: php;">:MP3
CALL :MP 1 "%~1" &#038;&#038; CALL :SPEAK "%~1" &#038;&#038; EXIT /B</pre>
<h3>MDYE – exit script with message %~1, then returns to CALLer</h3>
<pre class="brush: php;">:MDYE
SETLOCAL
SET _M= %~1
IF NOT "%_M%" == " " SET _M=REASON: %~1
CALL :MP 1 "EXITING SCRIPT...  %_M%" &#038;&#038; ECHO. &#038;&#038; ECHO.
ENDLOCAL &#038;&#038; EXIT /B</pre>
<h3>MKILL – exit cmd processor with message %~1</h3>
<pre class="brush: php;">:MKILL
SETLOCAL
SET _M= %~1
IF NOT "%_M%" == " " SET _M=REASON: %~1
ECHO. &#038;&#038; ECHO. &#038;&#038; CALL :MP 1 "EXITING CMD WINDOW IN 3 SECONDS...  %_M%" &#038;&#038; ECHO. &#038;&#038; ECHO. &#038;&#038; SLEEP 3
ENDLOCAL &#038;&#038; EXIT &#038;&#038; EXIT &#038;&#038; EXIT</pre>
<h2>EOF: Thoughts</h2>
<p>So what did you think?  I have around 20 batch scripts that utilize these and other functions to do all sorts of cool things.  One takes a screenshot of my desktop every 10 minutes and saves it for a real-cool archive of my activity.  Another lets me edit a boot.ini file with 1 command.. And another runs when I insert a USB drive to automatically mount a truecrypt volume and create SSH tunnels in the background by using Plink, AT, and the runas.exe command.</p>
<p>If you want to program, please use linux…  If you need to write a Windows batch file, I hope this helps.</p>
<p>Technorati Tags: <a  href="http://technorati.com/tag/.bat" rel="tag">.bat</a>, <a  href="http://technorati.com/tag/Advanced" rel="tag">Advanced</a>, <a  href="http://technorati.com/tag/batch+file" rel="tag">batch file</a>, <a  href="http://technorati.com/tag/cli" rel="tag">cli</a>, <a  href="http://technorati.com/tag/cmd.exe" rel="tag">cmd.exe</a>, <a  href="http://technorati.com/tag/Notepad" rel="tag">Notepad</a>, <a  href="http://technorati.com/tag/programming" rel="tag">programming</a>, <a  href="http://technorati.com/tag/scripting" rel="tag">scripting</a>, <a  href="http://technorati.com/tag/SSH+Tunnels" rel="tag">SSH Tunnels</a>, <a  href="http://technorati.com/tag/Windows" rel="tag">Windows</a></p>
<hr />
<p><small>© AskApache for <a  href="http://www.askapache.com">AskApache</a>, 2010. |<br />
<a  href="http://www.askapache.com/windows/advanced-batch-scripting.html">Permalink</a> |<br />
<a  href="http://www.askapache.com/windows/advanced-batch-scripting.html#comments">No comment</a> |<br />
Add to<br />
<a  href="http://del.icio.us/post?url=http://www.askapache.com/windows/advanced-batch-scripting.html&#038;title=Advanced%20Windows%20Batch%20File%20Scripting">del.icio.us</a><br />
<br />
Post tags: <a  href="http://www.askapache.com/t/bat/" rel="tag">.bat</a>, <a  href="http://www.askapache.com/t/advanced/" rel="tag">Advanced</a>, <a  href="http://www.askapache.com/t/batch-file/" rel="tag">batch file</a>, <a  href="http://www.askapache.com/t/cli/" rel="tag">cli</a>, <a  href="http://www.askapache.com/t/cmd-exe/" rel="tag">cmd.exe</a>, <a  href="http://www.askapache.com/t/notepad/" rel="tag">Notepad</a>, <a  href="http://www.askapache.com/t/programming/" rel="tag">programming</a>, <a  href="http://www.askapache.com/t/scripting/" rel="tag">scripting</a>, <a  href="http://www.askapache.com/t/ssh-tunnels/" rel="tag">SSH Tunnels</a>, <a  href="http://www.askapache.com/t/windows-2/" rel="tag">Windows</a><br />
</small></p>
<p><a  href="http://www.askapache.com/windows/advanced-batch-scripting.html"></a><a href="http://www.askapache.com/windows/advanced-batch-scripting.html">Advanced Windows Batch File Scripting</a> originally appeared on <cite>AskApache.com</cite> </p>
<p><!--/content--></p>
]]></content:encoded>
			<wfw:commentRss>http://www.taiwangeek.com/2010-09/advanced-windows-batch-file-scripting.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>FreeBSD 上使用 wkhtmltopdf 做網頁擷取</title>
		<link>http://www.taiwangeek.com/2010-09/freebsd-%e4%b8%8a%e4%bd%bf%e7%94%a8-wkhtmltopdf-%e5%81%9a%e7%b6%b2%e9%a0%81%e6%93%b7%e5%8f%96.html</link>
		<comments>http://www.taiwangeek.com/2010-09/freebsd-%e4%b8%8a%e4%bd%bf%e7%94%a8-wkhtmltopdf-%e5%81%9a%e7%b6%b2%e9%a0%81%e6%93%b7%e5%8f%96.html#comments</comments>
		<pubDate>Sun, 05 Sep 2010 22:56:15 +0000</pubDate>
		<dc:creator>tung</dc:creator>
				<category><![CDATA[Google Reader]]></category>
		<category><![CDATA[checksum]]></category>
		<category><![CDATA[depends-on-file]]></category>
		<category><![CDATA[generated]]></category>
		<category><![CDATA[global]]></category>
		<category><![CDATA[global-options]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[new-cache]]></category>
		<category><![CDATA[outline]]></category>
		<category><![CDATA[output]]></category>
		<category><![CDATA[PDF]]></category>
		<category><![CDATA[portrait]]></category>
		<category><![CDATA[running]]></category>
		<category><![CDATA[security]]></category>
		<category><![CDATA[windows]]></category>

		<guid isPermaLink="false">http://www.taiwangeek.com/2010-09/freebsd-%e4%b8%8a%e4%bd%bf%e7%94%a8-wkhtmltopdf-%e5%81%9a%e7%b6%b2%e9%a0%81%e6%93%b7%e5%8f%96.html</guid>
		<description><![CDATA[ Shared by &#23567;&#33891; 天阿 育典哥們 你看了也可以瞑目了 阿門~ 以往要用程式控制將網頁輸出pdf或擷取網頁,都是件浩大工程. 這次介紹如何在FreeBSD 命令列模式下即可輕易辦到,並且不需龐大的X Windows 圖形系統適合在server上跑. 以下是軟體原文介紹]]></description>
			<content:encoded><![CDATA[<blockquote>
<p><img src="http://www.taiwangeek.com/wp-content/uploads/2010/09/e9259af068test.jpg-89x150.jpg" /></p>
<p>The rest is here:<br />
<a  target="_blank" href="http://blog.sd.idv.tw/archives/286" title="FreeBSD 上使用 wkhtmltopdf 做網頁擷取">FreeBSD 上使用 wkhtmltopdf 做網頁擷取</a>
</p></blockquote>
<p><!--/content--></p>
<blockquote><p>Shared by  &#23567;&#33891;<br />
<br />
天阿 育典哥們 你看了也可以瞑目了 阿門~</p></blockquote>
<p>以往要用程式控制將網頁輸出pdf或擷取網頁,都是件浩大工程.<br />
這次介紹如何在FreeBSD 命令列模式下即可輕易辦到,並且不需龐大的X Windows 圖形系統適合在server上跑.</p>
<p>以下是軟體原文介紹.</p>
<h2><a  href="http://code.google.com/p/wkhtmltopdf/">wkhtmltopdf</a></h2>
<p>Convert html to pdf using webkit (qtwebkit)</p>
<h2><a name="Description">Description</a></h2>
<p>Simple shell utility to convert html to pdf using the webkit rendering engine, and qt.</p>
<h2><a name="Introduction">Introduction</a></h2>
<p>Searching  the web,  I have found several command line tools that allow you to  convert a HTML-document to a PDF-document, however they all seem to use  their own, and rather incomplete rendering engine,  resulting in poor  quality. Recently QT 4.4 was released with a WebKit widget (WebKit is  the engine of Apples Safari, which is a fork of the KDE KHtml), and  making a good tool became very easy.<br />
此軟體使用WebKit開發完成,除了flash以外其他接可正常顯示！！（包含js）<br />
在安裝前請先確定你的FreeBSD已安裝 linux-base 套件並正常使用,並且將port tree更新.<br />
<span></span><br />
1.安裝linux-expat</p>
<pre class="brush: php;"># cd /usr/ports/textproc/linux-f10-expat;make install clean;
===>  License check disabled, port has not defined LICENSE
=> expat-2.0.1-5.i386.rpm doesn&#39;t seem to exist in /usr/ports/distfiles/rpm/i386/fedora/10.
=> Attempting to fetch from http://ftp.tw.freebsd.org/pub/FreeBSD/distfiles/rpm/i386/fedora/10/.
expat-2.0.1-5.i386.rpm                        100% of   82 kB  244 kBps
===>  Extracting for linux-f10-expat-2.0.1
=> MD5 Checksum OK for rpm/i386/fedora/10/expat-2.0.1-5.i386.rpm.
=> SHA256 Checksum OK for rpm/i386/fedora/10/expat-2.0.1-5.i386.rpm.
===>   linux-f10-expat-2.0.1 depends on file: /usr/local/bin/rpm2cpio - found
===>  Patching for linux-f10-expat-2.0.1
===>  Configuring for linux-f10-expat-2.0.1
===>  Installing for linux-f10-expat-2.0.1
===>   linux-f10-expat-2.0.1 depends on file: /compat/linux/etc/fedora-release - found
===>   Generating temporary packing list
===>  Checking if textproc/linux-f10-expat already installed
cd /usr/ports/textproc/linux-f10-expat/work &#038;&#038; /usr/bin/find * -type d -exec /bin/mkdir -p "/compat/linux/{}" ;
cd /usr/ports/textproc/linux-f10-expat/work &#038;&#038; /usr/bin/find * ! -type d | /usr/bin/cpio -pm -R root:wheel /compat/linux
367 blocks
===>   Running linux ldconfig
/compat/linux/sbin/ldconfig -r /compat/linux
===>   Registering installation for linux-f10-expat-2.0.1
===>  Cleaning for linux-f10-expat-2.0.1
</pre>
<p>2.安裝linux-fontconfig</p>
<pre class="brush: php;"># cd /usr/ports/x11-fonts/linux-f10-fontconfig; make install clean;
===>  License check disabled, port has not defined LICENSE
=> fontconfig-2.6.0-3.fc10.i386.rpm doesn&#39;t seem to exist in /usr/ports/distfiles/rpm/i386/fedora/10.
=> Attempting to fetch from http://ftp.tw.freebsd.org/pub/FreeBSD/distfiles/rpm/i386/fedora/10/.
fontconfig-2.6.0-3.fc10.i386.rpm              100% of  182 kB  241 kBps
===>  Extracting for linux-f10-fontconfig-2.6.0
=> MD5 Checksum OK for rpm/i386/fedora/10/fontconfig-2.6.0-3.fc10.i386.rpm.
=> SHA256 Checksum OK for rpm/i386/fedora/10/fontconfig-2.6.0-3.fc10.i386.rpm.
===>   linux-f10-fontconfig-2.6.0 depends on file: /usr/local/bin/rpm2cpio - found
===>  Patching for linux-f10-fontconfig-2.6.0
===>  Configuring for linux-f10-fontconfig-2.6.0
===>  Installing for linux-f10-fontconfig-2.6.0
===>   linux-f10-fontconfig-2.6.0 depends on file: /compat/linux/etc/fedora-release - found
===>   linux-f10-fontconfig-2.6.0 depends on file: /compat/linux/lib/libexpat.so.1 - found
===>   Generating temporary packing list
===>  Checking if x11-fonts/linux-f10-fontconfig already installed
cd /usr/ports/x11-fonts/linux-f10-fontconfig/work &#038;&#038; /usr/bin/find * -type d -exec /bin/mkdir -p "/compat/linux/{}" ;
cd /usr/ports/x11-fonts/linux-f10-fontconfig/work &#038;&#038; /usr/bin/find * ! -type d | /usr/bin/cpio -pm -R root:wheel /compat/linux
617 blocks
===>   Running linux ldconfig
/compat/linux/sbin/ldconfig -r /compat/linux
===>   Registering installation for linux-f10-fontconfig-2.6.0
===>  Cleaning for linux-f10-fontconfig-2.6.0
</pre>
<p>3.安裝 linux-xorg-libs</p>
<pre class="brush: php;"># cd /usr/ports/x11/linux-f10-xorg-libs; make install clean;
===>  Extracting for linux-f10-xorg-libs-7.4_1
=> MD5 Checksum OK for rpm/i386/fedora/10/libICE-1.0.4-4.fc10.i386.rpm.
=> SHA256 Checksum OK for rpm/i386/fedora/10/libICE-1.0.4-4.fc10.i386.rpm.
=> MD5 Checksum OK for rpm/i386/fedora/10/libFS-1.0.1-2.fc10.i386.rpm.
=> SHA256 Checksum OK for rpm/i386/fedora/10/libFS-1.0.1-2.fc10.i386.rpm.
=> MD5 Checksum OK for rpm/i386/fedora/10/libSM-1.1.0-2.fc10.i386.rpm.
=> SHA256 Checksum OK for rpm/i386/fedora/10/libSM-1.1.0-2.fc10.i386.rpm.
=> MD5 Checksum OK for rpm/i386/fedora/10/libX11-1.1.5-4.fc10.i386.rpm.
=> SHA256 Checksum OK for rpm/i386/fedora/10/libX11-1.1.5-4.fc10.i386.rpm.
=> MD5 Checksum OK for rpm/i386/fedora/10/libXScrnSaver-1.1.3-1.fc10.i386.rpm.
=> SHA256 Checksum OK for rpm/i386/fedora/10/libXScrnSaver-1.1.3-1.fc10.i386.rpm.
=> MD5 Checksum OK for rpm/i386/fedora/10/libXTrap-1.0.0-6.fc10.i386.rpm.
=> SHA256 Checksum OK for rpm/i386/fedora/10/libXTrap-1.0.0-6.fc10.i386.rpm.
=> MD5 Checksum OK for rpm/i386/fedora/10/libXau-1.0.4-1.fc10.i386.rpm.
=> SHA256 Checksum OK for rpm/i386/fedora/10/libXau-1.0.4-1.fc10.i386.rpm.
=> MD5 Checksum OK for rpm/i386/fedora/10/libXaw-1.0.4-3.fc10.i386.rpm.
=> SHA256 Checksum OK for rpm/i386/fedora/10/libXaw-1.0.4-3.fc10.i386.rpm.
=> MD5 Checksum OK for rpm/i386/fedora/10/libXcomposite-0.4.0-5.fc10.i386.rpm.
=> SHA256 Checksum OK for rpm/i386/fedora/10/libXcomposite-0.4.0-5.fc10.i386.rpm.
=> MD5 Checksum OK for rpm/i386/fedora/10/libXcursor-1.1.9-3.fc10.i386.rpm.
=> SHA256 Checksum OK for rpm/i386/fedora/10/libXcursor-1.1.9-3.fc10.i386.rpm.
=> MD5 Checksum OK for rpm/i386/fedora/10/libXdamage-1.1.1-4.fc9.i386.rpm.
=> SHA256 Checksum OK for rpm/i386/fedora/10/libXdamage-1.1.1-4.fc9.i386.rpm.
=> MD5 Checksum OK for rpm/i386/fedora/10/libXdmcp-1.0.2-6.fc10.i386.rpm.
=> SHA256 Checksum OK for rpm/i386/fedora/10/libXdmcp-1.0.2-6.fc10.i386.rpm.
=> MD5 Checksum OK for rpm/i386/fedora/10/libXevie-1.0.2-4.fc10.i386.rpm.
=> SHA256 Checksum OK for rpm/i386/fedora/10/libXevie-1.0.2-4.fc10.i386.rpm.
=> MD5 Checksum OK for rpm/i386/fedora/10/libXext-1.0.4-1.fc9.i386.rpm.
=> SHA256 Checksum OK for rpm/i386/fedora/10/libXext-1.0.4-1.fc9.i386.rpm.
=> MD5 Checksum OK for rpm/i386/fedora/10/libXfixes-4.0.3-4.fc10.i386.rpm.
=> SHA256 Checksum OK for rpm/i386/fedora/10/libXfixes-4.0.3-4.fc10.i386.rpm.
=> MD5 Checksum OK for rpm/i386/fedora/10/libXfont-1.3.3-1.fc10.i386.rpm.
=> SHA256 Checksum OK for rpm/i386/fedora/10/libXfont-1.3.3-1.fc10.i386.rpm.
=> MD5 Checksum OK for rpm/i386/fedora/10/libXft-2.1.13-1.fc10.i386.rpm.
=> SHA256 Checksum OK for rpm/i386/fedora/10/libXft-2.1.13-1.fc10.i386.rpm.
=> MD5 Checksum OK for rpm/i386/fedora/10/libXi-1.1.3-4.fc9.i386.rpm.
=> SHA256 Checksum OK for rpm/i386/fedora/10/libXi-1.1.3-4.fc9.i386.rpm.
=> MD5 Checksum OK for rpm/i386/fedora/10/libXinerama-1.0.3-2.fc10.i386.rpm.
=> SHA256 Checksum OK for rpm/i386/fedora/10/libXinerama-1.0.3-2.fc10.i386.rpm.
=> MD5 Checksum OK for rpm/i386/fedora/10/libXmu-1.0.4-1.fc9.i386.rpm.
=> SHA256 Checksum OK for rpm/i386/fedora/10/libXmu-1.0.4-1.fc9.i386.rpm.
=> MD5 Checksum OK for rpm/i386/fedora/10/libXp-1.0.0-11.fc9.i386.rpm.
=> SHA256 Checksum OK for rpm/i386/fedora/10/libXp-1.0.0-11.fc9.i386.rpm.
=> MD5 Checksum OK for rpm/i386/fedora/10/libXpm-3.5.7-4.fc9.i386.rpm.
=> SHA256 Checksum OK for rpm/i386/fedora/10/libXpm-3.5.7-4.fc9.i386.rpm.
=> MD5 Checksum OK for rpm/i386/fedora/10/libXrandr-1.2.3-1.fc10.i386.rpm.
=> SHA256 Checksum OK for rpm/i386/fedora/10/libXrandr-1.2.3-1.fc10.i386.rpm.
=> MD5 Checksum OK for rpm/i386/fedora/10/libXrender-0.9.4-3.fc9.i386.rpm.
=> SHA256 Checksum OK for rpm/i386/fedora/10/libXrender-0.9.4-3.fc9.i386.rpm.
=> MD5 Checksum OK for rpm/i386/fedora/10/libXres-1.0.3-5.fc10.i386.rpm.
=> SHA256 Checksum OK for rpm/i386/fedora/10/libXres-1.0.3-5.fc10.i386.rpm.
=> MD5 Checksum OK for rpm/i386/fedora/10/libXt-1.0.5-1.fc10.i386.rpm.
=> SHA256 Checksum OK for rpm/i386/fedora/10/libXt-1.0.5-1.fc10.i386.rpm.
=> MD5 Checksum OK for rpm/i386/fedora/10/libXtst-1.0.3-3.fc9.i386.rpm.
=> SHA256 Checksum OK for rpm/i386/fedora/10/libXtst-1.0.3-3.fc9.i386.rpm.
=> MD5 Checksum OK for rpm/i386/fedora/10/libXv-1.0.4-1.fc10.i386.rpm.
=> SHA256 Checksum OK for rpm/i386/fedora/10/libXv-1.0.4-1.fc10.i386.rpm.
=> MD5 Checksum OK for rpm/i386/fedora/10/libXvMC-1.0.4-5.fc10.i386.rpm.
=> SHA256 Checksum OK for rpm/i386/fedora/10/libXvMC-1.0.4-5.fc10.i386.rpm.
=> MD5 Checksum OK for rpm/i386/fedora/10/libXxf86dga-1.0.2-3.fc10.i386.rpm.
=> SHA256 Checksum OK for rpm/i386/fedora/10/libXxf86dga-1.0.2-3.fc10.i386.rpm.
=> MD5 Checksum OK for rpm/i386/fedora/10/libXxf86misc-1.0.1-6.fc10.i386.rpm.
=> SHA256 Checksum OK for rpm/i386/fedora/10/libXxf86misc-1.0.1-6.fc10.i386.rpm.
=> MD5 Checksum OK for rpm/i386/fedora/10/libXxf86vm-1.0.2-1.fc10.i386.rpm.
=> SHA256 Checksum OK for rpm/i386/fedora/10/libXxf86vm-1.0.2-1.fc10.i386.rpm.
=> MD5 Checksum OK for rpm/i386/fedora/10/libfontenc-1.0.4-6.fc10.i386.rpm.
=> SHA256 Checksum OK for rpm/i386/fedora/10/libfontenc-1.0.4-6.fc10.i386.rpm.
=> MD5 Checksum OK for rpm/i386/fedora/10/libxcb-1.1.91-5.fc10.i386.rpm.
=> SHA256 Checksum OK for rpm/i386/fedora/10/libxcb-1.1.91-5.fc10.i386.rpm.
=> MD5 Checksum OK for rpm/i386/fedora/10/libxkbfile-1.0.4-5.fc9.i386.rpm.
=> SHA256 Checksum OK for rpm/i386/fedora/10/libxkbfile-1.0.4-5.fc9.i386.rpm.
=> MD5 Checksum OK for rpm/i386/fedora/10/mesa-libGLw-6.5.1-5.fc9.i386.rpm.
=> SHA256 Checksum OK for rpm/i386/fedora/10/mesa-libGLw-6.5.1-5.fc9.i386.rpm.
===>   linux-f10-xorg-libs-7.4_1 depends on file: /usr/local/bin/rpm2cpio - found
===>  Patching for linux-f10-xorg-libs-7.4_1
===>  Configuring for linux-f10-xorg-libs-7.4_1
===>  Installing for linux-f10-xorg-libs-7.4_1
===>   linux-f10-xorg-libs-7.4_1 depends on file: /compat/linux/etc/fedora-release - found
===>   linux-f10-xorg-libs-7.4_1 depends on file: /compat/linux/lib/libexpat.so.1 - found
===>   linux-f10-xorg-libs-7.4_1 depends on file: /compat/linux/usr/lib/libfontconfig.so.1.3.0 - found
===>   Generating temporary packing list
===>  Checking if x11/linux-f10-xorg-libs already installed
cd /usr/ports/x11/linux-f10-xorg-libs/work &#038;&#038; /usr/bin/find * -type d -exec /bin/mkdir -p "/compat/linux/{}" ;
cd /usr/ports/x11/linux-f10-xorg-libs/work &#038;&#038; /usr/bin/find * ! -type d | /usr/bin/cpio -pm -R root:wheel /compat/linux
12139 blocks
===>   Running linux ldconfig
/compat/linux/sbin/ldconfig -r /compat/linux
===>   Registering installation for linux-f10-xorg-libs-7.4_1
===> SECURITY REPORT:
      This port has installed the following files which may act as network
      servers and may therefore pose a remote security risk to the system.
/compat/linux/usr/lib/libICE.so.6.3.0
/compat/linux/usr/lib/libXdmcp.so.6.0.0

      If there are vulnerabilities in these programs there may be a security
      risk to the system. FreeBSD makes no guarantee about the security of
      ports included in the Ports Collection. Please type &#39;make deinstall&#39;
      to deinstall the port if this is a concern.

      For more information, and contact details about the security
      status of this software, see the following webpage:

http://x.org

===>  Cleaning for linux-f10-xorg-libs-7.4_1
</pre>
<p>4.安裝中文字型cwttf</p>
<pre class="brush: php;"># wget http://cle.linux.org.tw/fonts/cwttf/cwttf-v1.0.tar.gz
# cp * /usr/local/lib/X11/fonts/TTF
# fc-cache -f -v
/usr/local/lib/X11/fonts: caching, new cache contents: 0 fonts, 12 dirs
/usr/local/lib/X11/fonts/100dpi: caching, new cache contents: 398 fonts, 0 dirs
/usr/local/lib/X11/fonts/75dpi: caching, new cache contents: 398 fonts, 0 dirs
/usr/local/lib/X11/fonts/OTF: caching, new cache contents: 23 fonts, 0 dirs
/usr/local/lib/X11/fonts/TTF: caching, new cache contents: 31 fonts, 0 dirs
/usr/local/lib/X11/fonts/Type1: caching, new cache contents: 29 fonts, 0 dirs
/usr/local/lib/X11/fonts/bitstream-vera: caching, new cache contents: 10 fonts, 0 dirs
/usr/local/lib/X11/fonts/cyrillic: caching, new cache contents: 0 fonts, 0 dirs
/usr/local/lib/X11/fonts/encodings: caching, new cache contents: 0 fonts, 1 dirs
/usr/local/lib/X11/fonts/encodings/large: caching, new cache contents: 0 fonts, 0 dirs
/usr/local/lib/X11/fonts/lfpfonts-fix: caching, new cache contents: 71 fonts, 0 dirs
/usr/local/lib/X11/fonts/local: caching, new cache contents: 2 fonts, 0 dirs
/usr/local/lib/X11/fonts/misc: caching, new cache contents: 59 fonts, 0 dirs
/usr/local/lib/X11/fonts/util: caching, new cache contents: 0 fonts, 0 dirs
/root/.fonts: skipping, no such directory
/var/db/fontconfig: cleaning cache directory
/root/.fontconfig: not cleaning non-existent cache directory
fc-cache: succeeded
# fc-list :lang=zh-tw
文鼎ＰＬ中楷,AR PL KaitiM Big5:style=Regular
AR PL UMing TW:style=Light
AR PL UMing HK:style=Light
cwTeX 粗黑體,cwTeXHeiBold:style=Medium
AR PL UMing CN:style=Light
文鼎ＰＬ新宋,AR PL New Sung:style=Regular
AR PL UKai TW MBE:style=Book
cwTeX 仿宋體,cwTeXFangSong:style=Medium
cwTeX 明體,cwTeXMing:style=Medium
AR PL UKai CN:style=Book
AR PL UKai HK:style=Book
cwTeX 楷書,cwTeXKai:style=Medium
AR PL UKai TW:style=Book
文鼎ＰＬ細上海宋,AR PL Mingti2L Big5:style=Regular,Reguler
AR PL UMing TW MBE:style=Light
cwTeX 圓體,cwTeXYen:style=Medium
</pre>
<p>5.下載wkhtmltopdf  Linux Static Binary (i368)</p>
<pre class="brush: php;">wget http://wkhtmltopdf.googlecode.com/files/wkhtmltopdf-0.10.0_beta4-static-i386.tar.bz2
--2010-08-03 20:13:15--  http://wkhtmltopdf.googlecode.com/files/wkhtmltopdf-0.10.0_beta4-static-i386.tar.bz2
正在查找主機 wkhtmltopdf.googlecode.com... 64.233.183.82
正在連接 wkhtmltopdf.googlecode.com|64.233.183.82|:80... 連上了。
已送出 HTTP 要求，正在等候回應... 200 OK
長度: 11712708 (11M) application/x-bzip2
Saving to: `wkhtmltopdf-0.10.0_beta4-static-i386.tar.bz2&#39;

100%=================================================================================================================================================================================> 11,712,708  1.08M/s   in 13s

2010-08-03 20:13:29 (881 KB/s) -- 已儲存 ‘wkhtmltopdf-0.10.0_beta4-static-i386.tar.bz2’ 11712708/11712708)
</pre>
<p>6.執行</p>
<pre class="brush: php;"># ./wkhtmltopdf-i386
You need to specify atleast one input file, and exactly one output file
Use - for stdin or stdout

Name:
  wkhtmltopdf 0.10.0 beta4

Synopsis:
  wkhtmltopdf GLOBAL OPTION... OBJECT... 

Document objects:
  wkhtmltopdf is able to put several objecs into the output file, an object is
  either a single webpage, a cover webpage or a table of content.  The objects
  are put into the output document in the order they are specified on the
  commandline, options can be specified on a per object basis or in the global
  options area. Options from the Global Options section can only be placed in
  the global options area

  A page objects puts the content of a singe webpage into the output document.

  (page)? < input url/file name  > PAGE OPTION...
  Options for the page object can be placed in the global options and the page
  options areas. The applicable options can be found in the Page Options and
  Headers And Footer Options sections.

  A cover objects puts the content of a singe webpage into the output document,
  the page does not appear in the table of content, and does not have headers
  and footers.

  cover < input url/file name > PAGE OPTION...
  All options that can be specified for a page object can also be specified for
  a cover.

  A table of content object inserts a table of content into the output document.

  toc TOC OPTION...
  All options that can be specified for a page object can also be specified for
  a toc, further more the options from the TOC Options section can also be
  applied. The table of content is generated via xslt which means that it can be
  styled to look however you want it to look. To get an idear of how to do this
  you can dump the default xslt document by supplying the
  --dump-default-toc-xsl, and the outline it works on by supplying
  --dump-outline, see the Outline Options section.

Description:
  Converts one or more HTML pages into a PDF document, using wkhtmltopdf patched
  qt.

Global Options:
      --collate                       Collate when printing multiple copies
                                      (default)
      --no-collate                    Do not collate when printing multiple
                                      copies
      --copies                Number of copies to print into the pdf
                                      file (default 1)
  -H, --extended-help                 Display more extensive help, detailing
                                      less common command switches
  -g, --grayscale                     PDF will be generated in grayscale
  -h, --help                          Display help
  -l, --lowquality                    Generates lower quality pdf/ps. Useful to
                                      shrink the result document space
  -O, --orientation      Set orientation to Landscape or Portrait
                                      (default Portrait)
  -s, --page-size               Set paper size to: A4, Letter, etc.
                                      (default A4)
  -q, --quiet                         Be less verbose
      --read-args-from-stdin          Read command line arguments from stdin
      --title                   The title of the generated pdf file (The
                                      title of the first document is used if not
                                      specified)
  -V, --version                       Output version information an exit

Contact:
  If you experience bugs or want to request new features please visit
  , if you have any problems
  or comments please feel free to contact me: see
</pre>
<p>example:</p>
<pre class="brush: php;"># ./wkhtmltopdf-i386 http://tw.yahoo.com/ test.pdf
</pre>
<p><a  href="http://www.taiwangeek.com/wp-content/uploads/2010/09/e9259af068test.jpg.jpg" class="thickbox no_icon" rel="gallery-1341" title=""><img src="http://www.taiwangeek.com/wp-content/uploads/2010/09/8a203b94c978x300.jpg.jpg" alt="" title="test" width="178" height="300" /></a><br />
<a  href="http://blog.sd.idv.tw/wp-content/uploads/2010/08/test.pdf">PDF SAMPLE</a></p>
<p><!--/content--></p>
]]></content:encoded>
			<wfw:commentRss>http://www.taiwangeek.com/2010-09/freebsd-%e4%b8%8a%e4%bd%bf%e7%94%a8-wkhtmltopdf-%e5%81%9a%e7%b6%b2%e9%a0%81%e6%93%b7%e5%8f%96.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>[php-editor] USE PHP_Beautifier in Notepad++</title>
		<link>http://www.taiwangeek.com/2010-08/php-editor-use-php_beautifier-in-notepad.html</link>
		<comments>http://www.taiwangeek.com/2010-08/php-editor-use-php_beautifier-in-notepad.html#comments</comments>
		<pubDate>Wed, 18 Aug 2010 08:18:23 +0000</pubDate>
		<dc:creator>tung</dc:creator>
				<category><![CDATA[原創]]></category>
		<category><![CDATA[notepad++]]></category>
		<category><![CDATA[PHP-Beautifier]]></category>

		<guid isPermaLink="false">http://www.taiwangeek.com/?p=1329</guid>
		<description><![CDATA[This is the way to use PHP_Beautifier to formate php in notepad++ and output to clipboard Install PHP_Beautifier via http://pear.php.net/package/PHP_Beautifier Make sure your notepad++ have NPPExec Add Execute like this... <a class="meta-more" href="http://www.taiwangeek.com/2010-08/php-editor-use-php_beautifier-in-notepad.html">Read more <span class="meta-nav">&#187;</span></a>]]></description>
			<content:encoded><![CDATA[<h3>This is the way to use PHP_Beautifier to formate php in notepad++ and output to clipboard</h3>
<ul>
<li>Install PHP_Beautifier via http://pear.php.net/package/PHP_Beautifier</li>
<li>Make sure your notepad++ have NPPExec</li>
<p>Add Execute like this</p>
<pre class="brush:shell">&lt;%php_beautifier path%&gt;\php_beautifier.bat  $(FULL_CURRENT_PATH) | clip</pre>
<p>the formate output will save to clipboard</p>
<li>IF your php file is utf-8 ,edit your php_beautifier.bat like below<br />
ps,<strong>chcp 65001</strong> force output encode utf-8</li>
<pre class="brush:shell">@ECHO OFF
chcp 65001
SET PHP="\xampp\php\php.exe"
SET BEAUTIFY="\xampp\php"\php_beautifier
%PHP% -d output_buffering=1 -f %BEAUTIFY% -- %1 %2 %3 %4 %5 %6 %7 %8 %9
@ECHO ON
</pre>
</ul>
<p>Relate article form web</p>
<ul>
<li>http://weblogs.asp.net/owscott/archive/2006/12/15/clip-saving-command-line-and-powershell-output-directly-to-the-clipboard.aspx</li>
<li>http://jdev.tw/blog/1651/dos-tips-clip-exe</li>
<li>http://php.apsique.com/PHP_Beautifier/PHP_Beautifier/tutorial_PHP_Beautifier.howtouse.commandline.pkg.html</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.taiwangeek.com/2010-08/php-editor-use-php_beautifier-in-notepad.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>9 Useful PHP Functions and Features You Need to Know</title>
		<link>http://www.taiwangeek.com/2010-08/9-useful-php-functions-and-features-you-need-to-know.html</link>
		<comments>http://www.taiwangeek.com/2010-08/9-useful-php-functions-and-features-you-need-to-know.html#comments</comments>
		<pubDate>Wed, 18 Aug 2010 03:03:34 +0000</pubDate>
		<dc:creator>tung</dc:creator>
				<category><![CDATA[Google Reader]]></category>
		<category><![CDATA[Headline]]></category>
		<category><![CDATA[arguments]]></category>
		<category><![CDATA[article]]></category>
		<category><![CDATA[browser]]></category>
		<category><![CDATA[function]]></category>
		<category><![CDATA[generated]]></category>
		<category><![CDATA[languages]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[pre-name]]></category>
		<category><![CDATA[system-time]]></category>
		<category><![CDATA[unique]]></category>

		<guid isPermaLink="false">http://www.taiwangeek.com/2010-08/9-useful-php-functions-and-features-you-need-to-know.html</guid>
		<description><![CDATA[ Shared by &#23567;&#33891; 的確很優~ 1. Functions with Arbitrary Number of Arguments You may already know that PHP allows you to define functions with optional arguments]]></description>
			<content:encoded><![CDATA[<blockquote><p>Read more here:<br />
<a  title="9 Useful PHP Functions and Features You Need to Know" href="http://net.tutsplus.com/tutorials/php/9-useful-php-functions-and-features-you-need-to-know/" target="_blank">9 Useful PHP Functions and Features You Need to Know</a></p></blockquote>
<p><!--/content--></p>
<blockquote><p>Shared by  小董</p>
<p>的確很優~</p></blockquote>
<h2><span>1. </span>Functions with Arbitrary Number of Arguments</h2>
<p>You may already know that PHP allows you to define functions with optional arguments. But there is also a method for allowing completely arbitrary number of function arguments.</p>
<p>First, here is an example with just optional arguments:</p>
<pre class="brush:php" >// function with 2 optional arguments
function foo($arg1 = '', $arg2 = '') 

	echo "arg1: $arg1n";
	echo "arg2: $arg2n";

foo('hello','world');
/* prints:
arg1: hello
arg2: world
*/

foo();
/* prints:
arg1:
arg2:
*/
</pre>
<p>Now, let’s see how we can build a function that accepts any number of arguments. This time we are going to utilize <a  href="http://us2.php.net/manual/en/function.func-get-args.php">func_get_args()</a>:</p>
<pre class="brush:php" >// yes, the argument list can be empty
function foo() 

	// returns an array of all passed arguments
	$args = func_get_args();

	foreach ($args as $k =&gt; $v)
		echo "arg".($k+1).": $vn";

}

foo();
/* prints nothing */

foo('hello');
/* prints
arg1: hello
*/

foo('hello', 'world', 'again');
/* prints
arg1: hello
arg2: world
arg3: again
*/
</pre>
<hr />
<h2><span>2. </span>Using Glob() to Find Files</h2>
<p>Many PHP functions have long and descriptive names. However it may be hard to tell what a function named <a  href="http://us.php.net/manual/en/function.glob.php">glob()</a> does unless you are already familiar with that term from elsewhere.</p>
<p>Think of it like a more capable version of the <a  href="http://php.net/manual/en/function.scandir.php">scandir()</a> function. It can let you search for files by using patterns.</p>
<pre class="brush:php" >// get all php files
$files = glob('*.php');

print_r($files);
/* output looks like:
Array
(
    0 =&gt; phptest.php
    1 =&gt; pi.php
    2 =&gt; post_output.php
    3 =&gt; test.php
)
*/
</pre>
<p>You can fetch multiple file types like this:</p>
<pre class="brush:php" >// get all php files AND txt files
$files = glob('*.php,txt', GLOB_BRACE);

print_r($files);
/* output looks like:
Array
(
    0 =&gt; phptest.php
    1 =&gt; pi.php
    2 =&gt; post_output.php
    3 =&gt; test.php
    4 =&gt; log.txt
    5 =&gt; test.txt
)
*/
</pre>
<p>Note that the files can actually be returned with a path, depending on your query:</p>
<pre class="brush:php" >$files = glob('../images/a*.jpg');

print_r($files);
/* output looks like:
Array
(
    0 =&gt; ../images/apple.jpg
    1 =&gt; ../images/art.jpg
)
*/
</pre>
<p>If you want to get the full path to each file, you can just call the <a  href="http://php.net/manual/en/function.realpath.php">realpath()</a> function on the returned values:</p>
<pre class="brush:php" >$files = glob('../images/a*.jpg');

// applies the function to each array element
$files = array_map('realpath',$files);

print_r($files);
/* output looks like:
Array
(
    0 =&gt; C:wampwwwimagesapple.jpg
    1 =&gt; C:wampwwwimagesart.jpg
)
*/
</pre>
<hr />
<h2><span>3. </span>Memory Usage Information</h2>
<p>By observing the memory usage of your scripts, you may be able optimize your code better.</p>
<p>PHP has a garbage collector and a pretty complex memory manager. The amount of memory being used by your script. can go up and down during the execution of a script. To get the current memory usage, we can use the <a  href="http://us2.php.net/manual/en/function.memory-get-usage.php">memory_get_usage()</a> function, and to get the highest amount of memory used at any point, we can use the <a  href="http://us2.php.net/manual/en/function.memory-get-peak-usage.php">memory_get_peak_usage()</a> function.</p>
<pre class="brush:php" >echo "Initial: ".memory_get_usage()." bytes n";
/* prints
Initial: 361400 bytes
*/

// let's use up some memory
for ($i = 0; $i &lt; 100000; $i++)
	$array []= md5($i);

// let's remove half of the array
for ($i = 0; $i &lt; 100000; $i++)
	unset($array$i);

echo "Final: ".memory_get_usage()." bytes n";
/* prints
Final: 885912 bytes
*/

echo "Peak: ".memory_get_peak_usage()." bytes n";
/* prints
Peak: 13687072 bytes
*/
</pre>
<hr />
<h2><span>4. </span>CPU Usage Information</h2>
<p>For this, we are going to utilize the <a  href="http://us2.php.net/manual/en/function.getrusage.php">getrusage()</a> function. Keep in mind that this is not available on Windows platforms.</p>
<pre class="brush:php" >print_r(getrusage());
/* prints
Array
(
    ru_oublock =&gt; 0
    ru_inblock =&gt; 0
    ru_msgsnd =&gt; 2
    ru_msgrcv =&gt; 3
    ru_maxrss =&gt; 12692
    ru_ixrss =&gt; 764
    ru_idrss =&gt; 3864
    ru_minflt =&gt; 94
    ru_majflt =&gt; 0
    ru_nsignals =&gt; 1
    ru_nvcsw =&gt; 67
    ru_nivcsw =&gt; 4
    ru_nswap =&gt; 0
    ru_utime.tv_usec =&gt; 0
    ru_utime.tv_sec =&gt; 0
    ru_stime.tv_usec =&gt; 6269
    ru_stime.tv_sec =&gt; 0
)

*/
</pre>
<p>That may look a bit cryptic unless you already have a system administration background. Here is the explanation of each value (you don&#8217;t need to memorize these):</p>
<ul>
<li>ru_oublock: block output operations</li>
<li>ru_inblock: block input operations</li>
<li>ru_msgsnd: messages sent</li>
<li>ru_msgrcv: messages received</li>
<li>ru_maxrss: maximum resident set size</li>
<li>ru_ixrss: integral shared memory size</li>
<li>ru_idrss: integral unshared data size</li>
<li>ru_minflt: page reclaims</li>
<li>ru_majflt: page faults</li>
<li>ru_nsignals: signals received</li>
<li>ru_nvcsw: voluntary context switches</li>
<li>ru_nivcsw: involuntary context switches</li>
<li>ru_nswap: swaps</li>
<li>ru_utime.tv_usec: user time used (microseconds)</li>
<li>ru_utime.tv_sec: user time used (seconds)</li>
<li>ru_stime.tv_usec: system time used (microseconds)</li>
<li>ru_stime.tv_sec: system time used (seconds)</li>
</ul>
<p>To see how much CPU power the script has consumed, we need to look at the &#8216;user time&#8217; and &#8216;system time&#8217; values. The seconds and microseconds portions are provided separately by default. You can divide the microseconds value by 1 million, and add it to the seconds value, to get the total seconds as a decimal number.</p>
<p>Let&#8217;s see an example:</p>
<pre class="brush:php" >// sleep for 3 seconds (non-busy)
sleep(3);

$data = getrusage();
echo "User time: ".
	($data'ru_utime.tv_sec' +
	$data'ru_utime.tv_usec' / 1000000);
echo "System time: ".
	($data'ru_stime.tv_sec' +
	$data'ru_stime.tv_usec' / 1000000);

/* prints
User time: 0.011552
System time: 0
*/
</pre>
<p>Even though the script took about 3 seconds to run, the CPU usage was very very low. Because during the sleep operation, the script actually does not consume CPU resources. There are many other tasks that may take real time, but may not use CPU time, like waiting for disk operations. So as you see, the CPU usage and the actual length of the runtime are not always the same.</p>
<p>Here is another example:</p>
<pre class="brush:php" >// loop 10 million times (busy)
for($i=0;$i&lt;10000000;$i++) 

$data = getrusage();
echo "User time: ".
	($data'ru_utime.tv_sec' +
	$data'ru_utime.tv_usec' / 1000000);
echo "System time: ".
	($data'ru_stime.tv_sec' +
	$data'ru_stime.tv_usec' / 1000000);

/* prints
User time: 1.424592
System time: 0.004204
*/
</pre>
<p>That took about 1.4 seconds of CPU time, almost all of which was user time, since there were no system calls.</p>
<p>System Time is the amount of time the CPU spends performing system calls for the kernel on the program&#8217;s behalf. Here is an example of that:</p>
<pre class="brush:php" >$start = microtime(true);
// keep calling microtime for about 3 seconds
while(microtime(true) - $start &lt; 3) 

$data = getrusage();
echo "User time: ".
	($data'ru_utime.tv_sec' +
	$data'ru_utime.tv_usec' / 1000000);
echo "System time: ".
	($data'ru_stime.tv_sec' +
	$data'ru_stime.tv_usec' / 1000000);

/* prints
User time: 1.088171
System time: 1.675315
*/
</pre>
<p>Now we have quite a bit of system time usage. This is because the script calls the microtime() function many times, which performs a request through the operating system to fetch the time.</p>
<p>Also you may notice the numbers do not quite add up to 3 seconds. This is because there were probably other processes on the server as well, and the script was not using 100% CPU for the whole duration of the 3 seconds.</p>
<hr />
<h2><span>5. </span>Magic Constants</h2>
<p>PHP provides useful <a  href="http://php.net/manual/en/language.constants.predefined.php">magic constants</a> for fetching the current line number (__LINE__), file path (__FILE__), directory path (__DIR__), function name (__FUNCTION__), class name (__CLASS__), method name (__METHOD__) and namespace (__NAMESPACE__).</p>
<p>We are not going to cover each one of these in this article, but I will show you a few use cases.</p>
<p>When including other scripts, it is a good idea to utilize the __FILE__ constant (or also __DIR__ since PHP 5.3):</p>
<pre class="brush:php" >// this is relative to the loaded script's path
// it may cause problems when running scripts from different directories
require_once('config/database.php');

// this is always relative to this file's path
// no matter where it was included from
require_once(dirname(__FILE__) . '/config/database.php');
</pre>
<p>Using __LINE__ makes debugging easier. You can track down the line numbers:</p>
<pre class="brush:php" >// some code
// ...
my_debug("some debug message", __LINE__);
/* prints
Line 4: some debug message
*/

// some more code
// ...
my_debug("another debug message", __LINE__);
/* prints
Line 11: another debug message
*/

function my_debug($msg, $line)
	echo "Line $line: $msgn";
</pre>
<hr />
<h2><span>6. </span>Generating Unique ID&#8217;s</h2>
<p>There may be situations where you need to generate a unique string. I have seen many people use the md5() function for this, even though it&#8217;s not exactly meant for this purpose:</p>
<pre class="brush:php" >// generate unique string
echo md5(time() . mt_rand(1,1000000));
</pre>
<p>There is actually a PHP function named <a  href="http://us2.php.net/manual/en/function.uniqid.php">uniqid()</a> that is meant to be used for this.</p>
<pre class="brush:php" >// generate unique string
echo uniqid();
/* prints
4bd67c947233e
*/

// generate another unique string
echo uniqid();
/* prints
4bd67c9472340
*/
</pre>
<p>You may notice that even though the strings are unique, they seem similar for the first several characters. This is because the generated string is related to the server time. This actually has a nice side effect, as every new generated id comes later in alphabetical order, so they can be sorted.</p>
<p>To reduce the chances of getting a duplicate, you can pass a prefix, or the second parameter to increase entropy:</p>
<pre class="brush:php" >// with prefix
echo uniqid('foo_');
/* prints
foo_4bd67d6cd8b8f
*/

// with more entropy
echo uniqid('',true);
/* prints
4bd67d6cd8b926.12135106
*/

// both
echo uniqid('bar_',true);
/* prints
bar_4bd67da367b650.43684647
*/
</pre>
<p>This function will generate shorter strings than md5(), which will also save you some space.</p>
<hr />
<h2><span>7. </span>Serialization</h2>
<p>Did you ever need to store a complex variable in a database or a text file? You do not have to come up with a fancy solution to convert your arrays or objects into formatted strings, as PHP already has functions for this purpose.</p>
<p>There are two popular methods of serializing variables. Here is an example that uses the <a  href="http://php.net/manual/en/function.serialize.php">serialize()</a> and <a  href="http://www.php.net/manual/en/function.unserialize.php">unserialize()</a>:</p>
<pre class="brush:php" >// a complex array
$myvar = array(
	'hello',
	42,
	array(1,'two'),
	'apple'
);

// convert to a string
$string = serialize($myvar);

echo $string;
/* prints
a:4:i:0;s:5:"hello";i:1;i:42;i:2;a:2:i:0;i:1;i:1;s:3:"two";i:3;s:5:"apple";}
*/

// you can reproduce the original variable
$newvar = unserialize($string);

print_r($newvar);
/* prints
Array
(
    0 =&gt; hello
    1 =&gt; 42
    2 =&gt; Array
        (
            0 =&gt; 1
            1 =&gt; two
        )

    3 =&gt; apple
)
*/
</pre>
<p>This was the native PHP serialization method. However, since JSON has become so popular in recent years, they decided to add support for it in PHP 5.2. Now you can use the json_encode() and json_decode() functions as well:</p>
<pre class="brush:php" >// a complex array
$myvar = array(
	'hello',
	42,
	array(1,'two'),
	'apple'
);

// convert to a string
$string = json_encode($myvar);

echo $string;
/* prints
"hello",42,,"apple"]
*/

// you can reproduce the original variable
$newvar = json_decode($string);

print_r($newvar);
/* prints
Array
(
    0 =&gt; hello
    1 =&gt; 42
    2 =&gt; Array
        (
            0 =&gt; 1
            1 =&gt; two
        )

    3 =&gt; apple
)
*/
</pre>
<p>It is more compact, and best of all, compatible with javascript and many other languages. However, for complex objects, some information may be lost.</p>
<hr />
<h2><span>8. </span>Compressing Strings</h2>
<p>When talking about compression, we usually think about files, such as ZIP archives. It is possible to compress long strings in PHP, without involving any archive files.</p>
<p>In the following example we are going to utilize the <a  href="http://php.net/manual/en/function.gzcompress.php">gzcompress()</a> and <a  href="http://www.php.net/manual/en/function.gzuncompress.php">gzuncompress()</a> functions:</p>
<pre class="brush:php" >$string =
"Lorem ipsum dolor sit amet, consectetur
adipiscing elit. Nunc ut elit id mi ultricies
adipiscing. Nulla facilisi. Praesent pulvinar,
sapien vel feugiat vestibulum, nulla dui pretium orci,
non ultricies elit lacus quis ante. Lorem ipsum dolor
sit amet, consectetur adipiscing elit. Aliquam
pretium ullamcorper urna quis iaculis. Etiam ac massa
sed turpis tempor luctus. Curabitur sed nibh eu elit
mollis congue. Praesent ipsum diam, consectetur vitae
ornare a, aliquam a nunc. In id magna pellentesque
tellus posuere adipiscing. Sed non mi metus, at lacinia
augue. Sed magna nisi, ornare in mollis in, mollis
sed nunc. Etiam at justo in leo congue mollis.
Nullam in neque eget metus hendrerit scelerisque
eu non enim. Ut malesuada lacus eu nulla bibendum
id euismod urna sodales. ";

$compressed = gzcompress($string);

echo "Original size: ". strlen($string)."n";
/* prints
Original size: 800
*/

echo "Compressed size: ". strlen($compressed)."n";
/* prints
Compressed size: 418
*/

// getting it back
$original = gzuncompress($compressed);
</pre>
<p>We were able to achive almost 50% size reduction. Also the functions <a  href="http://www.php.net/manual/en/function.gzencode.php">gzencode()</a> and <a  href="http://www.php.net/manual/en/function.gzdecode.php">gzdecode()</a> achive similar results, by using a different compression algorithm.</p>
<hr />
<h2><span>9. </span>Register Shutdown Function</h2>
<p>There is a function called <a  href="http://www.php.net/manual/en/function.register-shutdown-function.php">register_shutdown_function()</a>, which will let you execute some code right before the script finishes running.</p>
<p>Imagine that you want to capture some benchmark statistics at the end of your script execution, such as how long it took to run:</p>
<pre class="brush:php" >// capture the start time
$start_time = microtime(true);

// do some stuff
// ...

// display how long the script took
echo "execution took: ".
		(microtime(true) - $start_time).
		" seconds.";
</pre>
<p>At first this may seem trivial. You just add the code to the very bottom of the script and it runs before it finishes. However, if you ever call the <a  href="http://php.net/manual/en/function.exit.php">exit()</a> function, that code will never run. Also, if there is a fatal error, or if the script is terminated by the user (by pressing the Stop button in the browser), again it may not run.</p>
<p>When you use register_shutdown_function(), your code will execute no matter why the script has stopped running:</p>
<pre class="brush:php" >$start_time = microtime(true);

register_shutdown_function('my_shutdown');

// do some stuff
// ...

function my_shutdown()
	global $start_time;

	echo "execution took: ".
			(microtime(true) - $start_time).
			" seconds.";
</pre>
<hr />
<h2>Conclusion</h2>
<p>Do you know any other PHP features that are not widely known but can be very useful? Please share with us in the comments. And thank you for reading!</p>
<p><!--/content--></p>
]]></content:encoded>
			<wfw:commentRss>http://www.taiwangeek.com/2010-08/9-useful-php-functions-and-features-you-need-to-know.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Object-Oriented PHP for Beginners</title>
		<link>http://www.taiwangeek.com/2010-08/object-oriented-php-for-beginners.html</link>
		<comments>http://www.taiwangeek.com/2010-08/object-oriented-php-for-beginners.html#comments</comments>
		<pubDate>Wed, 18 Aug 2010 02:59:11 +0000</pubDate>
		<dc:creator>tung</dc:creator>
				<category><![CDATA[Google Reader]]></category>
		<category><![CDATA[Headline]]></category>
		<category><![CDATA[article]]></category>
		<category><![CDATA[browser]]></category>
		<category><![CDATA[child]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[construction]]></category>
		<category><![CDATA[controller]]></category>
		<category><![CDATA[photos]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.taiwangeek.com/2010-08/object-oriented-php-for-beginners.html</guid>
		<description><![CDATA[ Shared by &#23567;&#33891; 會利用物件導向的確可以省很多事 但誤用會多更多事 For many PHP programmers, object-oriented programming is a frightening concept, full of complicated syntax and other roadblocks. As detailed in my book, Pro PHP and jQuery, you’ll learn the concepts behind object-oriented programming (OOP), a style of coding in which related actions are grouped into classes to aid in creating more-compact, effective code. Understanding Object-Oriented Programming Object-oriented programming is a style of coding that allows developers to group similar tasks into classes ]]></description>
			<content:encoded><![CDATA[<blockquote>
<p><img src="http://www.taiwangeek.com/wp-content/uploads/2010/08/0d5f8dbc8dhouses.jpg-150x68.jpg" /></p>
<p>Read the original here:<br />
<a  target="_blank" href="http://feedproxy.google.com/~r/nettuts/~3/xo-Zg1W_G6g/" title="Object-Oriented PHP for Beginners">Object-Oriented PHP for Beginners</a>
</p></blockquote>
<p><!--/content--></p>
<blockquote><p>Shared by  &#23567;&#33891;<br />
<br />
會利用物件導向的確可以省很多事 但誤用會多更多事</p></blockquote>
<p>
For many PHP programmers, object-oriented programming is a frightening concept, full of complicated syntax and other roadblocks. As detailed in my book, <em><a  href="http://www.amazon.com/gp/product/1430228474?ie=UTF8&#038;tag=ennudesi-20&#038;linkCode=as2&#038;camp=1789&#038;creative=390957&#038;creativeASIN=1430228474">Pro PHP and jQuery,</a></em> you’ll learn the concepts behind <strong>object-oriented programming</strong> (OOP), a style of coding in which related actions are grouped into classes to aid in creating more-compact, effective code.
</p>
<p><span></span></p>
<hr />
<h2>Understanding Object-Oriented Programming</h2>
<p>
Object-oriented programming is a style of coding that allows developers to group similar tasks into <strong>classes</strong>. This helps keep code following the tenet <a  href="http://en.wikipedia.org/wiki/Don%27t_repeat_yourself">“don’t repeat yourself” (DRY)</a> and easy-to-maintain.
</p>
<blockquote>
<p>
“Object-oriented programming is a style of coding that allows developers to group similar tasks into <strong>classes</strong>.”
</p>
</blockquote>
<p>
One of the major benefits of DRY programming is that, if a piece of information changes in your program, usually <strong>only one change is required to update the code.</strong> One of the biggest nightmares for developers is maintaining code where data is declared over and over again, meaning any changes to the program become an infinitely more frustrating game of <em>Where’s Waldo?</em> as they hunt for duplicated data and functionality.
</p>
<p>
OOP is intimidating to a lot of developers because it introduces new syntax and, at a glance, appears to be far more complex than simple procedural, or inline, code. However, upon closer inspection, OOP is actually a very straightforward and ultimately simpler approach to programming.
</p>
<hr />
<h2>Understanding Objects and Classes</h2>
<p>
Before you can get too deep into the finer points of OOP, a basic understanding of the differences between <strong>objects</strong> and <strong>classes</strong> is necessary. This section will go over the building blocks of classes, their different capabilities, and some of their uses.
</p>
<h3>Recognizing the Differences Between Objects and Classes</h3>
<div>
    <img src="http://www.taiwangeek.com/wp-content/uploads/2010/08/0d5f8dbc8dhouses.jpg.jpg" border="0" /></p>
<p>
        Photos by <a  href="http://www.flickr.com/photos/instantjefferson/">Instant Jefferson</a> and <a  href="http://www.flickr.com/photos/johnwardell/">John Wardell</a>
    </p>
</div>
<blockquote>
<p>
“Developers start talking about objects and classes, and they appear to be interchangeable terms. This is not the case, however.”
</p>
</blockquote>
<p>
Right off the bat, there’s confusion in OOP: seasoned developers start talking about objects and classes, and they appear to be interchangeable terms. This is not the case, however, though the difference can be tough to wrap your head around at first.
</p>
<p>
A class, for example, is like <strong>a blueprint for a house</strong>. It defines the shape of the house on paper, with relationships between the different parts of the house clearly defined and planned out, even though the house doesn’t exist.
</p>
<p>
An object, then, is like <strong>the actual house</strong> built according to that blueprint. The data stored in the object is like the wood, wires, and concrete that compose the house: without being assembled according to the blueprint, it’s just a pile of stuff. However, when it all comes together, it becomes an organized, useful house.
</p>
<p>
<strong>Classes form the structure of data and actions and use that information to build objects.</strong> More than one object can be built from the same class at the same time, each one independent of the others. Continuing with our construction analogy, it’s similar to the way an entire subdivision can be built from the same blueprint: 150 different houses that all look the same but have different<br />
families and decorations inside.
</p>
<h3>Structuring Classes</h3>
<p>
The syntax to create a class is pretty straightforward: declare a class using the <tt>class</tt> keyword, followed by the name of the class and a set of curly braces (<tt>{}</tt>):
</p>
<pre class="brush:php"  name="code">< ?php

class MyClass

    // Class properties and methods go here

?>
</pre>
<p>
After creating the class, a new class can be instantiated and stored in a variable using the <tt>new</tt> keyword:
</p>
<pre class="brush:php"  name="code">$obj = new MyClass;
</pre>
<p>
To see the contents of the class, use <tt>var_dump()</tt>:
</p>
<pre class="brush:php"  name="code">var_dump($obj);
</pre>
<p>
Try out this process by putting all the preceding code in a new file called <tt>test.php</tt> in your local testing folder:
</p>
<pre class="brush:php"  name="code">< ?php

class MyClass

	// Class properties and methods go here

$obj = new MyClass;

var_dump($obj);

?>
</pre>
<p>
Load the page in your browser at <tt>http://localhost/test.php</tt> and the following should display:
</p>
<pre class="brush:php"  name="code">object(MyClass)#1 (0)
</pre>
<p>
<strong>In its simplest form, you’ve just completed your first OOP script.</strong>
</p>
<hr />
<h2>Defining Class Properties</h2>
<p>
To add data to a class, <strong>properties</strong>, or class-specific variables, are used. These work exactly like regular variables, except they’re bound to the object and therefore can only be accessed using the object.
</p>
<p>
To add a property to <tt>MyClass</tt>, add the following code to your script:
</p>
<pre class="brush:php"  name="code">< ?php

class MyClass

    public $prop1 = "I&#39;m a class property!";

$obj = new MyClass;

var_dump($obj);

?>
</pre>
<p>
The keyword <tt>public</tt> determines the visibility of the property, which you’ll learn about a little later in this chapter. Next, the property is named using standard variable syntax, and a value is assigned (though class properties do not need an initial value).
</p>
<p>
To read this property and output it to the browser, reference the object from which to read and the property to be read:
</p>
<pre class="brush:php"  name="code">echo $obj->prop1;
</pre>
<p>
Because multiple instances of a class can exist, if the individual object is not referenced, the script would be unable to determine which object to read from. The use of the arrow (<tt>-></tt>) is an OOP construct that accesses the contained properties and methods of a given object.
</p>
<p>
Modify the script in <tt>test.php</tt> to read out the property rather than dumping the whole class by modifying the code as shown:
</p>
<pre class="brush:php"  name="code">< ?php

class MyClass

    public $prop1 = "I&#39;m a class property!";

$obj = new MyClass;

echo $obj->prop1; // Output the property

?>
</pre>
<p>
Reloading your browser now outputs the following:
</p>
<pre class="brush:php"  name="code">I'm a class property!
</pre>
<hr />
<h2>Defining Class Methods</h2>
<p>
<strong>Methods</strong> are class-specific functions. Individual actions that an object will be able to perform are defined within the class as methods.
</p>
<p>
For instance, to create methods that would set and get the value of the class property <tt>$prop1</tt>, add the following to your code:
</p>
<pre class="brush:php"  name="code">< ?php

class MyClass

    public $prop1 = "I&#39;m a class property!";

    public function setProperty($newval)

        $this->prop1 = $newval;

    public function getProperty()

        return $this->prop1 . "";

}

$obj = new MyClass;

echo $obj->prop1;

?>
</pre>
<p>
<strong>Note</strong> — OOP allows objects to reference themselves using <tt>$this</tt>. When working within a method, use <tt>$this</tt> in the same way you would use the object name outside the class.
</p>
<p>
To use these methods, call them just like regular functions, but first, reference the object they belong to. Read the property from <tt>MyClass</tt>, change its value, and read it out again by making the modifications below:
</p>
<pre class="brush:php"  name="code">< ?php

class MyClass

    public $prop1 = "I&#39;m a class property!";

    public function setProperty($newval)

        $this->prop1 = $newval;

    public function getProperty()

        return $this->prop1 . "";

}

$obj = new MyClass;

echo $obj->getProperty(); // Get the property value

$obj->setProperty("I&#39;m a new property value!"); // Set a new one

echo $obj->getProperty(); // Read it out again to show the change

?>
</pre>
<p>
Reload your browser, and you’ll see the following:
</p>
<pre class="brush:php"  name="code">I'm a class property!
I'm a new property value!
</pre>
<blockquote>
<p>
“The power of OOP becomes apparent when using multiple instances of the<br />
same class.”
</p>
</blockquote>
<pre class="brush:php"  name="code">< ?php

class MyClass

    public $prop1 = "I&#39;m a class property!";

    public function setProperty($newval)

        $this->prop1 = $newval;

    public function getProperty()

        return $this->prop1 . "";

}

// Create two objects
$obj = new MyClass;
$obj2 = new MyClass;

// Get the value of $prop1 from both objects
echo $obj->getProperty();
echo $obj2->getProperty();

// Set new values for both objects
$obj->setProperty("I&#39;m a new property value!");
$obj2->setProperty("I belong to the second instance!");

// Output both objects&#39; $prop1 value
echo $obj->getProperty();
echo $obj2->getProperty();

?>
</pre>
<p>
When you load the results in your browser, they read as follows:
</p>
<pre class="brush:php"  name="code">I'm a class property!
I'm a class property!
I'm a new property value!
I belong to the second instance!
</pre>
<p>
As you can see, <strong>OOP keeps objects as separate entities</strong>, which makes for easy separation of different pieces of code into small, related bundles.
</p>
<hr />
<h2>Magic Methods in OOP</h2>
<p>
To make the use of objects easier, PHP also provides a number of <strong>magic methods</strong>, or special methods that are called when certain common actions occur within objects. This allows developers to perform a number of useful tasks with relative ease.
</p>
<h3>Using Constructors and Destructors</h3>
<p>
When an object is instantiated, it’s often desirable to set a few things right off the bat. To handle this, PHP provides the magic method <tt>__construct()</tt>, which is called automatically whenever a new object is<br />
created.
</p>
<p>
For the purpose of illustrating the concept of constructors, add a constructor to <tt>MyClass</tt> that will output a message whenever a new instance of the class is created:
</p>
<pre class="brush:php"  name="code">< ?php

class MyClass

    public $prop1 = "I&#39;m a class property!";

    public function __construct()

        echo &#39;The class "&#39;, __CLASS__, &#39;" was initiated!&#39;;

    public function setProperty($newval)

        $this->prop1 = $newval;

    public function getProperty()

        return $this->prop1 . "";

}

// Create a new object
$obj = new MyClass;

// Get the value of $prop1
echo $obj->getProperty();

// Output a message at the end of the file
echo "End of file.";

?>
</pre>
<p>
<strong>Note</strong> — <tt>__CLASS__</tt> returns the name of the class in which it is called; this is what is known as a <a  href="http://us3.php.net/manual/en/language.constants.predefined.php">magic constant</a>. There are several available magic constants, which you can read more about in the PHP manual.
</p>
<p>
Reloading the file in your browser will produce the following result:
</p>
<pre class="brush:php"  name="code">The class "MyClass" was initiated!
I'm a class property!
End of file.
</pre>
<p>
To call a function when the object is destroyed, the <tt>__destruct()</tt> magic method is available. This is useful for class cleanup (closing a database connection, for instance).
</p>
<p>
Output a message when the object is destroyed by defining the magic method<br />
<tt>__destruct()</tt> in <tt>MyClass</tt>:
</p>
<pre class="brush:php"  name="code">< ?php

class MyClass

    public $prop1 = "I&#39;m a class property!";

    public function __construct()

        echo &#39;The class "&#39;, __CLASS__, &#39;" was initiated!&#39;;

    public function __destruct()

        echo &#39;The class "&#39;, __CLASS__, &#39;" was destroyed.&#39;;

    public function setProperty($newval)

        $this->prop1 = $newval;

    public function getProperty()

        return $this->prop1 . "";

}

// Create a new object
$obj = new MyClass;

// Get the value of $prop1
echo $obj->getProperty();

// Output a message at the end of the file
echo "End of file.";

?>
</pre>
<p>
With a destructor defined, reloading the test file results in the following output:
</p>
<pre class="brush:php"  name="code">The class "MyClass" was initiated!
I'm a class property!
End of file.
The class "MyClass" was destroyed.
</pre>
<blockquote>
<p>
“When the end of a file is reached, PHP automatically releases all resources.”
</p>
</blockquote>
<p>
To explicitly trigger the destructor, you can destroy the object using the<br />
function <tt>unset()</tt>:
</p>
<pre class="brush:php"  name="code">< ?php

class MyClass

    public $prop1 = "I&#39;m a class property!";

    public function __construct()

        echo &#39;The class "&#39;, __CLASS__, &#39;" was initiated!&#39;;

    public function __destruct()

        echo &#39;The class "&#39;, __CLASS__, &#39;" was destroyed.&#39;;

    public function setProperty($newval)

        $this->prop1 = $newval;

    public function getProperty()

        return $this->prop1 . "";

}

// Create a new object
$obj = new MyClass;

// Get the value of $prop1
echo $obj->getProperty();

// Destroy the object
unset($obj);

// Output a message at the end of the file
echo "End of file.";

?>
</pre>
<p>
Now the result changes to the following when loaded in your browser:
</p>
<pre class="brush:php"  name="code">The class "MyClass" was initiated!
I'm a class property!
The class "MyClass" was destroyed.
End of file.
</pre>
<h3>Converting to a String</h3>
<p>
To avoid an error if a script attempts to output <tt>MyClass</tt> as a string, another magic method is used called <tt>__toString()</tt>.
</p>
<p>
Without <tt>__toString()</tt>, <em>attempting to output the object as a string results in a fatal error</em>. Attempt to use <tt>echo</tt> to output the object without a magic method in place:
</p>
<pre class="brush:php"  name="code">< ?php

class MyClass

    public $prop1 = "I&#39;m a class property!";

    public function __construct()

        echo &#39;The class "&#39;, __CLASS__, &#39;" was initiated!&#39;;

    public function __destruct()

        echo &#39;The class "&#39;, __CLASS__, &#39;" was destroyed.&#39;;

    public function setProperty($newval)

        $this->prop1 = $newval;

    public function getProperty()

        return $this->prop1 . "";

}

// Create a new object
$obj = new MyClass;

// Output the object as a string
echo $obj;

// Destroy the object
unset($obj);

// Output a message at the end of the file
echo "End of file.";

?>
</pre>
<p>
This results in the following:
</p>
<pre class="brush:php"  name="code">The class "MyClass" was initiated!

Catchable fatal error: Object of class MyClass could not be converted to string in /Applications/XAMPP/xamppfiles/htdocs/testing/test.php on line 40
</pre>
<p>
To avoid this error, add a <tt>__toString()</tt> method:
</p>
<pre class="brush:php"  name="code">< ?php

class MyClass

    public $prop1 = "I&#39;m a class property!";

    public function __construct()

        echo &#39;The class "&#39;, __CLASS__, &#39;" was initiated!&#39;;

    public function __destruct()

        echo &#39;The class "&#39;, __CLASS__, &#39;" was destroyed.&#39;;

    public function __toString()

        echo "Using the toString method: ";
        return $this->getProperty();

    public function setProperty($newval)

        $this->prop1 = $newval;

    public function getProperty()

        return $this->prop1 . "";

}

// Create a new object
$obj = new MyClass;

// Output the object as a string
echo $obj;

// Destroy the object
unset($obj);

// Output a message at the end of the file
echo "End of file.";

?>
</pre>
<p>
In this case, attempting to convert the object to a string results in a call to the <tt>getProperty()</tt> method. Load the test script in your browser to see the result:
</p>
<pre class="brush:php"  name="code">The class "MyClass" was initiated!
Using the toString method: I'm a class property!
The class "MyClass" was destroyed.
End of file.
</pre>
<p>
<strong>Tip</strong> — In addition to the magic methods discussed in this section, several others are available. For a complete list of magic methods, see the  <a  href="http://us2.php.net/manual/en/language.oop5.magic.php">PHP manual page</a>.
</p>
<hr />
<h2>Using Class Inheritance</h2>
<p>
<strong>Classes can inherit the methods and properties of another class</strong> using the <tt>extends</tt> keyword. For instance, to create a second class that extends <tt>MyClass</tt> and adds a method, you would add the following to your test file:
</p>
<pre class="brush:php"  name="code">< ?php

class MyClass

    public $prop1 = "I&#39;m a class property!";

    public function __construct()

        echo &#39;The class "&#39;, __CLASS__, &#39;" was initiated!&#39;;

    public function __destruct()

        echo &#39;The class "&#39;, __CLASS__, &#39;" was destroyed.&#39;;

    public function __toString()

        echo "Using the toString method: ";
        return $this->getProperty();

    public function setProperty($newval)

        $this->prop1 = $newval;

    public function getProperty()

        return $this->prop1 . "";

}

class MyOtherClass extends MyClass

    public function newMethod()

        echo "From a new method in " . __CLASS__ . ".";

}

// Create a new object
$newobj = new MyOtherClass;

// Output the object as a string
echo $newobj->newMethod();

// Use a method from the parent class
echo $newobj->getProperty();

?>
</pre>
<p>
Upon reloading the test file in your browser, the following is output:
</p>
<pre class="brush:php"  name="code">The class "MyClass" was initiated!
From a new method in MyOtherClass.
I'm a class property!
The class "MyClass" was destroyed.
</pre>
<h3>Overwriting Inherited Properties and Methods</h3>
<p>
To change the behavior of an existing property or method in the new class, you can simply overwrite it by declaring it again in the new class:
</p>
<pre class="brush:php"  name="code">< ?php

class MyClass

    public $prop1 = "I&#39;m a class property!";

    public function __construct()

        echo &#39;The class "&#39;, __CLASS__, &#39;" was initiated!&#39;;

    public function __destruct()

        echo &#39;The class "&#39;, __CLASS__, &#39;" was destroyed.&#39;;

    public function __toString()

        echo "Using the toString method: ";
        return $this->getProperty();

    public function setProperty($newval)

        $this->prop1 = $newval;

    public function getProperty()

        return $this->prop1 . "";

}

class MyOtherClass extends MyClass

    public function __construct()

        echo "A new constructor in " . __CLASS__ . ".";

    public function newMethod()

        echo "From a new method in " . __CLASS__ . ".";

}

// Create a new object
$newobj = new MyOtherClass;

// Output the object as a string
echo $newobj->newMethod();

// Use a method from the parent class
echo $newobj->getProperty();

?>
</pre>
<p>
This changes the output in the browser to:
</p>
<pre class="brush:php"  name="code">A new constructor in MyOtherClass.
From a new method in MyOtherClass.
I'm a class property!
The class "MyClass" was destroyed.
</pre>
<h3>Preserving Original Method Functionality While Overwriting Methods</h3>
<p>
To add new functionality to an inherited method while keeping the original method intact, use the <tt>parent</tt> keyword with the <strong>scope resolution operator</strong> (<tt>::</tt>):
</p>
<pre class="brush:php"  name="code">< ?php

class MyClass

    public $prop1 = "I&#39;m a class property!";

    public function __construct()

        echo &#39;The class "&#39;, __CLASS__, &#39;" was initiated!&#39;;

    public function __destruct()

        echo &#39;The class "&#39;, __CLASS__, &#39;" was destroyed.&#39;;

    public function __toString()

        echo "Using the toString method: ";
        return $this->getProperty();

    public function setProperty($newval)

        $this->prop1 = $newval;

    public function getProperty()

        return $this->prop1 . "";

}

class MyOtherClass extends MyClass

    public function __construct()

        parent::__construct(); // Call the parent class&#39;s constructor
        echo "A new constructor in " . __CLASS__ . ".";

    public function newMethod()

        echo "From a new method in " . __CLASS__ . ".";

}

// Create a new object
$newobj = new MyOtherClass;

// Output the object as a string
echo $newobj->newMethod();

// Use a method from the parent class
echo $newobj->getProperty();

?>
</pre>
<p>
This outputs the result of both the parent constructor and the new class’s constructor:
</p>
<pre class="brush:php"  name="code">The class "MyClass" was initiated!
A new constructor in MyOtherClass.
From a new method in MyOtherClass.
I'm a class property!
The class "MyClass" was destroyed.
</pre>
<hr />
<h2>Assigning the Visibility of Properties and Methods</h2>
<p>
For added control over objects, methods and properties are assigned visibility. This controls how and from where properties and methods can be accessed. There are three visibility keywords: <tt>public</tt>, <tt>protected</tt>, and <tt>private</tt>. In addition to its visibility, a method or property can be declared as <tt>static</tt>, which allows them to be accessed without an instantiation of the class.
</p>
<blockquote><p>“For added control over objects, methods and properties are assigned visibility.”</p>
</blockquote>
<p>
<strong>Note</strong> — Visibility is a new feature as of PHP 5. For information on <a  href="http://us2.php.net/manual/en/language.oop5.php">OOP compatibility with PHP 4</a>, see the PHP manual page.
</p>
<h3>Public Properties and Methods</h3>
<p>
All the methods and properties you’ve used so far have been public. This means that they can be accessed anywhere, both within the class and externally.
</p>
<h3>Protected Properties and Methods</h3>
<p>
When a property or method is declared <tt>protected</tt>, <strong>it can only be accessed within the class itself or in descendant classes</strong> (classes that extend the class containing the protected method).
</p>
<p>
Declare the <tt>getProperty()</tt> method as protected in <tt>MyClass</tt> and try to access it directly from outside the class:
</p>
<pre class="brush:php"  name="code">< ?php

class MyClass

    public $prop1 = "I&#39;m a class property!";

    public function __construct()

        echo &#39;The class "&#39;, __CLASS__, &#39;" was initiated!&#39;;

    public function __destruct()

        echo &#39;The class "&#39;, __CLASS__, &#39;" was destroyed.&#39;;

    public function __toString()

        echo "Using the toString method: ";
        return $this->getProperty();

    public function setProperty($newval)

        $this->prop1 = $newval;

    protected function getProperty()

        return $this->prop1 . "";

}

class MyOtherClass extends MyClass

    public function __construct()

        parent::__construct();
		echo "A new constructor in " . __CLASS__ . ".";

    public function newMethod()

        echo "From a new method in " . __CLASS__ . ".";

}

// Create a new object
$newobj = new MyOtherClass;

// Attempt to call a protected method
echo $newobj->getProperty();

?>
</pre>
<p>
Upon attempting to run this script, the following error shows up:
</p>
<pre class="brush:php"  name="code">The class "MyClass" was initiated!
A new constructor in MyOtherClass.

Fatal error: Call to protected method MyClass::getProperty() from context '' in /Applications/XAMPP/xamppfiles/htdocs/testing/test.php on line 55
</pre>
<p>
Now, create a new method in <tt>MyOtherClass</tt> to call the <tt>getProperty()</tt> method:
</p>
<pre class="brush:php"  name="code">< ?php

class MyClass

    public $prop1 = "I&#39;m a class property!";

    public function __construct()

        echo &#39;The class "&#39;, __CLASS__, &#39;" was initiated!&#39;;

    public function __destruct()

        echo &#39;The class "&#39;, __CLASS__, &#39;" was destroyed.&#39;;

    public function __toString()

        echo "Using the toString method: ";
        return $this->getProperty();

    public function setProperty($newval)

        $this->prop1 = $newval;

    protected function getProperty()

        return $this->prop1 . "";

}

class MyOtherClass extends MyClass

    public function __construct()

        parent::__construct();
		echo "A new constructor in " . __CLASS__ . ".";

    public function newMethod()

        echo "From a new method in " . __CLASS__ . ".";

    public function callProtected()

        return $this->getProperty();

}

// Create a new object
$newobj = new MyOtherClass;

// Call the protected method from within a public method
echo $newobj->callProtected();

?>
</pre>
<p>
This generates the desired result:
</p>
<pre class="brush:php"  name="code">The class "MyClass" was initiated!
A new constructor in MyOtherClass.
I'm a class property!
The class "MyClass" was destroyed.
</pre>
<h3>Private Properties and Methods</h3>
<p>
A property or method declared <tt>private</tt> is accessible <strong>only from within the class that defines it</strong>. This means that <em>even if a new class extends the class that defines a private property,</em> that property or method will not be available at all within the child class.
</p>
<p>
To demonstrate this, declare <tt>getProperty()</tt> as private in <tt>MyClass</tt>, and attempt to call <tt>callProtected()</tt> from<br />
<tt>MyOtherClass</tt>:
</p>
<pre class="brush:php"  name="code">< ?php

class MyClass

    public $prop1 = "I&#39;m a class property!";

    public function __construct()

        echo &#39;The class "&#39;, __CLASS__, &#39;" was initiated!&#39;;

    public function __destruct()

        echo &#39;The class "&#39;, __CLASS__, &#39;" was destroyed.&#39;;

    public function __toString()

        echo "Using the toString method: ";
        return $this->getProperty();

    public function setProperty($newval)

        $this->prop1 = $newval;

    private function getProperty()

        return $this->prop1 . "";

}

class MyOtherClass extends MyClass

    public function __construct()

        parent::__construct();
        echo "A new constructor in " . __CLASS__ . ".";

    public function newMethod()

        echo "From a new method in " . __CLASS__ . ".";

    public function callProtected()

        return $this->getProperty();

}

// Create a new object
$newobj = new MyOtherClass;

// Use a method from the parent class
echo $newobj->callProtected();

?>
</pre>
<p>
Reload your browser, and the following error appears:
</p>
<pre class="brush:php"  name="code">The class "MyClass" was initiated!
A new constructor in MyOtherClass.

Fatal error: Call to private method MyClass::getProperty() from context 'MyOtherClass' in /Applications/XAMPP/xamppfiles/htdocs/testing/test.php on line 49
</pre>
<h3>Static Properties and Methods</h3>
<p>
A method or property declared <tt>static</tt> can be accessed without first instantiating the class; you simply supply the class name, scope resolution operator, and the property or method name.
</p>
<blockquote>
<p>
“One of the major benefits to using static properties is that they keep their stored values for the duration of the script.”
</p>
</blockquote>
<p>
To demonstrate this, add a static property called <tt>$count</tt> and a static method called <tt>plusOne()</tt> to <tt>MyClass</tt>. Then set up a <tt>do...while</tt> loop to output the incremented value of <tt>$count</tt> as long as the value is less than 10:
</p>
<pre class="brush:php"  name="code">< ?php

class MyClass

    public $prop1 = "I&#39;m a class property!";

    public static $count = 0;

    public function __construct()

        echo &#39;The class "&#39;, __CLASS__, &#39;" was initiated!&#39;;

    public function __destruct()

        echo &#39;The class "&#39;, __CLASS__, &#39;" was destroyed.&#39;;

    public function __toString()

        echo "Using the toString method: ";
        return $this->getProperty();

    public function setProperty($newval)

        $this->prop1 = $newval;

    private function getProperty()

        return $this->prop1 . "";

    public static function plusOne()

        return "The count is " . ++self::$count . ".";

}

class MyOtherClass extends MyClass

    public function __construct()

        parent::__construct();
        echo "A new constructor in " . __CLASS__ . ".";

    public function newMethod()

        echo "From a new method in " . __CLASS__ . ".";

    public function callProtected()

        return $this->getProperty();

}

do

    // Call plusOne without instantiating MyClass
    echo MyClass::plusOne();
 while ( MyClass::$count < 10 );

?>
</pre>
<p>
<strong>Note</strong> — When accessing static properties, the dollar sign<br />
(<tt>$</tt>) comes <em>after the scope resolution operator.</em>
</p>
<p>
When you load this script in your browser, the following is output:
</p>
<pre class="brush:php"  name="code">The count is 1.
The count is 2.
The count is 3.
The count is 4.
The count is 5.
The count is 6.
The count is 7.
The count is 8.
The count is 9.
The count is 10.
</pre>
<hr />
<h2>Commenting with DocBlocks</h2>
<blockquote>
<p>
“The DocBlock commenting style is a widely<br />
accepted method of documenting classes.”
</p>
</blockquote>
<p>
While not an official part of OOP, the <a  href="http://en.wikipedia.org/wiki/PHPDoc">DocBlock</a> commenting style is a widely accepted method of documenting classes. Aside from providing a standard for<br />
developers to use when writing code, it has also been adopted by many of the most popular software development kits (SDKs), such as <a  href="http://eclipse.org">Eclipse</a> and <a  href="http://netbeans.org">NetBeans</a>, and will be used to generate code hints.
</p>
<p>
A DocBlock is defined by using a block comment that starts with an additional asterisk:
</p>
<pre class="brush:php"  name="code">/**
 * This is a very basic DocBlock
 */
</pre>
<p>
The real power of DocBlocks comes with the ability to use <strong>tags</strong>, which start with an at symbol (<tt>@</tt>) immediately followed by the tag name and the value of the tag. <strong>DocBlock tags allow developers to define authors of a file, the license for a class, the property or method information, and other useful information.</strong>
</p>
<p>
The most common tags used follow:
</p>
<ul>
<li><strong>@author</strong>: The author of the current element (which might be a class, file, method, or any bit of code) are listed using this tag. Multiple author tags can be used in the same DocBlock if more than one author is credited. The format for the author name is <tt>John Doe <john .doe@email.com></john></tt>.</li>
<li><strong>@copyright</strong>: This signifies the copyright year and name of the copyright holder for the current element. The format is <tt>2010 Copyright Holder</tt>.</li>
<li><strong>@license</strong>: This links to the license for the current element. The format for the license information is<br />
        <tt>http://www.example.com/path/to/license.txt License Name</tt>.</li>
<li><strong>@var</strong>: This holds the type and description of a variable or class property. The format is <tt>type element description</tt>.</li>
<li><strong>@param</strong>: This tag shows the type and description of a function or method parameter. The format is <tt>type $element_name element description</tt>.</li>
<li><strong>@return</strong>: The type and description of the return value of a function or method are provided in this tag. The format is <tt>type return element description</tt>.</li>
</ul>
<p>
A sample class commented with DocBlocks might look like this:
</p>
<pre class="brush:php"  name="code">< ?php

/**
 * A simple class
 *
 * This is the long description for this class,
 * which can span as many lines as needed. It is
 * not required, whereas the short description is
 * necessary.
 *
 * It can also span multiple paragraphs if the
 * description merits that much verbiage.
 *
 * @author Jason Lengstorf <jason.lengstorf@ennuidesign.com>
 * @copyright 2010 Ennui Design
 * @license http://www.php.net/license/3_01.txt PHP License 3.01
 */
class SimpleClass

    /**
     * A public variable
     *
     * @var string stores data for the class
     */
    public $foo;

    /**
     * Sets $foo to a new value upon class instantiation
     *
     * @param string $val a value required for the class
     * @return void
     */
    public function __construct($val)

        $this->foo = $val;

    /**
     * Multiplies two integers
     *
     * Accepts a pair of integers and returns the
     * product of the two.
     *
     * @param int $bat a number to be multiplied
     * @param int $baz a number to be multiplied
     * @return int the product of the two parameters
     */
    public function bar($bat, $baz)

        return $bat * $baz;

}

?>
</pre>
<p>
Once you scan the preceding class, the benefits of DocBlock are apparent: everything is clearly defined so that the next developer can pick up the code and <em>never have to wonder what a snippet of code does or what it should contain.</em>
</p>
<hr />
<h2>Comparing Object-Oriented and Procedural Code</h2>
<p>
There’s not really a right and wrong way to write code. That being said, <strong>this section outlines a strong argument for adopting an object-oriented approach in software development, especially in large applications.</strong>
</p>
<hr />
<h2>Reason 1: Ease of Implementation</h2>
<blockquote>
<p>
“While it may be daunting at first, OOP actually provides an easier approach to dealing with data.”
</p>
</blockquote>
<p>
While it may be daunting at first, OOP actually provides an easier approach to dealing with data. Because an object can store data internally, variables don’t need to be passed from function to function to work properly.
</p>
<p>
Also, because <em>multiple instances of the same class can exist simultaneously</em>, dealing with large data sets is infinitely easier. For instance, imagine you have two people’s information being processed in a file. They need names, occupations, and ages.
</p>
<h3>The Procedural Approach</h3>
<p>
Here’s the procedural approach to our example:
</p>
<pre class="brush:php"  name="code">< ?php

function changeJob($person, $newjob)

    $person&#39;job&#39; = $newjob; // Change the person&#39;s job
    return $person;

function happyBirthday($person)

    ++$person&#39;age&#39;; // Add 1 to the person&#39;s age
    return $person;

$person1 = array(
    &#39;name&#39; => &#39;Tom&#39;,
    &#39;job&#39; => &#39;Button-Pusher&#39;,
    &#39;age&#39; => 34
);

$person2 = array(
    &#39;name&#39; => &#39;John&#39;,
    &#39;job&#39; => &#39;Lever-Puller&#39;,
    &#39;age&#39; => 41
);

// Output the starting values for the people
echo "</pre>
<pre class="brush:php"  class="brush: php;">Person 1: ", print_r($person1, TRUE), "</pre>
<p>&#8220;;<br />
echo &#8220;
<pre class="brush:php"  class="brush: php;">Person 2: ", print_r($person2, TRUE), "</pre>
<p>&#8220;;</p>
<p>// Tom got a promotion and had a birthday<br />
$person1 = changeJob($person1, &#39;Box-Mover&#39;);<br />
$person1 = happyBirthday($person1);</p>
<p>// John just had a birthday<br />
$person2 = happyBirthday($person2);</p>
<p>// Output the new values for the people<br />
echo &#8220;
<pre class="brush:php"  class="brush: php;">Person 1: ", print_r($person1, TRUE), "</pre>
<p>&#8220;;<br />
echo &#8220;
<pre class="brush:php"  class="brush: php;">Person 2: ", print_r($person2, TRUE), "</pre>
<p>&#8220;;</p>
<p>?></p>
<p>
When executed, the code outputs the following:
</p>
<pre class="brush:php"  name="code">Person 1: Array
(
    name => Tom
    job => Button-Pusher
    age => 34
)
Person 2: Array
(
    name => John
    job => Lever-Puller
    age => 41
)
Person 1: Array
(
    name => Tom
    job => Box-Mover
    age => 35
)
Person 2: Array
(
    name => John
    job => Lever-Puller
    age => 42
)
</pre>
<p>
While this code isn’t necessarily bad, there’s a lot to keep in mind while coding. <strong>The array of the affected person’s attributes must be passed and returned from each function call</strong>, which leaves margin for error.
</p>
<p>
To clean up this example, it would be desirable to <strong>leave as few things up to the developer as possible.</strong> Only absolutely essential information for the current operation should need to be passed to the functions.
</p>
<p>
<strong>This is where OOP steps in and helps you clean things up.</strong>
</p>
<h3>The OOP Approach</h3>
<p>
Here’s the OOP approach to our example:
</p>
<pre class="brush:php"  name="code">< ?php

class Person

    private $_name;
    private $_job;
    private $_age;

    public function __construct($name, $job, $age)

        $this->_name = $name;
        $this->_job = $job;
        $this->_age = $age;

    public function changeJob($newjob)

        $this->_job = $newjob;

    public function happyBirthday()

        ++$this->_age;

}

// Create two new people
$person1 = new Person("Tom", "Button-Pusher", 34);
$person2 = new Person("John", "Lever Puller", 41);

// Output their starting point
echo "</pre>
<pre class="brush:php"  class="brush: php;">Person 1: ", print_r($person1, TRUE), "</pre>
<p>&#8220;;<br />
echo &#8220;
<pre class="brush:php"  class="brush: php;">Person 2: ", print_r($person2, TRUE), "</pre>
<p>&#8220;;</p>
<p>// Give Tom a promotion and a birthday<br />
$person1->changeJob(&#8220;Box-Mover&#8221;);<br />
$person1->happyBirthday();</p>
<p>// John just gets a year older<br />
$person2->happyBirthday();</p>
<p>// Output the ending values<br />
echo &#8220;
<pre class="brush:php"  class="brush: php;">Person 1: ", print_r($person1, TRUE), "</pre>
<p>&#8220;;<br />
echo &#8220;
<pre class="brush:php"  class="brush: php;">Person 2: ", print_r($person2, TRUE), "</pre>
<p>&#8220;;</p>
<p>?></p>
<p>
This outputs the following in the browser:
</p>
<pre class="brush:php"  name="code">Person 1: Person Object
(
    _name:private => Tom
    _job:private => Button-Pusher
    _age:private => 34
)

Person 2: Person Object
(
    _name:private => John
    _job:private => Lever Puller
    _age:private => 41
)

Person 1: Person Object
(
    _name:private => Tom
    _job:private => Box-Mover
    _age:private => 35
)

Person 2: Person Object
(
    _name:private => John
    _job:private => Lever Puller
    _age:private => 42
)
</pre>
<p>
There’s a little bit more setup involved to make the approach object oriented, but after the class is defined, creating and modifying people is a breeze; <strong>a person’s information does not need to be passed or returned from methods, and only absolutely essential information is passed to each method.</strong>
</p>
<blockquote>
<p>
“OOP will significantly reduce your workload if implemented properly.”
</p>
</blockquote>
<p>
On the small scale, this difference may not seem like much, but as your applications grow in size, OOP will significantly reduce your workload if implemented properly.
</p>
<p>
<strong>Tip</strong> — <em>Not everything needs to be object oriented.</em> A quick function that handles something small in one place inside the application does not necessarily need to be wrapped in a class. Use your best judgment when deciding between object-oriented and procedural approaches.
</p>
<hr />
<h2>Reason 2: Better Organization</h2>
<p>
Another benefit of OOP is how well it lends itself to being <strong>easily packaged and cataloged.</strong> Each class can generally be kept in its own separate file, and if a uniform naming convention is used, accessing the classes is extremely simple.
</p>
<p>
Assume you’ve got an application with 150 classes that are called dynamically through a controller file at the root of your application filesystem. All 150 classes follow the naming convention <tt>class.classname.inc.php</tt> and reside in the <tt>inc</tt> folder of your application.
</p>
<p>
The controller can implement PHP’s <tt>__autoload()</tt> function to dynamically pull in only the classes it needs as they are called, rather than including all 150 in the controller file just in case or coming up with some clever way of including the files in your own code:
</p>
<pre class="brush:php"  name="code">< ?php
    function __autoload($class_name)

        include_once &#39;inc/class.&#39; . $class_name . &#39;.inc.php&#39;;

?>
</pre>
<p>
Having each class in a separate file also makes code more portable and easier to reuse in new applications without a bunch of copying and pasting.
</p>
<hr />
<h2>Reason 3: Easier Maintenance</h2>
<p>
Due to the more compact nature of OOP when done correctly, <strong>changes in the code are usually much easier to spot</strong> and make than in a long spaghetti code procedural implementation.
</p>
<p>
If a particular array of information gains a new attribute, a procedural piece of software may require (in a worst-case scenario) that the new attribute be added to each function that uses the array.
</p>
<p>
An OOP application could potentially be updated as easily adding the new property and then adding the methods that deal with said property.
</p>
<p>
A lot of the benefits covered in this section are the product of <strong>OOP in combination with DRY programming practices.</strong> It is definitely possible to create easy-to-maintain procedural code that doesn’t cause nightmares, and it is equally possible to create awful object-oriented code. <em>Pro PHP and  jQuery</em> will attempt to demonstrate a combination of good coding habits in conjunction with OOP to generate clean code that’s easy to read and maintain.
</p>
<hr />
<h2>Summary</h2>
<p>
At this point, you should feel comfortable with the object-oriented programming style. Learning OOP is a great way to take your programming to that next level. When implemented properly, OOP will help you produce easy-to-read, easy-to-maintain, portable code that will save you (and the developers who work with you) hours of extra work. Are you stuck on something that wasn’t covered in this article? Are you already using OOP and have some tips for beginners? Share them in the comments!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.taiwangeek.com/2010-08/object-oriented-php-for-beginners.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>[PHP::PDO]SQLITE Drop Columns function</title>
		<link>http://www.taiwangeek.com/2010-08/phppdosqlite-drop-columns-function.html</link>
		<comments>http://www.taiwangeek.com/2010-08/phppdosqlite-drop-columns-function.html#comments</comments>
		<pubDate>Tue, 17 Aug 2010 06:57:22 +0000</pubDate>
		<dc:creator>tung</dc:creator>
				<category><![CDATA[原創]]></category>
		<category><![CDATA[DROP-COLUMN]]></category>
		<category><![CDATA[SQLITE]]></category>

		<guid isPermaLink="false">http://www.taiwangeek.com/?p=1317</guid>
		<description><![CDATA[//CODE DEMO $dbh = new PDO('sqlite:ClientFB.sqlite3'); $st = $dbh-&#62;query("PRAGMA table_info(ap_form_elements)"); var_dump($st-&#62;fetchAll(PDO::FETCH_COLUMN,1)); sqlite_drop_table_columns('ap_form_elements',array('element_position','element_default_value'),$dbh); $st = $dbh-&#62;query("PRAGMA table_info(ap_form_elements)"); var_dump($st-&#62;fetchAll(PDO::FETCH_COLUMN,1)); /** * 實做一個刪除資料表欄位 function * @prama $table STRING * @prama $columns ARRAY */... <a class="meta-more" href="http://www.taiwangeek.com/2010-08/phppdosqlite-drop-columns-function.html">Read more <span class="meta-nav">&#187;</span></a>]]></description>
			<content:encoded><![CDATA[<pre class="brush:php">//CODE DEMO
$dbh = new PDO('sqlite:ClientFB.sqlite3');
$st = $dbh-&gt;query("PRAGMA table_info(ap_form_elements)");
var_dump($st-&gt;fetchAll(PDO::FETCH_COLUMN,1));

sqlite_drop_table_columns('ap_form_elements',array('element_position','element_default_value'),$dbh);

$st = $dbh-&gt;query("PRAGMA table_info(ap_form_elements)");
var_dump($st-&gt;fetchAll(PDO::FETCH_COLUMN,1));

/**
* 實做一個刪除資料表欄位 function
* @prama $table STRING
* @prama $columns ARRAY
*/
function sqlite_drop_table_columns($table,$columns,$dbh){
//取得所有欄位
$st = $dbh-&gt;query("PRAGMA table_info(ap_form_elements)");
if($st){
$fields = $st-&gt;fetchAll(PDO::FETCH_COLUMN,1);
//去除不要的欄位
$fls = array();
foreach($fields as $f){
if(!in_array($f,$columns)){
$fls[] = $f;
}
}
}else{
return FALSE;
}
unset($st);
//組合SQL語法
$field_list = implode(',',$fls);
$SQL = &lt; &lt;&lt;QUERY
CREATE TEMPORARY TABLE {$table}_bak({$field_list});
INSERT INTO {$table}_bak SELECT {$field_list} FROM {$table};
DROP TABLE {$table};
CREATE TABLE {$table}({$field_list});
INSERT INTO {$table} SELECT {$field_list} FROM {$table}_bak;
DROP TABLE {$table}_bak;
QUERY;
return $dbh-&gt;exec($SQL));
}
</pre>
<p>This is a sample show case,It will break the table attribut (ex: AUTOINCREMENT,PRIMARY KEY&#8230;.)</p>
<p>AND this is more powerful version</p>
<pre class="brush:php">
/**
* implement a drop columns sqlite function
* @param $table STRING
* @param $columns ARRAY
* @param $dbh PDO
* @retrun FALSE|INT
*/
function sqlite_drop_table_columns($table,$columns,$dbh){
	//取得所有欄位
	$st = sqlite_create_analytic($table,$dbh);
	if($st){
		$fields = array_keys($st);
		//去除不要的欄位
		$fls = array();
		foreach($st as $f =&gt; $v){
			if(!in_array($f,$columns)){
				$fls[$f] = $v;
			}
		}
	}else{
		return FALSE;
	}
	unset($st);
	//組合SQL語法
	$field_list = implode(',',array_keys($fls));
	$field_list_sql = implode(',',array_values($fls));
	$SQL = &lt;&lt;&lt;QUERY
CREATE TEMPORARY TABLE {$table}_bak({$field_list_sql});
INSERT INTO {$table}_bak SELECT {$field_list} FROM {$table};
DROP TABLE {$table};
CREATE TABLE {$table}({$field_list_sql});
INSERT INTO {$table} SELECT {$field_list} FROM {$table}_bak;
DROP TABLE {$table}_bak;
QUERY;

	return $dbh-&gt;exec($SQL);
}
/*
* @param $table STRING
* @param $dbh PDO
* @return FALSE|ARRAY
*/
function sqlite_create_analytic($table,$dbh){
	$sql = "SELECT sql FROM sqlite_master WHERE type='table' and name='{$table}'";
	$st = $dbh-&gt;query($sql);
	if($st){
		$sql = $st-&gt;fetch(PDO::FETCH_COLUMN,1);
	}else{
		return FALSE;
	}

	if(preg_match('/\(([\s\S\n]+)\)/si',$sql,$mt)){
		$col_sqls = explode(',',$mt[1]);
		$columns = array();
		$st = $dbh-&gt;query("PRAGMA table_info({$table})");
		if($st){
			$cols = $st-&gt;fetchAll(PDO::FETCH_COLUMN,1);
			foreach($cols as $col){
				foreach($col_sqls as $col_sql){
					$test = str_replace(array('"',"'"),'',$col_sql);
					if(FALSE === strstr($test,"{$col} ")){
						continue;
					}else{
						$columns[$col] = trim($col_sql);
					}
				}
			}
			if(empty($columns)){
				return false;
			}else{
				return $columns;
			}
		}else{
			return false;
		}
	}else{
		return FALSE;
	}
}
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.taiwangeek.com/2010-08/phppdosqlite-drop-columns-function.html/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>

<!-- Performance optimized by W3 Total Cache. Learn more: http://www.w3-edge.com/wordpress-plugins/

Minified using disk
Page Caching using disk (enhanced) (request URI doesn't have a trailing slash)

Served from: www.taiwangeek.com @ 2012-02-05 23:46:33 -->
