<?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. &#187; Google Reader</title>
	<atom:link href="http://www.taiwangeek.com/category/google-reader/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>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>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>Cleanup WordPress Header</title>
		<link>http://www.taiwangeek.com/2010-08/cleanup-wordpress-header.html</link>
		<comments>http://www.taiwangeek.com/2010-08/cleanup-wordpress-header.html#comments</comments>
		<pubDate>Tue, 03 Aug 2010 00:29:50 +0000</pubDate>
		<dc:creator>tung</dc:creator>
				<category><![CDATA[Google Reader]]></category>
		<category><![CDATA[engineer]]></category>
		<category><![CDATA[function]]></category>
		<category><![CDATA[hook]]></category>
		<category><![CDATA[link-rel]]></category>
		<category><![CDATA[links]]></category>
		<category><![CDATA[really-simple]]></category>
		<category><![CDATA[recents-drafts]]></category>
		<category><![CDATA[windows]]></category>
		<category><![CDATA[windows-live]]></category>
		<category><![CDATA[writer]]></category>

		<guid isPermaLink="false">http://www.taiwangeek.com/2010-08/cleanup-wordpress-header.html</guid>
		<description><![CDATA[ Shared by &#23567;&#33891; 你知道這些狗屎header消耗多少資源嗎?恩~當你超過上萬篇文章就有感覺了~ WordPress implements new standard features in the head of the theme since version 2.5, that are always on the hook wp_head . ]]></description>
			<content:encoded><![CDATA[<blockquote>
<p>Link:<br />
<a  target="_blank" href="http://wpengineer.com/wordpress-header/" title="Cleanup WordPress Header">Cleanup WordPress Header</a>
</p></blockquote>
<p><!--/content--></p>
<blockquote><p>Shared by  &#23567;&#33891;<br />
<br />
你知道這些狗屎header消耗多少資源嗎?恩~當你超過上萬篇文章就有感覺了~</p></blockquote>
<p>WordPress implements new standard features in the head of the theme since version 2.5, that are always on the hook <code>wp_head</code>. Even in WordPress 2.8 new functions were added. If you don&#8217;t need them you can easily disable them by using the function <a  href="http://codex.wordpress.org/Function_Reference/remove_action" title="Doc in Codex"><code>remove_action</code></a>.<br />
<span></span></p>
<h3>Function <code>remove_action</code></h3>
<p><code>remove_action( $tag, $function_to_add, $priority, $accepted_args );</code></p>
<blockquote><p>This function removes a function attached to a specified action hook. This method can be used to remove default functions attached to a specific action hook and possibly replace them with a substitute.</p>
<p><strong>Important:</strong> To remove a hook, the <code>$function_to_remove</code> and <code>$priority</code> arguments must match when the hook was added. This goes for both filters and actions. No warning will be given on removal failure.<br />
<cite>via: <a  href="http://codex.wordpress.org/Function_Reference/remove_action">WP Codexy</a></cite></p>
</blockquote>
<p>The following syntax shows an excerpt, only a part of the output you can have in your theme. They result from the standard functions, which are loaded in the head of the theme. Visible, if you search in the file <code>wp-includes/default-filters.php</code> for the Hook <code>wp_head</code>. Not all filters should be deactivated, because in most cases they are useful. But WordPress is not only as classical blog in use and therefore some functions are not necessary.</p>
<div>
<div>
<pre class="brush: php;"><span>< </span>link rel<span>=</span><span>"alternate"</span> type<span>=</span><span>"application/rss+xml"</span> title<span>=</span><span>"WP Engineer RSS Feed"</span> href<span>=</span><span>"http://wpengineer.com/feed/"</span> <span>/></span>
<span>< </span>link rel<span>=</span><span>"alternate"</span> type<span>=</span><span>"application/atom+xml"</span> title<span>=</span><span>"WP Engineer Atom Feed"</span> href<span>=</span><span>"http://wpengineer.com/feed/atom/"</span> <span>/></span>
<span>< </span>link rel<span>=</span><span>"pingback"</span> href<span>=</span><span>"http://wpengineer.com/blog/xmlrpc.php"</span> <span>/></span>
<span>< </span>link rel<span>=</span><span>"EditURI"</span> type<span>=</span><span>"application/rsd+xml"</span> title<span>=</span><span>"RSD"</span> href<span>=</span><span>"http://wpengineer.com/xmlrpc.php?rsd"</span> <span>/></span>
<span>< </span>link rel<span>=</span><span>'index'</span> title<span>=</span><span>'WP Engineer'</span> href<span>=</span><span>'http://wpengineer.com'</span> <span>/></span>
<span>< </span>link rel<span>=</span><span>'start'</span> title<span>=</span><span>'Use WordPress 2.7 Offline'</span> href<span>=</span><span>'http://wpengineer.com/use-wordpress-27-offline/'</span> <span>/></span>
<span>< </span>link rel<span>=</span><span>'prev'</span> title<span>=</span><span>'Recents Drafts All Authors'</span> href<span>=</span><span>'http://wpengineer.com/recents-drafts-all-authors/'</span> <span>/></span></span></span></span></span></span></span></span></pre>
</div>
</div>
<p>This is an example, not a recommendation where some functions are deactivated. Check your header and turn off what you don&#8217;t need. Less markup and better loading time.</p>
<div>
<div>
<pre class="brush: php;">remove_action<span>(</span> <span>'wp_head'</span><span>,</span> <span>'feed_links_extra'</span><span>,</span> <span>3</span> <span>)</span><span>;</span> <span>// Display the links to the extra feeds such as category feeds</span>
remove_action<span>(</span> <span>'wp_head'</span><span>,</span> <span>'feed_links'</span><span>,</span> <span>2</span> <span>)</span><span>;</span> <span>// Display the links to the general feeds: Post and Comment Feed</span>
remove_action<span>(</span> <span>'wp_head'</span><span>,</span> <span>'rsd_link'</span> <span>)</span><span>;</span> <span>// Display the link to the Really Simple Discovery service endpoint, EditURI link</span>
remove_action<span>(</span> <span>'wp_head'</span><span>,</span> <span>'wlwmanifest_link'</span> <span>)</span><span>;</span> <span>// Display the link to the Windows Live Writer manifest file.</span>
remove_action<span>(</span> <span>'wp_head'</span><span>,</span> <span>'index_rel_link'</span> <span>)</span><span>;</span> <span>// index link</span>
remove_action<span>(</span> <span>'wp_head'</span><span>,</span> <span>'parent_post_rel_link'</span><span>,</span> <span>10</span><span>,</span> <span>0</span> <span>)</span><span>;</span> <span>// prev link</span>
remove_action<span>(</span> <span>'wp_head'</span><span>,</span> <span>'start_post_rel_link'</span><span>,</span> <span>10</span><span>,</span> <span>0</span> <span>)</span><span>;</span> <span>// start link</span>
remove_action<span>(</span> <span>'wp_head'</span><span>,</span> <span>'adjacent_posts_rel_link'</span><span>,</span> <span>10</span><span>,</span> <span>0</span> <span>)</span><span>;</span> <span>// Display relational links for the posts adjacent to the current post.</span>
remove_action<span>(</span> <span>'wp_head'</span><span>,</span> <span>'wp_generator'</span> <span>)</span><span>;</span> <span>// Display the XHTML generator that is generated on the wp_head hook, WP version</span></pre>
</div>
</div>
<p><!--/content--></p>
]]></content:encoded>
			<wfw:commentRss>http://www.taiwangeek.com/2010-08/cleanup-wordpress-header.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Our WordPress Developer Toolbox</title>
		<link>http://www.taiwangeek.com/2010-08/our-wordpress-developer-toolbox.html</link>
		<comments>http://www.taiwangeek.com/2010-08/our-wordpress-developer-toolbox.html#comments</comments>
		<pubDate>Tue, 03 Aug 2010 00:26:58 +0000</pubDate>
		<dc:creator>tung</dc:creator>
				<category><![CDATA[Google Reader]]></category>
		<category><![CDATA[browser]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[commander]]></category>
		<category><![CDATA[development]]></category>
		<category><![CDATA[environment]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[people]]></category>
		<category><![CDATA[plugin]]></category>
		<category><![CDATA[search]]></category>
		<category><![CDATA[time]]></category>
		<category><![CDATA[tools]]></category>
		<category><![CDATA[windows]]></category>
		<category><![CDATA[work]]></category>

		<guid isPermaLink="false">http://www.taiwangeek.com/2010-08/our-wordpress-developer-toolbox.html</guid>
		<description><![CDATA[ Shared by &#23567;&#33891; 我真的為這個文章喝采 他可讓我節省好多時間 Again and again the question comes in: What do you use as an environment to develop with WordPress. Some suggestions I would like to give, these are just my preferences, but I would be happy if you tell me your preferences of tools. ]]></description>
			<content:encoded><![CDATA[<blockquote>
<p>See the article here:<br />
<a  target="_blank" href="http://wpengineer.com/our-wordpress-developer-toolbox/" title="Our WordPress Developer Toolbox">Our WordPress Developer Toolbox</a>
</p></blockquote>
<p><!--/content--></p>
<blockquote><p>Shared by  &#23567;&#33891;<br />
<br />
我真的為這個文章喝采 他可讓我節省好多時間</p></blockquote>
<p>Again and again the question comes in: What do you use as an environment to develop with WordPress. Some suggestions I would like to give, these are just my preferences, but I would be happy if you tell me your preferences of tools. Maybe there is one or the other useful tool included, I never heard of.<br /> <span></span></p>
<h4>Platform</h4>
<p>Currently I am working on Windows and Linux, so that should be a priority, that I can use my tools on both platforms. This is important to me because I consider a heterogeneous environment for conducive.</p>
<h4>Browser</h4>
<p>In my everyday environment of web development, I work primarily in the browser and the editor, therefore, these two tools for me are also the center of my work.</p>
<p>My favorite browser is <a  href="http://www.mozilla-europe.org/de/firefox/">Firefox</a>, especially because of the great Add-ons. Therefore I have to mention the awesome Add-on <a  href="http://getfirebug.com/">FireBug</a> , I cannot imagine to work without it. For this Add-on there are even <a  href="http://getfirebug.com/downloads#extensions">more Add-ons</a>, which I also use and recommend, especially <a  href="http://developer.yahoo.com/yslow/">YSlow</a>, <a  href="http://www.firephp.org/">FirePHP</a> and <a  href="http://code.google.com/intl/de-DE/speed/page-speed/">Page Speed</a>.</p>
<p>Also I like to use the Add-on <a  href="http://chrispederick.com/work/web-developer/features/">Web Developer</a> to get access to certain content of the website, like Cookies or JavaScript. The possibilities of Web Developer are tremendous and therefore a wonderful tool. Some functionalities are included in Firebug and Web Developer, you have to decide which functions you like more in each Add-on.</p>
<h4>Editor</h4>
<p>Another important tool is the editor, and my favorite is <a  href="http://www.ultraedit.com/">UltraEdit</a>. An editor, which is not Open Source, but I love to use since several years. Here I guess mainly the speed of the editor and the wonderful extensibility with your own tools is the part I really like. That&#8217;s why I parse PHP and validate HTML and CSS directly in the editor. For the parsing of CSS I also use <a  href="http://csstidy.sourceforge.net/">CSSTidy</a>, also available online. I parse PHP via web server that is integrated in the editor and also integrated via <a  href="http://www.icosaedro.it/phplint/"> PHPLint</a>, also in the additional tools of the editor.</p>
<p>Under Linux I can not quite decide whether I should use <a  href="http://www.geany.org/"> Geany</a> or <a  href="http://netbeans.org/">NetBeans</a>, where NetBeans is already too slow and I really miss one or the other feature in Geany. UE is currently still in the testing and beta phase and we&#8217;ll see, maybe I can not yet get away off this editor.</p>
<h4>Webserver &#038; Tools</h4>
<p>There are two other important tools to use in the context of web development. I work on the local environment under Windows with <a  href="http://www.apachefriends.org/de/xampp.html">XAMPP</a> and in Linux is the local web environment installed via package manager. So I have on each client an environment to work with PHP and mySQL.</p>
<p>Important in the development with PHP is error and warning output and debugging. In PHP, there are several different approaches and I use the module <a  href="http://xdebug.org/">xdebug</a>.<br /> Furthermore, I write in the context the ErrorLog and evaluate them. The last tool I would like to point out is <a  href="http://code.google.com/p/webgrind/">Webgrind</a>, which is used as a web application. Alternatively, there are desktop tools that perform this work, for example <a  href="http://sourceforge.net/projects/wincachegrind/">WinCacheGrind</a> under Windows. This evaluates perfectly the profiling and optimizes your code.</p>
<h4>FTP</h4>
<p>To get the development on the server, it usually requires a tool, which dominates the FTP protocol and provides a possible interface for managing the accounts. Here I use under Windows <a  href="http://www.ghisler.com">Total Commander</a>, which can be perfectly adapted to your needs and I love it that I can open multiple connections in several tabs. On Linux I use the Add-on for Firefox <a  href="http://fireftp.mozdev.org/">FireFTP</a>. There are several more tools, but I&#8217;ve never found the time to look at various other options.</p>
<h4>WordPress</h4>
<p>As I develop primarily in and for WordPress, I have a few small Plugins in the test environment active, which ease my view on certain data, and which specifically save errors or issues in WordPress. A small list with short explanation of Plugins, even if I don&#8217;t use all of them, but there might be one or two in this list you like.</p>
<ul>
<li><a  href="http://wordpress.org/extend/plugins/wp-developer-assistant/">WP Developer Assistant</a> &#8211; because it has some reports and feature, which are very handy</li>
<li><a  href="http://www.code-styling.de/english/development/wordpress-plugin-codestyling-localization-en">CodeStyling Localization</a> &#8211; because you can create a Plugin multilingual, it&#8217;s easy to create new language files</li>
<li><a  href="http://striderweb.com/nerdaphernalia/features/wp-log-deprecated-calls/">Log Deprecated Calls</a> &#8211; not always in use, but can be useful</li>
<li><a  href="http://www.mittineague.com/dev/er.php">Error Reporting</a></li>
<li><a  href="http://bueltge.de/wordpress-performance-analysieren-plugin/558/">Debug Queries</a> &#8211; Analysis of queries</li>
<li><a  href="http://bueltge.de/debug-objects-wordpress-plugin/966/">Debug Objects</a> &#8211; Evaluates many values</li>
<li><a  href="http://www.adminer.org/en/">Adminer</a> &#8211; for the fast access to your webspace or as <a  href="http://bueltge.de/adminer-fuer-wordpress/1014/">Plugin</a> directly in your WordPress</li>
<li><a  href="http://www.firephp.org/">FirePHP</a> &#8211; as <a  href="http://bueltge.de/firephp-und-wordpress/944/">Plugin</a> for WordPress to access specific content without crawling through your source code</li>
<li><a  href="http://jeffsayre.com/2010/04/29/introducing-wordpress-hook-sniffer-a-developer-plugin/">WordPress Hook Sniffer</a> &#8211; interest idea; bad is the replacing of the core-file plugin.php</li>
</ul>
<p>That should be enough, even there are many more for sure. The decisive factor, in my view are not the Plugins, but the environment with xDebug and the settings that WordPress offers as standard in this context. Therefore, I can only recommend to have the following lines in the <code>wp-config.php</code> of the environment.</p>
<div>
<div>
<pre class="brush: php;"><span>/** Debugging WP */</span>
<span>define</span><span>(</span><span>'WP_DEBUG'</span><span>,</span> <span>true</span><span>)</span><span>;</span> <span>//enable the reporting of notices during development - E_ALL</span>
<span>define</span><span>(</span><span>'WP_DEBUG_DISPLAY'</span><span>,</span> <span>true</span><span>)</span><span>;</span> <span>//use the globally configured setting for display_errors and not force errors to be displayed</span>
<span>define</span><span>(</span><span>'WP_DEBUG_LOG'</span><span>,</span> <span>true</span><span>)</span><span>;</span> <span>//error logging to wp-content/debug.log</span>
<span>define</span><span>(</span><span>'SCRIPT_DEBUG'</span><span>,</span> <span>true</span><span>)</span><span>;</span> <span>//loads the development (non-minified) versions of all scripts and CSS and disables compression and concatenation,</span>
<span>define</span><span>(</span><span>'E_DEPRECATED'</span><span>,</span> <span>false</span><span>)</span><span>;</span> <span>//E_ALL &amp; ~E_DEPRECATED &amp; ~E_STRICT</span>
 
<span>define</span><span>(</span><span>'AUTOSAVE_INTERVAL'</span><span>,</span> <span>'300'</span><span>)</span><span>;</span>    <span>// Autosave interval</span>
<span>define</span><span>(</span><span>'SAVEQUERIES'</span><span>,</span> <span>true</span><span>)</span><span>;</span>    <span>// Analyse queries</span>
<span>define</span><span>(</span><span>'WP_POST_REVISIONS'</span><span>,</span> <span>false</span><span>)</span><span>;</span></pre>
</div>
</div>
<p>These definitions make the work easily with WordPress and there are many indications of WP to have a clean code and current functions. I change the autosave interval only to small values, if I work in this segment, so if I need the script as soon as possible.</p>
<h4>Web Applications</h4>
<p>On the web there are a variety of tools that are useful &#8211; I&#8217;d like to briefly introduce some them I use often and also to say my thanks to the people who make these services available.</p>
<ul>
<li><a  href="http://de2.php.net/">php.net</a> &#8211; because you never get information fast enough, therefore I have in the Firefox Add-on an additional extension for the internal search field, which searches directly in the functions of php.net (<a  href="http://bueltge.de/test/searchplugins/phpnet.php">You can use it if you like to</a>)</li>
<li><a  href="http://bueltge.de/test/searchplugins/phpnet.php">wpseek.com</a> &#8211; the search for WordPress, also a search extension for Firefox is available</li>
<li><a  href="http://xref.yoast.com/">PHP Cross Reference of WordPress Source</a> &#8211; sometimes I&#8217;m faster with it than via editor</li>
</ul>
<h4>Conclusion</h4>
<p>A small overview of my latest tools and perhaps you find one of them useful or you have suggestions as well for me.</p>
<hr />
<h3>Related posts:</h3>
<ul>
<li><a  href="http://wpengineer.com/3rd-door-today-the-advice-dont-steal-premium-wordpress-themes/" rel="bookmark" title="Permanent Link: 3rd Door – Today The Advice: Don’t Steal Premium WordPress Themes">3rd Door – Today The Advice: Don’t Steal Premium WordPress Themes</a></li>
<li><a  href="http://wpengineer.com/yaml-31-released/" rel="bookmark" title="Permanent Link: YAML 3.1 Released">YAML 3.1 Released</a></li>
<li><a  href="http://wpengineer.com/quick-view-on-wordpress-settings/" rel="bookmark" title="Permanent Link: Quick View on WordPress Settings">Quick View on WordPress Settings</a></li>
<li><a  href="http://wpengineer.com/wp_page_menu-in-wordpress-27/" rel="bookmark" title="Permanent Link: wp_page_menu in WordPress 2.7">wp_page_menu in WordPress 2.7</a></li>
<li><a  href="http://wpengineer.com/a-chance-wordpress-plugin-competition/" rel="bookmark" title="Permanent Link: A Chance: WordPress Plugin Competition">A Chance: WordPress Plugin Competition</a></li>
</ul>
<hr />
<p><img src="http://wpengineer.com/favicon.ico" alt="WP Engineer Favicon" /> Thanks for subscribing our feed! <a  href="http://buysellads.com/buy/detail/3646/">Sponsor the WP Engineer Blog</a> and get your brand in front of several hundred users per day!<br /> © <a  href="http://wpengineer.com/">WP Engineer Team</a>, All rights reserved <small>(Digital Fingerprint: WPEngineer-be0254ce2b4972feb4b9cb72034a092d)</small></p>
</p>
<p><!--/content--></p>
]]></content:encoded>
			<wfw:commentRss>http://www.taiwangeek.com/2010-08/our-wordpress-developer-toolbox.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>WordPress Theme Frameworks: Options You Should Consider</title>
		<link>http://www.taiwangeek.com/2010-07/wordpress-theme-frameworks-options-you-should-consider.html</link>
		<comments>http://www.taiwangeek.com/2010-07/wordpress-theme-frameworks-options-you-should-consider.html#comments</comments>
		<pubDate>Fri, 16 Jul 2010 02:00:27 +0000</pubDate>
		<dc:creator>tung</dc:creator>
				<category><![CDATA[Google Reader]]></category>
		<category><![CDATA[application]]></category>
		<category><![CDATA[child]]></category>
		<category><![CDATA[imagination]]></category>
		<category><![CDATA[mind]]></category>
		<category><![CDATA[personal]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[repetitive]]></category>
		<category><![CDATA[search-engine]]></category>
		<category><![CDATA[time]]></category>

		<guid isPermaLink="false">http://www.taiwangeek.com/2010-07/wordpress-theme-frameworks-options-you-should-consider.html</guid>
		<description><![CDATA[ There is no doubt that WordPress is an awesome piece of open source application, and in addition, creating custom themes for it is very intuitive and relatively easy with the WordPress API. With that said, creating your own custom themes from scratch can be very time-consuming, with plenty of unnecessarily repetitive tasks]]></description>
			<content:encoded><![CDATA[<blockquote>
<p><img src="http://www.taiwangeek.com/wp-content/uploads/2010/07/1875c600ebld_img.jpg-150x54.jpg" /></p>
<p>View original post here:<br />
<a  target="_blank" href="http://feedproxy.google.com/~r/SixRevisions/~3/FUJa-Xi-vIE/" title="WordPress Theme Frameworks: Options You Should Consider">WordPress Theme Frameworks: Options You Should Consider</a>
</p></blockquote>
<p><!--/content--></p>
<p><a  href="http://sixrevisions.com/wordpress/wordpress-theme-frameworks-options-you-should-consider/"><img src="http://www.taiwangeek.com/wp-content/uploads/2010/07/1875c600ebld_img.jpg.jpg" width="550" height="200" alt="WordPress Theme Frameworks: Options You Should Consider" /></a></p>
<p>There is no doubt that <a  href="http://sixrevisions.com/category/wordpress/" title="WordPress category on Six Revisions - sixrevisions.com">WordPress</a> is  an awesome piece of open source application, and in addition, creating custom  themes for it is very intuitive and relatively easy with the WordPress API.</p>
<p>With that said, creating your own custom themes from scratch  can be very time-consuming, with plenty of unnecessarily repetitive tasks.</p>
<p><span></span></p>
<p>WordPress theme frameworks–which are themes that you can  use as a foundation for the creation of your own themes–can drastically boost  your performance and efficiency. </p>
<p>To help you learn  about WordPress theme frameworks and make your job as developer a bit easier,  we are going to review the best WordPress theme frameworks out there.</p>
<p>By the way, this article will not be covering WordPress theme  frameworks that don’t use the <a  href="http://www.gnu.org/licenses/gpl.html">General  Public License</a> that the WordPress core has, as this is the supported licensing  type of WordPress.</p>
<h3>Why Use a Framework?</h3>
<p>In a web developer’s life, a framework helps the speed of  production. Much like JavaScript frameworks like MooTools or jQuery, CSS  frameworks like the <a  href="http://sixrevisions.com/web_design/the-960-grid-system-made-easy/" title="The 960 Grid System Made Easy - sixrevisions.com">960 Grid System</a>, or  server-side scripting frameworks like <a  href="http://sixrevisions.com/web-development/getting-started-with-ruby-on-rails-installation/" title="Getting Started with Ruby on Rails: Installation">Ruby on Rails</a> or  CakePHP, WordPress theme frameworks achieve the same sort of efficiency,  reduction of errors through cross-browser compatibility, and the provision of  useful and common functions.</p>
<p>Let’s draw out the pros and cons of using WordPress theme frameworks.</p>
<h4>Pros</h4>
<ul>
<li>Time savings</li>
<li>Easier development</li>
<li>Support via communities built around the WordPress theme  frameworks</li>
<li>Typically has optimized CSS, HTML, PHP functions, and SEO</li>
<li>Typically has code that’s written with WordPress standards  and best practices</li>
<li>Ease of updating for future releases of WordPress</li>
</ul>
<h4>Cons</h4>
<p>A disadvantage of using frameworks is at the beginning,  where there is always going to  be a learning curve as you adopt new stuff to  your development workflow. Though the learning time is relatively short compared  to, for example, a new server-side scripting language, you will still have to  account for this time when considering the use of WordPress theme frameworks.</p>
<p>However, the best way to look at using any web development  framework is that it will be a long-term investment. The time you spend  learning the technology at the start pays off in the end in terms of  development speed and efficiency.</p>
<p>Another possible disadvantage is that themes built on top of  frameworks, depending on the skill of the web developer, could be slower in  performance than building themes from scratch, since all frameworks, not just  WordPress theme frameworks, <a  href="http://en.wikipedia.org/wiki/Software_framework" title="Software framework - en.wikipedia.org">provide an additional abstraction  layer</a>.</p>
<h3>The Concept of Child Themes</h3>
<p>Before we start reviewing each framework, it’s important  that all of us understand what child themes are in the context of WordPress.</p>
<p>WordPress, by default, supports <a  href="http://codex.wordpress.org/Child_Themes" title="Child Themes - codex.wordpress.org">child themes</a>. Child themes look  exactly like their parent themes, unless you make modifications to them. Child  themes inherit all the templates, functions, and CSS of parent themes. This compartmentalizes  variations so that you can make changes without affecting the integrity of the  parent theme.</p>
<p>A child theme is usually contained in a folder having a <code>styles.css</code>  (required) and a <code>functions.php</code> file. <code>functions.php</code> is not mandatory, but  you will need it if you want to include some custom functions on top of your  parent theme (which, in this scenario, is the WordPress theme framework). Both  the child theme and parent theme folders will be in the <code>themes</code> directory  of your <a  href="http://sixrevisions.com/tutorials/web-development-tutorials/using-xampp-for-local-wordpress-theme-development/" title="Using XAMPP for Local WordPress Theme Development - sixrevisions.com">WordPress  installation</a>. You can override the inherited traits from its parent by  modifying its own <code>styles.css</code> and <code>functions.php</code> files.</p>
<p>Here is how you declare a child theme (this goes inside  <code>styles.css</code>, at the top).</p>
<pre class="brush: php;">/*  
Theme Name: Child Theme
Theme URI: http://sixrevisions.com
Description: A child theme description.
Author: Saad Bassi
Author URI: http://addictivefonts.com/
<strong>Template: My Framework</strong> (e.g thematic or Hybrid)
Version: 1.0
Tags: theme
*/</pre>
<p>The <code>Template</code> attribute above instructs the WordPress  core to inherit all the templates of &#8220;My Framework,&#8221; which is the name  of the parent theme in our hypothetical scenario.</p>
<h3>WordPress Theme Frameworks</h3>
<p>Now let’s review the five best WordPress theme frameworks  that you should consider if you are planning to take advantage of them. </p>
<h4>1. <a  href="http://themehybrid.com/">ThemeHybrid</a></h4>
<p><img src="http://www.taiwangeek.com/wp-content/uploads/2010/07/540c6504b2hybrid.jpg.jpg" width="550" height="256" alt="ThemeHybrid" /></p>
<p>ThemeHybrid is a popular, free framework developed by the  equally popular WordPress developer, <a  href="http://justintadlock.com/">Justin  Tadlock</a>.</p>
<p>ThemeHybrid is free, but to get support on its forums, you need  to sign up for an Exclusive Membership to their Theme Club, which is $25 per year.</p>
<p>With a massive community, you will never get stuck on an  issue. ThemeHybrid has many child themes available for download on its website,  which you can use to give your WordPress installation a new look without much  coding.</p>
<p><img src="http://www.taiwangeek.com/wp-content/uploads/2010/07/e359b3833fd_demo.jpg.jpg" width="550" height="306" alt="ThemeHybrid" /></p>
<p>ThemeHybrid comes with plenty of WordPress widgets and page  templates.</p>
<p>Want to extend the framework? Sky’s the limit and your only real limitation  is your imagination (and WordPress theme development skills, of course).</p>
<p>While many people say that frameworks are bloated and slow, ThemeHybrid  will change their mind as it is lightning fast and optimized for high performance.</p>
<p><img src="http://www.taiwangeek.com/wp-content/uploads/2010/07/38af131579widget.jpg.jpg" width="550" height="296" alt="ThemeHybrid" /></p>
<h4>2. <a  href="http://themeshaper.com/">Thematic</a></h4>
<p><img src="http://www.taiwangeek.com/wp-content/uploads/2010/07/617d86dae8shaper.jpg.jpg" width="550" height="305" alt="Thematic" /></p>
<p>Thematic is a theme framework by WordPress theme developer, <a  href="http://twitter.com/iandstewart">Ian Stewart</a>. Thematic is completely  free; from forums to child themes, everything is free!</p>
<p>Though the documentation of this theme is not as comprehensive  as ThemeHybrid, you can get insightful tips and tricks from its forum.</p>
<p><img src="http://www.taiwangeek.com/wp-content/uploads/2010/07/3cab10df65c_demo.jpg.jpg" width="550" height="298" alt="Thematic" /></p>
<p>Thematic has 13 widget areas that are more than enough for most  of your needs. With the WordPress theme framework’s many filters and actions,  you can customize your child theme in any way that you want. Its out-of-the-box simple  and clean look can even be used without any aesthetical modifications–and it  will still look great.</p>
<h4>3. <a  href="http://www.woothemes.com/amember/go.php?r=26050&#038;i=l64">Canvas</a></h4>
<p><img src="http://www.taiwangeek.com/wp-content/uploads/2010/07/3cf8cf761ds_demo.jpg.jpg" width="550" height="315" alt="Canvas" /></p>
<p>Canvas is a <a  href="http://sixrevisions.com/wordpress/a-guide-to-premium-wordpress-themes/" title="A Guide to Premium WordPress Themes - sixrevisions.com">premium theme</a> framework from WooThemes. As to be expected with any WooThemes product, it has a  huge number of options and customization features.</p>
<p>Canvas is best for novice developers and those that don’t  want to be bogged down by the ins and outs of coding, but still want to take  advantage of the many benefits of using a theme framework.</p>
<p>You can style each element of Canvas differently from its  Theme Options panel. The theme framework supports child themes and also has 5  built-in page templates for your home page, including a magazine-style layout and  a business site template.</p>
<p>Canvas also supports 6 CSS layouts for your blog and even  provides you an option for choosing distinctive layouts for each post and page.</p>
<p>If you are a web designer that doesn’t want to mess with  code too much, Canvas should be your pick. To witness the real power of Canvas,  watch this <a  href="http://screenr.com/gFM">video</a>.</p>
<p><img src="http://www.taiwangeek.com/wp-content/uploads/2010/07/7fa021b758ackend.jpg.jpg" width="550" height="345" alt="Canvas" /></p>
<h4>4. <a  href="http://www.studiopress.com/themes/genesis">Genesis</a></h4>
<p><img src="http://www.taiwangeek.com/wp-content/uploads/2010/07/77a50c7a4es_demo.jpg.jpg" width="550" height="271" alt="Genesis" /></p>
<p>Genesis is a premium theme framework that was built by StudioPress.  Genesis has a child theme marketplace where you can buy all additional child  themes. Genesis has native support for search engine optimization (which it  focuses on). You can set all the options in the Genesis backend panel, just like  with most good WordPress theme frameworks.</p>
<p><img src="http://www.taiwangeek.com/wp-content/uploads/2010/07/efd0febd08ptions.jpg.jpg" width="550" height="306" alt="Genesis" /></p>
<p>Similar to the Canvas WordPress theme framework, Genesis  gives you the option to select separate layouts for each post and page. Genesis  is intended for developers, as opposed to designers, because you will have to  learn its hooks and filters before getting started with it, and thus,  will need  some  coding proficiency.</p>
<h4>5. <a  href="http://prothemedesign.com/themes/elemental/">Elemental</a></h4>
<p><img src="http://www.taiwangeek.com/wp-content/uploads/2010/07/87916e480cmental.jpg.jpg" width="550" height="303" alt="Genesis" /></p>
<p>Elemental is a product of ProThemeDesign. One of its unique  features is that it comes bundled with an admin menu bar that stays on top of  your WordPress web pages if you are logged in. The admin menu bar allows you to  go to the most common places inside the WordPress admin dashboard. The  framework comes with 12 page templates and 7 custom widgets by default.</p>
<p><img src="http://www.taiwangeek.com/wp-content/uploads/2010/07/4f3ffef5d7ackend.jpg.jpg" width="550" height="275" alt="Genesis" /></p>
<h3>Conclusion</h3>
<p>After reviewing these five WordPress theme frameworks, I  pick ThemeHybrid as my personal choice–the helpful community coupled with the  excellent set of features make it a clear winner in <em>my</em> book.</p>
<p>For WordPress themers just starting out and those that would  like to take advantage of WordPress theme frameworks without being bogged down  by code, I highly recommend you to go for Canvas, which allows you to modify  everything right from the Theme Options panel.</p>
<p><img src="http://www.taiwangeek.com/wp-content/uploads/2010/07/ada06b3548ptions.jpg.jpg" width="550" height="579" alt="Genesis" /></p>
<p>The other three frameworks are also awesome, and the final  selection will depend upon your needs and tastes (and, hopefully, this guide  will have made making that decision easier for you).</p>
<h3>Related Content</h3>
<ul>
<li><a  href="http://sixrevisions.com/wordpress/wordpress-3-0-guide/">WordPress 3.0:  Ultimate Guide to New Features</a></li>
<li><a  href="http://sixrevisions.com/resources/50-beautiful-free-wordpress-themes/">50  Beautiful Free WordPress Themes</a></li>
<li><a  href="http://sixrevisions.com/wordpress/optimizing-wordpress-for-search-engines/">Optimizing  WordPress for Search Engines</a></li>
<li><em>Related categories</em>: <a  href="http://sixrevisions.com/category/wordpress/">WordPress</a> and <a  href="http://sixrevisions.com/category/web-development/">Web Development</a></li>
</ul>
<h3>About the Author</h3>
<p><img src="http://www.taiwangeek.com/wp-content/uploads/2010/07/4e2e2509c4small.jpg.jpg" alt="" width="80" height="80" /><strong>Saad Bassi</strong> is a 20-year-old web developer from Pakistan. He is the Co-Editor at <a  href="http://www.crispytech.com/">CrispyTech</a>, and blogs about Windows at <a  href="http://www.windows8geek.com/">Windows8Geek</a>. Don’t forget to give him a &#8220;hello&#8221; on <a  href="http://www.twitter.com/saadbassi">Twitter</a>. Last but not least, make sure that you check out hist latest project, <a  href="http://addictivefonts.com">Addictive Fonts</a> which focuses on free high quality font downloads.</p>
<div>
<a  href="http://feeds.feedburner.com/~ff/SixRevisions?a=FUJa-Xi-vIE:IB6DvBqODzg:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/SixRevisions?i=FUJa-Xi-vIE:IB6DvBqODzg:V_sGLiPBpWU" border="0" /></a> <a  href="http://feeds.feedburner.com/~ff/SixRevisions?a=FUJa-Xi-vIE:IB6DvBqODzg:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/SixRevisions?d=yIl2AUoC8zA" border="0" /></a> <a  href="http://feeds.feedburner.com/~ff/SixRevisions?a=FUJa-Xi-vIE:IB6DvBqODzg:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/SixRevisions?d=qj6IDK7rITs" border="0" /></a> <a  href="http://feeds.feedburner.com/~ff/SixRevisions?a=FUJa-Xi-vIE:IB6DvBqODzg:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/SixRevisions?i=FUJa-Xi-vIE:IB6DvBqODzg:gIN9vFwOqvQ" border="0" /></a> <a  href="http://feeds.feedburner.com/~ff/SixRevisions?a=FUJa-Xi-vIE:IB6DvBqODzg:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/SixRevisions?d=7Q72WNTAKBA" border="0" /></a>
</div>
<p><img src="http://feeds.feedburner.com/~r/SixRevisions/~4/FUJa-Xi-vIE" height="1" width="1" /><br />
<!--/content--></p>
]]></content:encoded>
			<wfw:commentRss>http://www.taiwangeek.com/2010-07/wordpress-theme-frameworks-options-you-should-consider.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Photo</title>
		<link>http://www.taiwangeek.com/2010-07/photo.html</link>
		<comments>http://www.taiwangeek.com/2010-07/photo.html#comments</comments>
		<pubDate>Sat, 10 Jul 2010 23:02:42 +0000</pubDate>
		<dc:creator>tung</dc:creator>
				<category><![CDATA[Google Reader]]></category>

		<guid isPermaLink="false">http://www.taiwangeek.com/2010-07/photo.html</guid>
		<description><![CDATA[ ]]></description>
			<content:encoded><![CDATA[<blockquote>
<p><img src="http://www.taiwangeek.com/wp-content/uploads/2010/07/28f49c9589o1_500.jpg-84x150.jpg" /></p>
<p>Excerpt from:<br />
<a  target="_blank" href="http://feedproxy.google.com/~r/Papertissue/~3/tvALkZMHHtY/796882191" title="Photo">Photo</a>
</p></blockquote>
<p><!--/content--><br />
<img src="http://www.taiwangeek.com/wp-content/uploads/2010/07/28f49c9589o1_500.jpg.jpg" /></p>
<p><img src="http://feeds.feedburner.com/~r/Papertissue/~4/tvALkZMHHtY" height="1" width="1" /><br />
<!--/content--></p>
]]></content:encoded>
			<wfw:commentRss>http://www.taiwangeek.com/2010-07/photo.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Top 10 YouTube Videos About Your Web Interface</title>
		<link>http://www.taiwangeek.com/2010-07/top-10-youtube-videos-about-your-web-interface.html</link>
		<comments>http://www.taiwangeek.com/2010-07/top-10-youtube-videos-about-your-web-interface.html#comments</comments>
		<pubDate>Sat, 10 Jul 2010 17:10:10 +0000</pubDate>
		<dc:creator>tung</dc:creator>
				<category><![CDATA[Google Reader]]></category>
		<category><![CDATA[collection]]></category>
		<category><![CDATA[contributions]]></category>
		<category><![CDATA[future]]></category>
		<category><![CDATA[graphical]]></category>
		<category><![CDATA[hyposurface]]></category>
		<category><![CDATA[innovation]]></category>
		<category><![CDATA[iphones]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[lists]]></category>
		<category><![CDATA[microsoft]]></category>
		<category><![CDATA[radio]]></category>
		<category><![CDATA[result]]></category>
		<category><![CDATA[touch-screen]]></category>

		<guid isPermaLink="false">http://www.taiwangeek.com/2010-07/top-10-youtube-videos-about-your-web-interface.html</guid>
		<description><![CDATA[ The graphical user interface or GUI shapes and defines how we interact with the Web. ]]></description>
			<content:encoded><![CDATA[<blockquote>
<p><img src="http://www.taiwangeek.com/wp-content/uploads/2010/07/8710d3e6b9e_logo.jpg.jpg" /></p>
<p>View original post here:<br />
<a  target="_blank" href="http://feedproxy.google.com/~r/readwriteweb/~3/1Wgxl6fdNTI/top_10_youtube_videos_about_how_you_interface_with.php" title="Top 10 YouTube Videos About Your Web Interface">Top 10 YouTube Videos About Your Web Interface</a>
</p></blockquote>
<p><!--/content--></p>
<p><img alt="youtube_logo.jpg" src="http://www.taiwangeek.com/wp-content/uploads/2010/07/8710d3e6b9e_logo.jpg.jpg" width="150" height="112" />The graphical user interface or <a  href="http://en.wikipedia.org/wiki/GUI">GUI</a> shapes and defines how we interact with the Web. These YouTube videos on GUI innovation can guide us to a more fluid and natural way to interact with not just the web, but with computers in general. </p>
<p>There are no <a  href="http://www.readwriteweb.com/tag/ipad">iPads</a> or <a  href="http://www.readwriteweb.com/tag/iphone">iPhones</a> in this collection. Their groundbreaking contributions to GUI have been noted on our site <a  href="http://www.readwriteweb.com/archives/ipad_nexus_one_best_of_the_web_2010.php">often</a>. Instead, our choices for the best YouTube videos in GUI include a Perceptive Pixel demo, 10 finger multi-touch, Microsoft Surface, a popular Linux interface and 3D touch display. Also of note is <a  href="http://www.hyposurface.org/">Hyposurface</a>, which is a screen made out of physically movable pixels.</p>
<p align="right"><em>Sponsor</em><br /><a  href="http://d.ads.readwriteweb.com/ck.php?n=20518&#038;cb=20518"><img src="http://d.ads.readwriteweb.com/avw.php?zoneid=14&#038;cb=20518&#038;n=20518" border="0" alt="" /></a></p>
<p>If you have any favorite videos about GUI that we didn&#8217;t choose, please let us know about them in the comments below.</p>
<ol>
<p>
<li>
<h2>Microsoft Surface Demo @ CES 2008</h2>
</li>
<p>
1,448,802 views
 </p>
<p></p>
<li>
<h2>Perceptive pixel</h2>
</li>
<p>
294,342 views
</p>
<p></p>
<li>
<h2>GNU/LINUX UBUNTU 7.04 Feisty Fawn</h2>
</li>
<p>
286,200 views
</p>
<p></p>
<li>
<h2>CES 2009: Intel 3D Touch-screen Display</h2>
</li>
<p>
90,822 views
</p>
<p></p>
<li>
<h2>The world of Graphical User Interface.. me inside computer </h2>
</li>
<p>
78,956 views
</p>
<p></p>
<li>
<h2>BLUI: Blowable user interface</h2>
</li>
<p>
71,272 views
</p>
<p></p>
<li>
<h2>New technology of Korean touchpad</h2>
</li>
<p>
43,989 views
</p>
<p></p>
<li>
<h2>10/GUI &#8211; 10 Finger Multitouch User Interface</h2>
</li>
<p>
36,057 views
</p>
<p></p>
<li>
<h2>Office of the Future</h2>
</li>
<p>
29,094 views
</p>
<p></p>
<li>
<h2>Hyposurface on WBZ Radio</h2>
</li>
<p>
13,435 views
 </p>
</ol>
<p><strong><a  href="http://www.readwriteweb.com/archives/top_10_youtube_videos_about_how_you_interface_with.php#comments-open">Discuss</a></strong>
</p>
<div>
<a  href="http://feeds.feedburner.com/~ff/readwriteweb?a=1Wgxl6fdNTI:SmFNXbei5BI:FFnlKYwJmN0"><img src="http://feeds.feedburner.com/~ff/readwriteweb?d=FFnlKYwJmN0" border="0" /></a> <a  href="http://feeds.feedburner.com/~ff/readwriteweb?a=1Wgxl6fdNTI:SmFNXbei5BI:Ij26kaj3iuU"><img src="http://feeds.feedburner.com/~ff/readwriteweb?d=Ij26kaj3iuU" border="0" /></a> <a  href="http://feeds.feedburner.com/~ff/readwriteweb?a=1Wgxl6fdNTI:SmFNXbei5BI:C2pbw5bZMiI"><img src="http://feeds.feedburner.com/~ff/readwriteweb?d=C2pbw5bZMiI" border="0" /></a> <a  href="http://feeds.feedburner.com/~ff/readwriteweb?a=1Wgxl6fdNTI:SmFNXbei5BI:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/readwriteweb?d=yIl2AUoC8zA" border="0" /></a> <a  href="http://feeds.feedburner.com/~ff/readwriteweb?a=1Wgxl6fdNTI:SmFNXbei5BI:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/readwriteweb?i=1Wgxl6fdNTI:SmFNXbei5BI:V_sGLiPBpWU" border="0" /></a> <a  href="http://feeds.feedburner.com/~ff/readwriteweb?a=1Wgxl6fdNTI:SmFNXbei5BI:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/readwriteweb?i=1Wgxl6fdNTI:SmFNXbei5BI:gIN9vFwOqvQ" border="0" /></a> <a  href="http://feeds.feedburner.com/~ff/readwriteweb?a=1Wgxl6fdNTI:SmFNXbei5BI:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/readwriteweb?i=1Wgxl6fdNTI:SmFNXbei5BI:F7zBnMyn0Lo" border="0" /></a> <a  href="http://feeds.feedburner.com/~ff/readwriteweb?a=1Wgxl6fdNTI:SmFNXbei5BI:OqabYuBsmOY"><img src="http://feeds.feedburner.com/~ff/readwriteweb?d=OqabYuBsmOY" border="0" /></a>
</div>
<p><img src="http://feeds.feedburner.com/~r/readwriteweb/~4/1Wgxl6fdNTI" height="1" width="1" /><br />
<!--/content--></p>
]]></content:encoded>
			<wfw:commentRss>http://www.taiwangeek.com/2010-07/top-10-youtube-videos-about-your-web-interface.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Introducing WordPress 3 Custom Taxonomies</title>
		<link>http://www.taiwangeek.com/2010-07/introducing-wordpress-3-custom-taxonomies.html</link>
		<comments>http://www.taiwangeek.com/2010-07/introducing-wordpress-3-custom-taxonomies.html#comments</comments>
		<pubDate>Tue, 06 Jul 2010 11:29:40 +0000</pubDate>
		<dc:creator>tung</dc:creator>
				<category><![CDATA[Google Reader]]></category>
		<category><![CDATA[archives]]></category>
		<category><![CDATA[classification]]></category>
		<category><![CDATA[classifications]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[computers]]></category>
		<category><![CDATA[data]]></category>
		<category><![CDATA[database]]></category>
		<category><![CDATA[desktop]]></category>
		<category><![CDATA[function]]></category>
		<category><![CDATA[languages]]></category>
		<category><![CDATA[normal]]></category>
		<category><![CDATA[operating-systems]]></category>
		<category><![CDATA[taxonomies]]></category>
		<category><![CDATA[time]]></category>
		<category><![CDATA[tutorial]]></category>

		<guid isPermaLink="false">http://www.taiwangeek.com/2010-07/introducing-wordpress-3-custom-taxonomies.html</guid>
		<description><![CDATA[ Shared by &#23567;&#33891; 滿適合拿來作商品屬性的~~ WordPress 3 fills in a number of important gaps towards being a serious content management system. The easy-to-use custom taxonomies function gives site designers some powerful tools for building a good information architecture. Learn what taxonomies are, why they’re useful, and how to use them in today’s tutorial! What is a Taxonomy? ]]></description>
			<content:encoded><![CDATA[<blockquote>
<p><img src="http://www.taiwangeek.com/wp-content/uploads/2010/07/ce0d841db0xample.png-150x144.png" /></p>
<p>Continue reading here:<br />
<a  target="_blank" href="http://feedproxy.google.com/~r/nettuts/~3/dKgVcNaVUcU/" title="Introducing WordPress 3 Custom Taxonomies">Introducing WordPress 3 Custom Taxonomies</a>
</p></blockquote>
<p><!--/content--></p>
<blockquote><p>Shared by  &#23567;&#33891;<br />
<br />
滿適合拿來作商品屬性的~~</p></blockquote>
<p>WordPress 3 fills in a number of important gaps towards being a serious content management system. The easy-to-use custom taxonomies function gives site designers some powerful tools for building a good information architecture. Learn what taxonomies are, why they’re useful, and how to use them in today’s tutorial!</p>
<p><span></span></p>
<hr />
<h2>What is a Taxonomy?</h2>
<blockquote><p>Taxonomies are different methods for classifying things.</p>
</blockquote>
<p>Taxonomies are different methods for classifying things. This tutorial uses an example of posts about different desktop computers, which can be classified by a number of distinct criteria, including:</p>
<ul>
<li>Amount of RAM</li>
<li>Size of hard drive</li>
<li>Speed of CPU</li>
<li>Type of CPU</li>
<li>Operating system installed</li>
<li>and so forth…</li>
</ul>
<hr />
<h2>A Brief History of WordPress Taxonomies</h2>
<h3>Categories</h3>
<div>
<img src="http://www.taiwangeek.com/wp-content/uploads/2010/07/ce0d841db0xample.png.png" alt="Category Example" />
</div>
<p>Prior to version 2.3, WordPress had only one generic taxonomy, called Category, for Posts. This worked well for blogs, as you could create a top-level category called “Desktop Computers,” with a subcategory called “RAM,” which may have subcategories such as “Less than 1 GB,” “1 GB,” “2 GB to 4GB,” and so on. A second child category of “Desktop Computers” might be called “Operating System,” with subcategories such as “Windows XP,” “Mac OS,” “Red Hat,” “Ubuntu,” and so forth.</p>
<p>When a system allows you to have categories that can be divided into subcategories, we call it a hierarchical structure. The best you could do for a serious site architecture prior to WordPress version 2.3 was to create a large hierarchy of categories, where the top level categories represented large taxonomy groups.</p>
<h3>Tags</h3>
<div>
<img src="http://www.taiwangeek.com/wp-content/uploads/2010/07/feb16374cexample.png.png" alt="Tags Example" />
</div>
<p>Version 2.3 of WordPress added another type of taxonomy called Tags. While categories are usually thought out in advance, specific to the types of content on a site, tags provide a more freeform, impromptu method of classifying content.</p>
<p>For instance, when writing a Post about a particular desktop computer, tags allow the author to type one or more keywords such as “gaming,” “tivo,” “noisy fan,” and so forth. These keywords might not make sense as site-wide categories, but help provide some additional classification to a post. Site visitors could then easily find all the posts tagged with “noisy fan” later. The freeform nature of tags, however, doesn’t help us build a solid classification system around known values such as operating system types or CPU types. Tags are also one-dimensional, not allowing any hierarchical structure.</p>
<h3>Single-Level Custom Taxonomies</h3>
<div>
<img src="http://www.taiwangeek.com/wp-content/uploads/2010/07/73a7d3c637tax-1d.png.png" alt="Single-Level Custom Taxonomies" />
</div>
<p>WordPress version 2.8 made it possible to add custom classification schemes with just a few changes to the code on your site. This allowed you to build a list of possible operating systems, separate from a list of possible RAM types, and so on. It did not, however, allow these custom taxonomies to be built in a hierarchy similar to the generic categories taxonomy.</p>
<h3>Fully Hierarchical Custom Taxonomies</h3>
<div>
<img src="http://www.taiwangeek.com/wp-content/uploads/2010/07/0c26346731tax-2d.png.png" alt="Fully Hierarchical Custom Taxonomies" />
</div>
<p>Finally, WordPress version 3 gives us fully hierarchical custom taxonomies. Notice how the hierarchical nature allows us to simplify the Operating System taxonomy, for instance, by pushing all the different Windows variants under a “Windows” parent classification. This will allow visitors to see all posts classified with any Windows operating system, or allow them to be more specific and see only posts classified with Windows XP, for instance.</p>
<hr />
<h2>Creating a Custom Taxonomy</h2>
<h3>Editing your theme’s functions.php file</h3>
<p>WordPress version 3 does not allow you to create custom taxonomies from the administration screen. To initially define your custom taxonomies without a plugin, you’ll need to add a little bit of code to your theme’s functions.php file. This isn’t too difficult — just follow my lead.</p>
<p>To add custom taxonomies, we need to edit the “functions.php” file found inside your theme directory. For instance, I’m using the default “twentyten” theme that comes with WordPress 3.0, and my WordPress installation is in a directory named “wp.” My functions.php file is then at:<br />
website_root/wp/wp-content/themes/twentyten/functions.php.</p>
<hr />
<h2>Adding the Taxonomies in Code</h2>
<p>We’ll stick with the Desktop Computer example, adding separate taxonomies for RAM, Hard Drive, and Operating System. At this point, we’re simply adding the taxonomies themselves, like empty containers. Fortunately, we can add and manage the different classifications, such as “Windows XP,” from the comfort of the admin dashboard.
</p>
<hr />
<h2><span>Step 1</span> One Function to Create Them All</h2>
<p>First, we need to build one function that creates all the taxonomies we need. We’ll call the function “build_taxonomies.” Let’s add this function to the bottom of the functions.php file.</p>
<pre class="brush:php;">function build_taxonomies()
    // code will go here
</pre>
<hr />
<h2><span>Step 2</span> Defining the Taxonomies</h2>
<p>Next, for each taxonomy we want to create, we need to call a particular WordPress function with the right parameters. Here’s the function, and its important parameters explained.</p>
<pre class="brush:php;">register_taxonomy(
	&#39;internal_name&#39;,
	&#39;object_type&#39;,
	array(
		&#39;hierarchical&#39; => true,
		&#39;label&#39; => &#39;Human Readable Name&#39;,
		&#39;query_var&#39; => true,
		&#39;rewrite&#39; => true
	)
);
</pre>
<ul>
<li><strong>internal_name:</strong> What will this taxonomy be called from inside WordPress, in the database and template files?</li>
<li><strong>object_type:</strong> Which types of content can be classified with this taxonomy? Possible values are “post, page, link,” and then names of custom post types we’ll learn to create in a future tutorial.</li>
<li>Next comes an array of optional parameters. We’ll use the most important ones here in this tutorial, but a full list can be found on the Function Reference / register_taxonomy Codex page. The parameters we’ll use are:</li>
<li><strong>hierarchical</strong>: If ‘true,’ this taxonomy has hierarchical abilities like WordPress Categories. If ‘false,’ this taxonomy behaves much like freeform Tags.</li>
<li><strong>label:</strong> This is the human-readable name used in your site’s interface to label the taxonomy.</li>
<li><strong>query_var:</strong> If ‘true,’ we’ll be able to ask WordPress for posts dependent upon the selections for this taxonomy. For example, we could search for all the posts where the operating system taxonomy has ‘Windows’ selected.</li>
<li><strong>rewrite:</strong> If ‘true,’ WordPress will use friendly URL’s when viewing a page for this taxonomy. For example, a page listing all the posts with the “Windows” operating system selected would be represented by the following url: http://domain.com/operating_system/windows</li>
</ul>
<p>Our entry specific to adding the Operating System taxonomy looks like so:</p>
<pre class="brush:php;">register_taxonomy( &#39;operating_system&#39;, &#39;post&#39;, array( &#39;hierarchical&#39; => true, &#39;label&#39; => &#39;Operating System&#39;, &#39;query_var&#39; => true, &#39;rewrite&#39; => true ) );
</pre>
<p>Go ahead and add that to your “build_taxonomies” function.</p>
<h3>More information:</h3>
<p><a  href="http://codex.wordpress.org/Function_Reference/register_taxonomy">“register_taxonomy” is further defined within the WordPress codex.</a> </p>
<hr />
<h2><span>Step 3</span> Calling the Taxonomy-Creating Function</h2>
<p>We need to add one more line to the “functions.php” file so our “build_taxonomies” function will actually be executed. We’ll “hook” the “build_taxonomies” function to the “init” event by adding the following code:</p>
<pre class="brush:php;">add_action( 'init', 'build_taxonomies', 0 );
</pre>
<p>You can add this line anywhere, but I generally add it above the function we’re calling, so it would look like this:</p>
<pre class="brush:php;">// Custom Taxonomy Code
add_action( &#39;init&#39;, &#39;build_taxonomies&#39;, 0 );

function build_taxonomies()
    register_taxonomy( &#39;operating_system&#39;, &#39;post&#39;, array( &#39;hierarchical&#39; => true, &#39;label&#39; => &#39;Operating System&#39;, &#39;query_var&#39; => true, &#39;rewrite&#39; => true ) );
</pre>
<h3>More information:</h3>
<p><a  href="http://codex.wordpress.org/Function_Reference/add_action">Learn more about add_action</a>.</p>
<hr />
<h2>Adding Classifications to the New Taxonomy</h2>
<div>
<img src="http://www.taiwangeek.com/wp-content/uploads/2010/07/c9498e8396posts.png.png" alt="Viewing taxonomy classifications" />
</div>
<p>Once you’ve added the “Operating System” taxonomy to the “functions.php” file correctly, it should show up as a new item in the “Posts” panel of your dashboard. Click the taxonomy’s name to add and edit the classifications you want to include.</p>
<div>
<img src="http://www.taiwangeek.com/wp-content/uploads/2010/07/98d0ce9469ries-b.png.png" alt="Adding taxonomy classifications" />
</div>
<p>Now, you can add and edit Operating Systems just as you would add generic Categories.
</p>
<hr />
<h2>Adding More Taxonomies</h2>
<p>If you want to add the “RAM” and “Hard Drive” taxonomies to follow along with the example, just add the following to your functions.php file:</p>
<pre class="brush:php;">register_taxonomy( &#39;ram&#39;, &#39;post&#39;, array( &#39;hierarchical&#39; => true, &#39;label&#39; => &#39;RAM&#39;, &#39;query_var&#39; => true, &#39;rewrite&#39; => true ) );
register_taxonomy( &#39;hard_drive&#39;, &#39;post&#39;, array( &#39;hierarchical&#39; => true, &#39;label&#39; => &#39;Hard Drive&#39;, &#39;query_var&#39; => true, &#39;rewrite&#39; => true ) );
</pre>
<p>Once finished, the changed section of your functions.php file will look something like this:</p>
<pre class="brush:php;">// Custom Taxonomy Code
add_action( &#39;init&#39;, &#39;build_taxonomies&#39;, 0 );

function build_taxonomies()
register_taxonomy( &#39;operating_system&#39;, &#39;post&#39;, array( &#39;hierarchical&#39; => true, &#39;label&#39; => &#39;Operating System&#39;, &#39;query_var&#39; => true, &#39;rewrite&#39; => true ) );
register_taxonomy( &#39;ram&#39;, &#39;post&#39;, array( &#39;hierarchical&#39; => true, &#39;label&#39; => &#39;RAM&#39;, &#39;query_var&#39; => true, &#39;rewrite&#39; => true ) );
register_taxonomy( &#39;hard_drive&#39;, &#39;post&#39;, array( &#39;hierarchical&#39; => true, &#39;label&#39; => &#39;Hard Drive&#39;, &#39;query_var&#39; => true, &#39;rewrite&#39; => true ) );
</pre>
<hr />
<h2>Creating a Post Using your New Taxonomy</h2>
<div>
<img src="http://www.taiwangeek.com/wp-content/uploads/2010/07/1f8c411bc7w-post.png.png" alt="Creating post with classifications" />
</div>
<p>Create a few new posts, and you’ll see your new taxonomy options appear in the Edit Post screen. Select whatever classifications you feel apply to your posts.</p>
<hr />
<h2>Showing a Post’s Various Taxonomies</h2>
<p>Nothing we’ve done so far can be seen by your site visitors. We’d like for posts to show what custom taxonomies they’re classified in, just like posts commonly reveal their categories and tags.</p>
<p>To do so, we only need to make a simple addition to the loop in certain template files.</p>
<hr />
<h2>Displaying Taxonomy Classifications on Individual Pages</h2>
<p>In the twentyten theme, and many others, a post’s categories and tags are listed below the body text. We’re going to add custom taxonomy information, if it exists, just before the category and tag information.</p>
<div>
<img src="http://www.taiwangeek.com/wp-content/uploads/2010/07/bc4df6043areshow.png.png" alt="Taxonomy info on single posts" />
</div>
<p>To make this happen, we’ll need to edit the “single.php” template file, which is normally called to display an individual post. My single.php file is at: website_root/wp/wp-content/themes/twentyten/single.php.</p>
<hr />
<h2><span>Step 1</span> Find the Right Place to Add Code</h2>
<p>In single.php, find the line with:
</p>
<pre class="brush:php;">
<div class="entry-utility"></div>
</pre>
<p>This appears just before the:
</p>
<pre class="brush:php;">
<div id="nav-below"></div>
</pre>
<p> In twentyten, this div contains the categories, tags, permalink, and other data for the current post. We’ll put our taxonomy information just above this div.</p>
<hr />
<h2><span>Step 2</span> Retrieve Taxonomy Information About the Current Post</h2>
<p>Populate some variables for holding the taxonomy information output and the different taxonomy information we may expect to find.</p>
<pre class="brush:php;">< ?php
// Let&#39;s find out if we have taxonomy information to display
// Something to build our output in
$taxo_text = "";

// Variables to store each of our possible taxonomy lists
// This one checks for an Operating System classification
$os_list = get_the_term_list( $post->ID, &#39;operating_system&#39;, &#39;<strong>Operating System(s):</strong> &#39;, &#39;, &#39;, &#39;&#39; );
</pre>
<p>Here, we’re calling the WordPress function “get_the_term” list with the following parameters:</p>
<ul>
<li><strong>$post->ID</strong> : the id of the current post.</li>
<li><strong>‘operating_system’</strong> : the name of the custom taxonomy we’re checking for data. We’re asking if the current post has been given any classifications in the ‘operating_system’ taxonomy.</li>
<li><strong>‘Operating System(s)’</strong> : If anything is returned, this is the string we’d like to have in front of it.</li>
<li><strong>‘, ‘</strong> : If multiple items are returned, this is the string we’d like to have them separated by.</li>
<li><strong>”</strong> : If anything is returned, this is the string we’d like to have behind it. In this case, we want nothing added behind the result.</li>
</ul>
<p>We’ll do the same for the other two taxonomies we might expect to contain data:</p>
<pre class="brush:php;">$ram_list = get_the_term_list( $post->ID, &#39;ram&#39;, &#39;<strong>RAM Option(s):</strong> &#39;, &#39;, &#39;, &#39;&#39; );
$hd_list = get_the_term_list( $post->ID, &#39;hard_drive&#39;, &#39;<strong>Hard Drive Option(s):</strong> &#39;, &#39;, &#39;, &#39;&#39; );
</pre>
<h3>More information:</h3>
<p><a  href="http://codex.wordpress.org/Function_Reference/get_the_term_list">Learn more about “get_the_term_list.”</a></p>
<hr />
<h2><span>Step 3</span> Format Results from Classifications, if Any</h2>
<p>Check for results in each of the three possible taxonomies. If they exist, add them to our output, as well as a linebreak.</p>
<pre class="brush:php;">// Add OS list if this post was so tagged
if ( &#39;&#39; != $os_list )
    $taxo_text .= "$os_listn";

// Add RAM list if this post was so tagged
if ( &#39;&#39; != $ram_list )
    $taxo_text .= "$ram_listn";

// Add HD list if this post was so tagged
if ( &#39;&#39; != $hd_list )
    $taxo_text .= "$hd_listn";
</pre>
<hr />
<h2><span>Step 4</span> Display Classification Results, if Any</h2>
<p>Check to see if the above steps resulted in any taxonomy information at all to output. If taxonomy info exists, we’ll output it wrapped in a div of class “entry-utility.”</p>
<pre class="brush:php;">// Output taxonomy information if there was any
// NOTE: We won&#39;t even open a div if there&#39;s nothing to put inside it.
if ( &#39;&#39; != $taxo_text )
?>
<div class="entry-utility">
< ?php
echo $taxo_text;
?>
</div>

< ?
 // endif
?>
</pre>
<hr />
<h2><span>Step 5</span> Check Your Results</h2>
<p>Visit a post page, and you should see any custom taxonomy classifications listed below.</p>
<div>
<img src="http://www.taiwangeek.com/wp-content/uploads/2010/07/2f10f4e6b6howing.png.png" alt="Taxonomy info on single posts 2" />
</div>
<hr />
<h2>Viewing a List of Posts by Taxonomy Classification</h2>
<p>Now our individual posts tell us what custom taxonomies they have been classified with. When they list a custom taxonomy classification, they also provide a link to list all posts under that classification. For instance, clicking the “Mac OS” link next to “Operating Systems” under our post will theoretically list all the posts with the “Mac OS” operating system classification.</p>
<p>However, this doesn’t happen out of the box with WordPress version 3. We’ll have to make a custom template file for displaying taxonomy archives in order for it to work. WordPress already lets visitors view all posts assigned to a particular category, or all posts given a certain tag. When we’re done here, we’ll be able to view all posts assigned to particular classifications in our custom taxonomies, too.</p>
<p>To make this happen, we’ll need to create the “taxonomy.php” template file. WordPress will try to use this file any time it wants to list posts in a custom taxonomy.</p>
<hr />
<h2><span>Step 1</span></h2>
<p>Open the “category.php” file, copy its contents, and paste it into a new file called “taxonomy.php.” Save taxonomy.php in the theme directory. For instance, my taxonomy.php file is at:<br />
website_root/wp/wp-content/themes/twentyten/taxonomy.php.</p>
<hr />
<h2><span>Step 2</span> Get Information About Current Taxonomy Classification</h2>
<p>In the taxonomy.php file, we need to get information about the taxonomy being listed. We’ll probably want the name and description (if any) for the selected classification.</p>
<p>Just under < ?php get_header(); ?>, add the following line:</p>
<pre class="brush:php;">$term = get_term_by( 'slug', get_query_var( 'term' ), get_query_var( 'taxonomy' ) );
</pre>
<p>This gets all of the information about the taxonomy that called this page and returns it as an object into the variable $term. For example, the “Mac OS” classification returns an object as such:</p>
<pre class="brush:php;">stdClass Object
(
    term_id => 13
    name => Mac OS
    slug => mac-os
    term_group => 0
    term_taxonomy_id => 22
    taxonomy => operating_system
    description =>
    parent => 0
    count => 2
)
</pre>
<hr />
<h2><span>Step 3</span> Display Classification Name and Description</h2>
<p>We want to change the page name to tell visitors what they’re looking at. Since we started with the category.php template, we can take the line that used to print the category name and change it a bit to give us our desired page name and, if applicable, description.</p>
<p>Change the following line from category.php:</p>
<pre class="brush:php;">printf( __( &#39;Category Archives: %s&#39;, &#39;twentyten&#39; ), &#39;<span>&#39; . single_cat_title( &#39;&#39;, false ) . &#39;</span>&#39; );
</pre>
<p>To read as follows:</p>
<pre class="brush:php;">printf( __( &#39;Posts classified under: %s&#39;, &#39;twentyten&#39; ), &#39;<span>&#39; . $term_name . &#39;</span>&#39; );
</pre>
<p>This changes the static text beginning the line, and then inserts the name of the classification. (Note: for proper localization, we would need to add ‘Posts classified under:’ correctly to the languages/twentyten.pot file. That’s outside the scope of this tutorial, but be aware of the transgression here.)</p>
<p>Then add the following:</p>
<pre class="brush:php;">if (&#39;&#39; != $term_descr )
echo "

$term_descr

n";
</pre>
<p>If a description exists for this classification, it will be displayed just beneath the title.</p>
<div>
<img src="http://www.taiwangeek.com/wp-content/uploads/2010/07/f71df3c73csting2.png.png" alt="Taxonomy Archive Page" />
</div>
<p>After making changes to taxonomy.php, visit one of your posts that has been given a custom taxonomy classification. Because of our earlier work in the file “single.php,” the post should show custom classifications below it. Simply click one of those classifications to see the taxonomy listing at work.</p>
<hr />
<h2>Conclusion</h2>
<p>I hope this tutorial explained clearly what taxonomies are and showed you how to make use of them in WordPress 3 as a powerful organizational tool. I hope to provide a follow up tutorial soon explaining WordPress custom post types, their tight relationship with custom taxonomies, and how to use them. Thanks so much for taking the time to visit Nettuts!</p>
<div>
<a  href="http://feeds.feedburner.com/~ff/nettuts?a=dKgVcNaVUcU:r96V6ugiAFI:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/nettuts?d=yIl2AUoC8zA" border="0" /></a> <a  href="http://feeds.feedburner.com/~ff/nettuts?a=dKgVcNaVUcU:r96V6ugiAFI:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/nettuts?i=dKgVcNaVUcU:r96V6ugiAFI:F7zBnMyn0Lo" border="0" /></a> <a  href="http://feeds.feedburner.com/~ff/nettuts?a=dKgVcNaVUcU:r96V6ugiAFI:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/nettuts?i=dKgVcNaVUcU:r96V6ugiAFI:V_sGLiPBpWU" border="0" /></a> <a  href="http://feeds.feedburner.com/~ff/nettuts?a=dKgVcNaVUcU:r96V6ugiAFI:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/nettuts?i=dKgVcNaVUcU:r96V6ugiAFI:gIN9vFwOqvQ" border="0" /></a> <a  href="http://feeds.feedburner.com/~ff/nettuts?a=dKgVcNaVUcU:r96V6ugiAFI:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/nettuts?d=TzevzKxY174" border="0" /></a>
</div>
<p><img src="http://feeds.feedburner.com/~r/nettuts/~4/dKgVcNaVUcU" height="1" width="1" /><br />
<!--/content--></p>
]]></content:encoded>
			<wfw:commentRss>http://www.taiwangeek.com/2010-07/introducing-wordpress-3-custom-taxonomies.html/feed</wfw:commentRss>
		<slash:comments>0</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-05-19 05:56:49 -->
