<?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>Untitled &#187; howto</title>
	<atom:link href="http://ammonlauritzen.com/blog/tag/howto/feed/" rel="self" type="application/rss+xml" />
	<link>http://ammonlauritzen.com/blog</link>
	<description>and still for good reason.</description>
	<lastBuildDate>Wed, 05 May 2010 18:43:20 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>virtualbox rules</title>
		<link>http://ammonlauritzen.com/blog/2010/03/10/virtualbox-rules/</link>
		<comments>http://ammonlauritzen.com/blog/2010/03/10/virtualbox-rules/#comments</comments>
		<pubDate>Wed, 10 Mar 2010 21:42:23 +0000</pubDate>
		<dc:creator>Ammon</dc:creator>
				<category><![CDATA[personal]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[sysadmin]]></category>
		<category><![CDATA[geek]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[linux]]></category>

		<guid isPermaLink="false">http://ammonlauritzen.com/blog/?p=1111</guid>
		<description><![CDATA[Nothing much to say here, but with absolutely minimal pain and suffering, I have 64-bit linux virtual machines running on top of my 32-bit windows XP install. This pleases me.
The recipe:

Compatible CPU with VT-x/AMD-V enabled in the BIOS
Innotek/Oracle/Sun VirtualBox (a current version) with hardware virtualization enabled
Profit!

The one downside to this? 64-bit VM&#8217;s running on 32-bit [...]]]></description>
			<content:encoded><![CDATA[<p>Nothing much to say here, but with absolutely minimal pain and suffering, I have 64-bit linux virtual machines running on top of my 32-bit windows XP install. This pleases me.</p>
<p>The recipe:</p>
<ol>
<li>Compatible CPU with VT-x/AMD-V enabled in the BIOS</li>
<li>Innotek/Oracle/Sun VirtualBox (a current version) with hardware virtualization enabled</li>
<li>Profit!</li>
</ol>
<p>The one downside to this? 64-bit VM&#8217;s running on 32-bit host OS can&#8217;t see multiple cpu&#8217;s. Boo. Hoo. I&#8217;ll just run more VM&#8217;s!</p>
<p><a href="http://ammonlauritzen.com/blog/wp-content/uploads/2010/03/centos-installer-64-virtualbox.png"><img src="http://ammonlauritzen.com/blog/wp-content/uploads/2010/03/centos-installer-64-virtualbox-300x250.png" alt="64-bit centos installer" title="centos-installer-64-virtualbox" width="300" height="250" class="alignnone size-medium wp-image-1112" /></a> <a href="http://ammonlauritzen.com/blog/wp-content/uploads/2010/03/ubuntu-64-virtualbox.png"><img src="http://ammonlauritzen.com/blog/wp-content/uploads/2010/03/ubuntu-64-virtualbox-300x250.png" alt="64-bit ubuntu livecd" title="ubuntu-64-virtualbox" width="300" height="250" class="alignnone size-medium wp-image-1113" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://ammonlauritzen.com/blog/2010/03/10/virtualbox-rules/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>lazy php profiler</title>
		<link>http://ammonlauritzen.com/blog/2010/01/12/lazy-php-profiler/</link>
		<comments>http://ammonlauritzen.com/blog/2010/01/12/lazy-php-profiler/#comments</comments>
		<pubDate>Wed, 13 Jan 2010 01:06:56 +0000</pubDate>
		<dc:creator>Ammon</dc:creator>
				<category><![CDATA[programming]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://ammonlauritzen.com/blog/?p=1096</guid>
		<description><![CDATA[Caveman profiling with a side of &#8220;where were you at 9pm on the night in question?&#8221; As always, season to taste.

&#60;?
$_profile_log = &#34;/tmp/php-profile.log&#34;;

function _profile() {
    static $fh;
    if( !isset($fh) ) {
        global $_profile_log;
        if( !file_exists($_profile_log) [...]]]></description>
			<content:encoded><![CDATA[<p>Caveman profiling with a side of &#8220;where were you at 9pm on the night in question?&#8221; As always, season to taste.</p>
<pre class="brush: php;">
&lt;?
$_profile_log = &quot;/tmp/php-profile.log&quot;;

function _profile() {
    static $fh;
    if( !isset($fh) ) {
        global $_profile_log;
        if( !file_exists($_profile_log) ) {
            @touch( $_profile_log );
            @chmod( $_profile_log, 0664 );
        }
        $fh = @fopen( $_profile_log, &quot;a&quot; );
    }
    if( !$fh )
        return false;

    $stack = debug_backtrace();
    if( $stack[1] )
        $base = $stack[1];
    else
        $base = $stack[0];
    $buf = $base['file'].&quot;:&quot;.$base['line'].&quot;, &quot;;
    if( $base['class'] )
        $buf .= $base['class'].$base['type'];
    $buf .= $base['function'];

    $buf = sprintf(&quot;[%s] %s\n&quot;,date(&quot;H:i:s&quot;),$buf);
    return @fwrite( $fh, $buf );
}
?&gt;
</pre>
<p><span id="more-1096"></span><br />
Sample use:</p>
<pre class="brush: php;">
&lt;?
require_once &quot;profiler.php&quot;;

// setup
function func() {
    _profile();
}

class obj {
    function method() {
        _profile();
    }
    function other_method() {
        func();
    }
    function indirect_method() {
        $this-&gt;method();
    }
}

$obj = new obj();

// actual invocation cases
_profile();
func();
obj::method();
$obj-&gt;method();
$obj-&gt;other_method();
$obj-&gt;indirect_method();
?&gt;
</pre>
<p>Output:</p>
<pre class="brush: plain;">
ammon@elzar:~$ cat /tmp/php-profile.log
[19:00:21] /home/ammon/test.php:20, _profile
[19:00:21] /home/ammon/test.php:21, func
[19:00:21] /home/ammon/test.php:22, obj::method
[19:00:21] /home/ammon/test.php:24, obj-&gt;method
[19:00:21] /home/ammon/test.php:13, func
[19:00:21] /home/ammon/test.php:16, obj-&gt;method
</pre>
]]></content:encoded>
			<wfw:commentRss>http://ammonlauritzen.com/blog/2010/01/12/lazy-php-profiler/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>xtrabackup innodb_file_per_table gotcha</title>
		<link>http://ammonlauritzen.com/blog/2009/08/18/xtrabackup-innodb_file_per_table-gotcha/</link>
		<comments>http://ammonlauritzen.com/blog/2009/08/18/xtrabackup-innodb_file_per_table-gotcha/#comments</comments>
		<pubDate>Tue, 18 Aug 2009 17:55:03 +0000</pubDate>
		<dc:creator>Ammon</dc:creator>
				<category><![CDATA[sysadmin]]></category>
		<category><![CDATA[gotcha]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[innodb]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[xtrabackup]]></category>

		<guid isPermaLink="false">http://ammonlauritzen.com/blog/?p=540</guid>
		<description><![CDATA[Several months ago, I&#8217;d switched to using Percona&#8217;s xtrabackup &#038; innobackupex for all of my mysql backup needs. I had successfully used these backups to restore and replicate databases across several systems. It is good stuff.
Last week, I needed to set up new replication of an 80gb database. This should have been routine by now, [...]]]></description>
			<content:encoded><![CDATA[<p>Several months ago, I&#8217;d switched to using Percona&#8217;s xtrabackup &#038; innobackupex for all of my mysql backup needs. I had successfully used these backups to restore and replicate databases across several systems. It is good stuff.</p>
<p>Last week, I needed to set up new replication of an 80gb database. This should have been routine by now, but when I attempted to prepare the backup this time, it whined and complained and failed. I was kind of frazzled by the time I gave up on the issue and declared it a fluke of one sort or another.</p>
<p>Last night, I tried again from Sunday&#8217;s full backup, and it happened again:</p>
<pre>
ammon@amy:/var/lib/2009-08-16_04-02-17$ sudo xtrabackup --prepare --target-dir=.
xtrabackup  Ver 0.8.1rc Rev 78 for 5.0.83 unknown-linux-gnu (x86_64)
xtrabackup: cd to .
xtrabackup: This target seems to be not prepared yet.
xtrabackup: xtrabackup_logfile detected: size=75546624, start_lsn=(86 1293090752)
xtrabackup: Temporary instance for recovery is set as followings.
xtrabackup:   innodb_data_home_dir = ./
xtrabackup:   innodb_data_file_path = ibdata1:512M:autoextend
xtrabackup:   innodb_log_group_home_dir = ./
xtrabackup:   innodb_log_files_in_group = 1
xtrabackup:   innodb_log_file_size = 75546624
xtrabackup: Starting InnoDB instance for recovery.
xtrabackup: Using 104857600 bytes for buffer pool (set by --use-memory parameter)
InnoDB: Log scan progressed past the checkpoint lsn 86 1293090752
090818  2:54:34  InnoDB: Database was not shut down normally!
InnoDB: Starting crash recovery.
InnoDB: Reading tablespace information from the .ibd files...
090818  2:54:34  InnoDB: Operating system error number 2 in a file operation.
InnoDB: The error means the system cannot find the path specified.
InnoDB: If you are installing InnoDB, remember that you must create
InnoDB: directories yourself, InnoDB does not create them.
InnoDB: File name .//tmp/#sql6e1e_8cce1_0.ibd
InnoDB: File operation call: 'create'.
InnoDB: Cannot continue operation.
</pre>
<p>I gave up after poking a few things.</p>
<p>This morning&#8217;s fresh look turned up <a href='http://bugs.mysql.com/bug.php?id=41609'>this bug report</a>.</p>
<pre>
ammon@amy:/var/lib/2009-08-16_04-02-17$ sudo <b>mkdir tmp</b>
ammon@amy:/var/lib/2009-08-16_04-02-17$ sudo xtrabackup --prepare --target-dir=.
xtrabackup  Ver 0.8.1rc Rev 78 for 5.0.83 unknown-linux-gnu (x86_64)
xtrabackup: cd to .
xtrabackup: This target seems to be not prepared yet.
090818 12:27:41  InnoDB: Operating system error number 2 in a file operation.
InnoDB: The error means the system cannot find the path specified.
xtrabackup: Warning: cannot open ./xtrabackup_logfile. will try to find.
xtrabackup: 'ib_logfile0' seems to be 'xtrabackup_logfile'. will retry.
xtrabackup: xtrabackup_logfile detected: size=84983808, start_lsn=(86 1293090752)
xtrabackup: Temporary instance for recovery is set as followings.
xtrabackup:   innodb_data_home_dir = ./
xtrabackup:   innodb_data_file_path = ibdata1:512M:autoextend
xtrabackup:   innodb_log_group_home_dir = ./
xtrabackup:   innodb_log_files_in_group = 1
xtrabackup:   innodb_log_file_size = 84983808
xtrabackup: Starting InnoDB instance for recovery.
xtrabackup: Using 104857600 bytes for buffer pool (set by --use-memory parameter)
InnoDB: Log scan progressed past the checkpoint lsn 86 1293090752
090818 12:27:41  InnoDB: Database was not shut down normally!
InnoDB: Starting crash recovery.
InnoDB: Reading tablespace information from the .ibd files...
InnoDB: Doing recovery: scanned up to log sequence number 86 1298333184 (6 %)
InnoDB: Doing recovery: scanned up to log sequence number 86 1303576064 (13 %)
InnoDB: Doing recovery: scanned up to log sequence number 86 1308818944 (20 %)
InnoDB: Doing recovery: scanned up to log sequence number 86 1314061824 (27 %)
InnoDB: Doing recovery: scanned up to log sequence number 86 1319304704 (34 %)
090818 12:27:44  InnoDB: Starting an apply batch of log records to the database...
<i>... snip ...</i>
</pre>
<p>That&#8217;s right. There&#8217;s a bug in innodb restoration that interprets location of /tmp (configurable in my.cnf) to be relative in stead of absolute.</p>
<p>So, if you have problems while trying to restore from an xtrabackup/ibbackup snapshot (or if you&#8217;re trying to recover innodb after a crash), just creating the offending tmp directory appears to work.</p>
]]></content:encoded>
			<wfw:commentRss>http://ammonlauritzen.com/blog/2009/08/18/xtrabackup-innodb_file_per_table-gotcha/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>init.d template</title>
		<link>http://ammonlauritzen.com/blog/2009/06/18/initd-template/</link>
		<comments>http://ammonlauritzen.com/blog/2009/06/18/initd-template/#comments</comments>
		<pubDate>Thu, 18 Jun 2009 17:29:31 +0000</pubDate>
		<dc:creator>Ammon</dc:creator>
				<category><![CDATA[programming]]></category>
		<category><![CDATA[sysadmin]]></category>
		<category><![CDATA[bash]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[init.d]]></category>

		<guid isPermaLink="false">http://ammonlauritzen.com/blog/?p=512</guid>
		<description><![CDATA[This is a rudimentary template that I&#8217;ve been using for very quick and dirty /etc/init.d scripts recently.
It works under the assumption that your server daemon has a unique name and only ever runs a single instance &#8211; this also means that the binary and the init.d script cannot share a name &#8211; otherwise strange things [...]]]></description>
			<content:encoded><![CDATA[<p>This is a rudimentary template that I&#8217;ve been using for very quick and dirty /etc/init.d scripts recently.</p>
<p>It works under the assumption that your server daemon has a unique name and only ever runs a single instance &#8211; this also means that the binary and the init.d script cannot share a name &#8211; otherwise strange things happen <img src='http://ammonlauritzen.com/blog/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p>Actual invocation logic may need to be updated on a per-service basis and chkconfig style headers would have to be added manually, but it works well for what it is.</p>
<pre class="brush: bash;">
#!/bin/bash

DIR=''	# path to the daemon executable
CMD=''	# name of the command itself
ARG=''	# optional. any arguments to pass when starting
NAM=''	# descriptive name of the daemon so it shows up pretty

function get_ps {
	ps --no-header -C${CMD}
}

function do_start {
	echo -n &quot;Starting ${NAM}... &quot;
	cd ${DIR}
	nohup ./${CMD} ${ARG} &amp;
	SUCC=`get_ps | wc -l`
	if [ &quot;1&quot; == &quot;$SUCC&quot; ]; then
		echo &quot;[SUCCESS]&quot;
	else
		echo &quot;[FAILURE]&quot;
	fi
}

function do_stop {
	echo -n &quot;Stopping ${NAM}... &quot;
	PID=`get_ps | awk '{print $1}'`
	kill $PID
	SUCC=`get_ps | wc -l`
	if [ &quot;0&quot; == &quot;$SUCC&quot; ]; then
		echo &quot;[SUCCESS]&quot;
	else
		echo &quot;[FAILURE]&quot;
	fi
}

case &quot;${1:-''}&quot; in
	'start')
		do_start
		;;
	'stop')
		do_stop
		;;
	'restart')
		do_stop
		do_start
		;;
	*)
		#echo &quot;Usage: $SELF start|stop|restart|reload|force-reload|status&quot;
		echo &quot;Usage: $SELF start|stop|restart&quot;
		exit 1
		;;
esac
</pre>
]]></content:encoded>
			<wfw:commentRss>http://ammonlauritzen.com/blog/2009/06/18/initd-template/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>gearman 0.3 php extension api</title>
		<link>http://ammonlauritzen.com/blog/2009/05/26/gearman-03-php-extension-api/</link>
		<comments>http://ammonlauritzen.com/blog/2009/05/26/gearman-03-php-extension-api/#comments</comments>
		<pubDate>Tue, 26 May 2009 21:10:17 +0000</pubDate>
		<dc:creator>Ammon</dc:creator>
				<category><![CDATA[programming]]></category>
		<category><![CDATA[gearman]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://ammonlauritzen.com/blog/?p=500</guid>
		<description><![CDATA[No real preamble to be made here. Gearman is a distributed job queuing system by the fine folks who brought us memcached. It is nicer than anything else I&#8217;ve looked at. I am attempting to switch one of my projects over to it (replacing a crufty curl + unix sockets + memcached monstrosity that attempted [...]]]></description>
			<content:encoded><![CDATA[<p>No real preamble to be made here. <a href='http://gearman.org'>Gearman</a> is a distributed job queuing system by the <a href='http://danga.com/'>fine folks</a> who brought us <a href='http://danga.com/memcached/'>memcached</a>. It is nicer than anything else I&#8217;ve looked at. I am attempting to switch one of my projects over to it (replacing a crufty curl + unix sockets + memcached monstrosity that attempted to do the same job).</p>
<p>The documentation is lacking, but if the discussion group is any indication, real docs are a high priority for the project team. Today, I visited the IRC channel to ask for a status update on docs for the PHP extension api (as opposed to the PEAR all-script api, whose auto-generated docs are broken). Turns out my suspicions were right. Documentation is a high priority and none currently exists for the api in question. However&#8230; I was informed that the classes support reflection&#8230; so <img src='http://ammonlauritzen.com/blog/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>A quick grep of the source for the extension tells me that I am looking at four classes: GearmanClient, GearmanWorker, GearmanJob, and GearmanTask. A ridiculously short php script later&#8230;</p>
<pre class="brush: php;">
&lt;?
Reflection::export( new ReflectionClass('GearmanWorker') );
Reflection::export( new ReflectionClass('GearmanClient') );
Reflection::export( new ReflectionClass('GearmanJob') );
Reflection::export( new ReflectionClass('GearmanTask') );
?&gt;
</pre>
<p>And I can at least try to make a human readable list of available methods.</p>
<h3>GearmanWorker</h3>
<ul>
<li>__construct()</li>
<li>clone()</li>
<li>error()</li>
<li>returnCode()</li>
<li>setOptions( $option, $data )</li>
<li>addServer( $host, $port ) &#8211; both args optional, examples say defaults are localhost on port 4730.</li>
<li>addFunction( $function_name, $function, $data, $timeout ) &#8211; data and timeout optional</li>
<li>work()</li>
</ul>
<h3>GearmanClient</h3>
<ul>
<li>__construct()</li>
<li>clone()</li>
<li>error()</li>
<li>setOptions( $option, $data )</li>
<li>addServer( $host, $port ) &#8211; reflection says REQUIRED, however the provided examples and personal experience says otherwise</li>
<li>do( $function_name, $workload, $unique ) &#8211; unique is optional</li>
<li>doHigh( $function_name, $workload, $unique ) &#8211; unique is optional</li>
<li>doLow( $function_name, $workload, $unique ) &#8211; unique is optional</li>
<li>doJobHandle()</li>
<li>doStatus()</li>
<li>doBackground( $function_name, $workload, $unique ) &#8211; unique is optional</li>
<li>doHighBackground( $function_name, $workload, $unique ) &#8211; unique is optional</li>
<li>doLowBackground( $function_name, $workload, $unique ) &#8211; unique is optional</li>
<li>jobStatus( $job_handle )</li>
<li>echo( $workload )</li>
<li>addTask( $function_name, $workload, $data, $unique ) &#8211; data and unique are optional</li>
<li>addTaskHigh( $function_name, $workload, $data, $unique ) &#8211; data and unique are optional</li>
<li>addTaskLow( $function_name, $workload, $data, $unique ) &#8211; data and unique are optional</li>
<li>addTaskBackground( $function_name, $workload, $data, $unique ) &#8211; data and unique are optional</li>
<li>addTaskHighBackground( $function_name, $workload, $data, $unique ) &#8211; data and unique are optional</li>
<li>addTaskLowBackground( $function_name, $workload, $data, $unique ) &#8211; data and unique are optional</li>
<li>addTaskStatus( $job_handle, $data ) &#8211; data is optional</li>
<li>setWorkloadCallback( $callback )</li>
<li>setCreatedCallback( $callback)</li>
<li>setClientCallback( $callback)</li>
<li>setWarningCallback( $callback)</li>
<li>setStatusCallback( $callback)</li>
<li>setCompleteCallback( $callback)</li>
<li>setExceptionCallback( $callback)</li>
<li>setFailCallback( $callback)</li>
<li>clearCallbacks()</li>
<li>data()</li>
<li>setData( $data )</li>
<li>runTasks()</li>
</ul>
<h3>GearmanJob</h3>
<ul>
<li>__construct()</li>
<li>returnCode()</li>
<li>workload()</li>
<li>workloadSize()</li>
<li>warning( $warning )</li>
<li>status( $numerator, $denominator )</li>
<li>handle()</li>
<li>unique()</li>
<li>data( $data )</li>
<li>complete( $result )</li>
<li>exception( $exception )</li>
<li>fail()</li>
<li>functionName()</li>
<li>setReturn( $gearman_return_t )</li>
</ul>
<h3>GearmanTask</h3>
<ul>
<li>__construct()</li>
<li>returnCode()</li>
<li>create()</li>
<li>free()</li>
<li>function()</li>
<li>uuid()</li>
<li>jobHandle()</li>
<li>isKnown()</li>
<li>isRunning()</li>
<li>taskNumerator()</li>
<li>taskDenominator()</li>
<li>data()</li>
<li>dataSize()</li>
<li>takeData( $task_object ) &#8211; optional</li>
<li>sendData( $data )</li>
<li>recvData( $data_len )</li>
</ul>
<p>The extension also appears to expose all constants defined in the C api.</p>
<p>I have since added this to the official <a href='http://www.gearman.org/doku.php?id=php_reflection'>wiki</a> &#8211; so there are at least SOME docs on the site now <img src='http://ammonlauritzen.com/blog/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://ammonlauritzen.com/blog/2009/05/26/gearman-03-php-extension-api/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>php autoload</title>
		<link>http://ammonlauritzen.com/blog/2008/10/28/php-autoload/</link>
		<comments>http://ammonlauritzen.com/blog/2008/10/28/php-autoload/#comments</comments>
		<pubDate>Tue, 28 Oct 2008 23:06:40 +0000</pubDate>
		<dc:creator>Ammon</dc:creator>
				<category><![CDATA[programming]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[rant]]></category>
		<category><![CDATA[style]]></category>

		<guid isPermaLink="false">http://ammonlauritzen.com/blog/?p=407</guid>
		<description><![CDATA[As of version 5.0, PHP has had the ability to dynamically include required classes as needed &#8211; without requiring the developer to manually include all possible dependencies beforehand. This means that in cases where your code execution never touches 39 of the 40 classes in the project, it loads, parses, and runs that much faster.
There [...]]]></description>
			<content:encoded><![CDATA[<p>As of version 5.0, PHP has had the ability to dynamically include required classes as needed &#8211; without requiring the developer to manually include all possible dependencies beforehand. This means that in cases where your code execution never touches 39 of the 40 classes in the project, it loads, parses, and runs that much faster.</p>
<p>There is a performance hit for actually having to call the <a href='http://php.net/autoload'>__autoload()</a> method, but if you&#8217;re in a situation where the hit for executing a few extra comparison calls is unacceptable&#8230; you probably aren&#8217;t developing in PHP in the first place <img src='http://ammonlauritzen.com/blog/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p>Almost all of the php I&#8217;ve written in the last 2-3 years uses autoloading, and it has probably saved me hundreds of hours of aggravation.</p>
<p>In most of my projects, the first line of any script or class usually looks something like this:</p>
<pre class="brush: php;">
require_once &quot;/var/www/common/lib.php&quot;;
</pre>
<p>Then lib.php usually reads something like this:</p>
<pre class="brush: php;">
&lt;?
function __autoload( $class ) {
    include_once( &quot;$class.php&quot; );
}
?&gt;
</pre>
<p>And that is all that is strictly required to make the magic happen. It is fast, it is easy to understand, it is easy to use. You can use require_once() or include_once() and there is very little meaningful difference.</p>
<p>I&#8217;ve looked around the net and found several other attempts at improving on this simple mechanism. But they invariably overcomplicate things. They attempt to recurse source directories, cache filename->class differences to the filesystem, and otherwise turn what should be a simple filesystem operation that the php environment supports natively into a mess of exception handling and wheel reinvention.</p>
<p>There are obviously theoretical instances where you might want to have more than the one require_once/include_once line&#8230; but I&#8217;ve honestly never encountered one myself.</p>
<p>I mean, you could try to throw an exception if the file didn&#8217;t exist or otherwise failed to load&#8230; but nothing will happen. Failure to instantiate a nonexistant class is a fatal error in PHP, and will be handled as such with or without you &#8211; preempting any attempt at throwing an exception.</p>
<p>The only thing you can add is a bit of extra diagnostics or maybe logging to a separate location.</p>
<p>Assume that we have a file &#8216;test.php&#8217;:</p>
<pre class="brush: php;">
&lt;?
require_once &quot;autoload.php&quot;;
$frog = new Frog();
?&gt;
</pre>
<p>If autoload.php contains a simple simple autoload function that uses require_once(), and Frog.php doesn&#8217;t exist anywhere in your include path, the results will look something like this:</p>
<pre class="brush: plain;">
ammon@kif:~$ php test.php 

Warning: require_once(Frog.php): failed to open stream: No such file or directory in /home/ammon/autoload.php on line 3

Fatal error: require_once(): Failed opening required 'Frog.php' (include_path='.:/usr/share/php:/usr/share/pear') in /home/ammon/autoload.php on line 3
</pre>
<p>If we had used an include_once() call, the output is similar, but slightly more informative:</p>
<pre class="brush: plain;">
ammon@kif:~$ php test.php 

Warning: include_once(Frog.php): failed to open stream: No such file or directory in /home/ammon/autoload.php on line 3

Warning: include_once(): Failed opening 'Frog.php' for inclusion (include_path='.:/usr/share/php:/usr/share/pear') in /home/ammon/autoload.php on line 3

Fatal error: Class 'Frog' not found in /home/ammon/test.php on line 4
</pre>
<p>So that&#8217;s probably a bit more useful in tracking down the error. Require calls don&#8217;t return anything &#8211; they throw a fatal error on failure. Include calls, however, return FALSE on failure and TRUE if the file is (or, in the case of include_once, has already been) successfully included. So you can include_once() and write to a separate logfile (or to the output stream&#8230;) if you need more information than the fatal error already provides you.</p>
<h3>&lt;rant&gt;</h3>
<p>To those who insist on giving your classes and their containing files different names&#8230; umm. Wow.</p>
<p>If I have a class called DatabaseConnection, I&#8217;m going to put it in a file called DatabaseConnection.php. If I&#8217;m working with strange people who somehow don&#8217;t think that is explicit enough, I might call it DatabaseConnection.class.php and tweak the autoload method ever so slightly to compensate. There&#8217;s no good reason to put it in a file called projx-database_connection.incl or something. No. There isn&#8217;t.</p>
<p>If you want to organize your classes into a meaningful directory structure&#8230; good for you. Use PHP&#8217;s built-in <a href='http://php.net/get_include_path'>include_path</a> ini option. Don&#8217;t waste time trying to cascade down a directory structure searching for the classes &#8211; just make sure your includes are all in a set of reliable locations. You don&#8217;t actually have to edit the php.ini file and bounce Apache or your php-cgi processes, just define the additional include paths in the same file where you define your autoloader:</p>
<pre class="brush: php;">
set_include_path(
    get_include_path() . PATH_SEPARATOR .
    &quot;/var/www/includes&quot; . PATH_SEPARATOR .
    &quot;/var/www/includes/apple&quot; . PATH_SEPARATOR .
    &quot;/var/www/includes/banana&quot;
);
</pre>
<p>Naturally, you could turn that into some function calls to dynamically register and unregister directories, etc&#8230; but at that point, you&#8217;re probably hurting yourself again. If your codebase is being reorganized enough to make maintenance of the list of include dirs onerous without full time intervention, something else has probably already gone very wrong. At best, the code probably doesn&#8217;t work anyway, so any brief delay in updating the list can&#8217;t hurt any more than whatever else is happening.</p>
<h3>&lt;/rant&gt;</h3>
<p>But seriously. __autoload() is your friend. It will help clean up your code if you let it. It can help enforce naming conventions. It can even improve performance&#8230; so long as you refrain from using it to shoot yourself in the foot. <img src='http://ammonlauritzen.com/blog/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://ammonlauritzen.com/blog/2008/10/28/php-autoload/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>php signals while selecting</title>
		<link>http://ammonlauritzen.com/blog/2008/10/27/php-signals-while-selecting/</link>
		<comments>http://ammonlauritzen.com/blog/2008/10/27/php-signals-while-selecting/#comments</comments>
		<pubDate>Mon, 27 Oct 2008 20:26:38 +0000</pubDate>
		<dc:creator>Ammon</dc:creator>
				<category><![CDATA[programming]]></category>
		<category><![CDATA[gotcha]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[posix signals]]></category>
		<category><![CDATA[sockets]]></category>

		<guid isPermaLink="false">http://ammonlauritzen.com/blog/?p=399</guid>
		<description><![CDATA[So a fairly longstanding gripe of mine has been that PHP fails to execute registered signal handlers when it receives a signal in the middle of a blocking select call. Today, I finally bumped into a situation where I couldn&#8217;t just change the spec to avoid the situation&#8230; and I&#8217;ve finally figured out how to [...]]]></description>
			<content:encoded><![CDATA[<p>So a fairly longstanding gripe of mine has been that PHP fails to execute registered signal handlers when it receives a signal in the middle of a blocking select call. Today, I finally bumped into a situation where I couldn&#8217;t just change the spec to avoid the situation&#8230; and I&#8217;ve finally figured out how to make it work.</p>
<p>The bug has been reported <a href='http://bugs.php.net/44614'>here</a>, where it was ignored for a few months before being shot down and ignored some more as per php dev team regulations.</p>
<p>Sample code given by the reporter of the bug is markedly similar to the situations I&#8217;ve encountered the problem:</p>
<pre class="brush: php;">
pcntl_signal(SIGINT, &quot;sig_handler&quot;);
$sock = socket_create_listen($port);
$read_socks = array($sock);
$n = NULL;
$foo = socket_select($read_socks, $n, $n, NULL);
</pre>
<p>By filling in his blanks, my first test case looks something like this:</p>
<pre class="brush: php;">
&lt;?
function sig_handler($signo) {
        echo &quot;received sig #$signo\\\n&quot;;
}
pcntl_signal( SIGINT, &quot;sig_handler&quot; );

$socket = socket_create_listen( 1234 );
$r = array( $socket );
$n = NULL;
while( true ) {
        $foo = socket_select( $r, $n, $n, NULL );
        echo &quot;select returned '$foo'\\\n&quot;;
}
?&gt;
</pre>
<p>When executing the script and pressing ^C (which sends SIGINT), the following occurs:</p>
<pre class="brush: plain;">
ammon@morbo:~$ php sigtest.php
PHP Warning:  socket_select(): unable to select [4]: Interrupted system call in /home/ammon/sigtest.php on line 13
select returned ''
</pre>
<p>Ok, so the warning is to be expected, and we can easily squelch that.</p>
<p>The real problem is that the signal handler never runs.</p>
<p>However&#8230; for the first time in my life, a response to a php bug report proves enlightening. The dev who answered this ticket provides his sample code and says he can&#8217;t duplicate the bug. Upon looking at the differences between their code, only one difference stands out:</p>
<pre class="brush: php;">
declare(ticks=1);
</pre>
<p>The <a href='http://php.net/declare'>declare(ticks)</a> directive is deprecated as of php 5.3 and will not be with us in php 6.0. Ticks are an unreliable, unpredictable, and generally bad thing in php. I&#8217;ve neither successfully used them nor seen a successful and justified use.</p>
<p>That being said&#8230; turning the tick on but not telling it to do anything appears to address the problem of discarded interrupts:</p>
<pre class="brush: php;">
&lt;?
declare(ticks=1);

function sig_handler($signo) {
        echo &quot;received sig #$signo\\\n&quot;;
}
pcntl_signal( SIGINT, &quot;sig_handler&quot; );

$socket = socket_create_listen( 1234 );
$r = array( $socket );
$n = NULL;
while( true ) {
        $foo = @socket_select( $r, $n, $n, NULL );
        echo &quot;select returned '$foo'\\\n&quot;;
}
?&gt;
</pre>
<p>And execution:</p>
<pre class="brush: plain;">
ammon@morbo:~$ php sigtest.php
received sig #2
select returned ''
</pre>
<p>Which is precisely the desired behavior.</p>
<p>I don&#8217;t know what the performance hit for turning ticks on is, I haven&#8217;t had time to research this. But I can confirm that by declaring ticks globally, it does work in an OO environment as well:</p>
<pre class="brush: php;">
&lt;?
declare(ticks=1);

class signal_tester {
    function __construct() {
        pcntl_signal( SIGINT, array(&amp;$this,&quot;sig_handler&quot;) );
        $this-&gt;start();
    }

    function sig_handler($signo) {
        echo &quot;received sig #$signo\\\n&quot;;
    }

    function start() {
        $socket = socket_create_listen( 1234 );
        $r = array( $socket );
        $n = NULL;
        while( true ) {
            $foo = @socket_select( $r, $n, $n, NULL );
            echo &quot;select returned '$foo'\\\n&quot;;
        }
    }
}

$test = new signal_tester();
?&gt;
</pre>
<p>Executing and hitting ^C:</p>
<pre class="brush: plain;">
ammon@morbo:~$ php sigtest.php
received sig #2
select returned ''
</pre>
<p>After a few minutes of largely unscientific testing, it appears that turning ticks on globally costs a whopping 4 bytes of ram and causes the script to occasionally consume more cpu than the top process I used to monitor it. So&#8230; at first glance the cost is pretty negligible and all I can say is that if you ever need to handle signals (SIGTERM, SIGHUP, etc&#8230;) from within a blocking select call in php, it looks like declare ticks is the only option for now.</p>
<p>I did the initial tests in 5.1.6, but can confirm the same behavior in 5.2.5. I don&#8217;t know how the behavior is going to be in 5.3, since I don&#8217;t run alpha releases on my servers but my gut likes to think that it will continue to work the same for now&#8230; and will hopefully not break until 6.0 (when everything else will explode for a few years). Shrug.</p>
]]></content:encoded>
			<wfw:commentRss>http://ammonlauritzen.com/blog/2008/10/27/php-signals-while-selecting/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>php tail</title>
		<link>http://ammonlauritzen.com/blog/2008/05/27/php-tail/</link>
		<comments>http://ammonlauritzen.com/blog/2008/05/27/php-tail/#comments</comments>
		<pubDate>Tue, 27 May 2008 19:08:21 +0000</pubDate>
		<dc:creator>Ammon</dc:creator>
				<category><![CDATA[programming]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://ammonlauritzen.com/blog/?p=389</guid>
		<description><![CDATA[I have a php script that frequently needs to email me the last few lines of a log file. I can&#8217;t afford to exec() a binary tail process, so the solution has to be in pure php.
Originally, the files in question never exceeded more than a few thousand lines. Unfortunately, I am encountering cases now [...]]]></description>
			<content:encoded><![CDATA[<p>I have a php script that frequently needs to email me the last few lines of a log file. I can&#8217;t afford to exec() a binary tail process, so the solution has to be in pure php.</p>
<p>Originally, the files in question never exceeded more than a few thousand lines. Unfortunately, I am encountering cases now where the files are now occasionally 50,000 lines or longer. This causes PHP&#8217;s memory consumption to explode.</p>
<p><i>Note: Code snippets provided here are not fully functional standalone shell scripts. The scripts I ran to benchmark the algorithms contain some rudimentary setup logic that is not important here, so has not been included.</i></p>
<p>My original method:</p>
<pre class="brush: php;">
// tail-file.php
$arr = @file( $fname, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES );
$arr = array_slice($arr, -$lines);
$buf = implode(&quot;\\\n&quot;,$arr);
</pre>
<p>This is easy to understand and is pretty fast, all things considered. Unfortunately, the memory footprint for loading a file into an array is obscene. Loading a 4400 line log file with this method could consume more than 17mb of ram. 50,000 line files easily stressed the 256mb limit I am able to provide the process.</p>
<p>So, the obvious solution to the memory consumption is to avoid loading the entire file at once. What if we kept a rotating list of lines in the file?</p>
<pre class="brush: php;">
// tail-array.php
$arr = array_fill( 0, $lines+1, &quot;\\\n&quot; );

$fp = fopen($fname, &quot;r&quot;);
while( !feof($fp) ) {
    $line = fgets($fp, 4096);
    $arr[] = $line; // faster than array_push()
    array_shift($arr);
}
fclose($fp);
$buf = implode(&quot;&quot;,$arr);
</pre>
<p>This method works by keeping the $lines-many most recent lines of the file in an array. Memory consumption remains sane, but the performance hit for performing so many array pushes and shifts is bad. Really bad. With small files, I can&#8217;t notice any difference between this method and the file() method&#8230; but with longer files, it adds up quickly.</p>
<p>Given a 51 line, 4kb file, an average execution ($lines = 20) might look like this:</p>
<pre class="brush: plain;">
ammon@zapp:~$ time ./tail-file.php a.log &gt;/dev/null

real    0m0.015s
user    0m0.009s
sys     0m0.007s

ammon@zapp:~$ time ./tail-array.php a.log &gt;/dev/null

real    0m0.016s
user    0m0.010s
sys     0m0.006s
</pre>
<p>Comparable enough. But given a 50,004 line (3.3mb) log file:</p>
<pre>
ammon@zapp:~$ time ./tail-file.php b.log >/dev/null                  

real    0m0.079s
user    0m0.058s
sys     0m0.021s

ammon@zapp:~$ time ./tail-array.php b.log >/dev/null                 

real    0m0.119s
user    0m0.112s
sys     0m0.007s
</pre>
<p>The difference becomes quite clear. However&#8230; what if my log file grows obscenely large? I&#8217;ve got a 9 million line log file (1.6gb) lying around to test with&#8230;</p>
<pre>
ammon@zapp:~$ time ./tail-file.php c.log >/dev/null

real    0m0.015s
user    0m0.008s
sys     0m0.008s

ammon@zapp:~$ time ./tail-array.php c.log >/dev/null                 

real    0m19.351s
user    0m18.545s
sys     0m0.803s
</pre>
<p>The file() method crashes because it can&#8217;t allocate enough ram to hold a 9 million element array and the array method takes almost 20 seconds to execute. It&#8217;s slow&#8230; but at least it works.</p>
<p>Of course, there are other methods. The one I finally settled on is this:</p>
<pre class="brush: php;">
// tail-seek.php
$fp = fopen($fname, &quot;r&quot;);
$lines_read = 0;
if( $fp !== FALSE ) {
    fseek( $fp, 0, SEEK_END );
    $pos = $eof = ftell($fp);
    do {
        --$pos;
        fseek($fp, $pos);
        $c = fgetc($fp);
        if( $c == &quot;\\\n&quot; )
            $lines_read++;
    } while( $pos &gt; 0 &amp;&amp; $lines_read &lt;= $lines );
    $buf = fread($fp, $eof-$pos);
}
fclose($fp);
</pre>
<p>This method doesn&#8217;t waste time reading the bulk of the file. It jumps to the end and scans backward until enough newlines have been located. The only problem here is that your average filesystem isn&#8217;t optimized for reading backwards&#8230; but since we&#8217;re not really reading very much data, it doesn&#8217;t much matter.</p>
<pre>
ammon@zapp:~$ time ./tail-seek.php a.log >/dev/null

real    0m0.017s
user    0m0.009s
sys     0m0.008s

ammon@zapp:~$ time ./tail-seek.php b.log >/dev/null                  

real    0m0.017s
user    0m0.008s
sys     0m0.010s

ammon@zapp:~$ time ./tail-seek.php c.log >/dev/null                  

real    0m0.023s
user    0m0.015s
sys     0m0.008s
</pre>
<p>Performance is a trifle slower on small files, but it&#8217;s astronomically better on long ones. This is similar to the method used by most unix &#8216;tail&#8217; commands, and is the clear winner for actual use in my application.</p>
<p>Of course, it needs a bit of cleanup from the state I&#8217;ve provided it in, and isn&#8217;t appropriate for all environments&#8230; but it&#8217;s a trifle better than requiring 20 seconds and 20gb of ram to execute <img src='http://ammonlauritzen.com/blog/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://ammonlauritzen.com/blog/2008/05/27/php-tail/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>svn whitespace blues</title>
		<link>http://ammonlauritzen.com/blog/2008/03/18/svn-whitespace-blues/</link>
		<comments>http://ammonlauritzen.com/blog/2008/03/18/svn-whitespace-blues/#comments</comments>
		<pubDate>Wed, 19 Mar 2008 06:57:13 +0000</pubDate>
		<dc:creator>Ammon</dc:creator>
				<category><![CDATA[sysadmin]]></category>
		<category><![CDATA[diff]]></category>
		<category><![CDATA[gotcha]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[subversion]]></category>

		<guid isPermaLink="false">http://ammonlauritzen.com/blog/2008/03/18/svn-whitespace-blues/</guid>
		<description><![CDATA[For the longest time, I have been suffering with problems of changes whitespace rendering SVN diffs useless.
Sometimes it&#8217;s the spaces vs tabs issue. Sometimes it&#8217;s file line endings (silly Windows-only editors and their CRLF). And sometimes it&#8217;s just people adjusting whitespace arbitrarily on lines (like adding spaces around parens or leaving spaces at the end [...]]]></description>
			<content:encoded><![CDATA[<p>For the longest time, I have been suffering with problems of changes whitespace rendering SVN diffs useless.</p>
<p>Sometimes it&#8217;s the spaces vs tabs issue. Sometimes it&#8217;s file line endings (silly Windows-only editors and their CRLF). And sometimes it&#8217;s just people adjusting whitespace arbitrarily on lines (like adding spaces around parens or leaving spaces at the end of lines, etc&#8230;).</p>
<p>Regardless of the individual manifestation, it&#8217;s a silly problem, but one that causes more than its share of tears among developers everywhere.</p>
<p>Perhaps the easiest and smartest solution is to browbeat your co-developers into compliance. Force people to use editors that preserve line endings, force them to strip trailing whitespace and conform to a universal standard of indentation, etc&#8230; but it&#8217;s not always the nicest or most reliable solution. People will make mistakes, even if it&#8217;s only once a month&#8230; going over that diff might cost you an hour to figure out what had actually changed.</p>
<p>There are a few other solutions out there. They&#8217;re not new, and they&#8217;re not for everyone&#8230; but they can be phenomenally helpful at times. I&#8217;ll go over the two simplest ones.</p>
<h3>dos2unix</h3>
<p>Ever gotten a diff that reads like this?</p>
<pre style='border: thin solid black; padding: 0.25em'><code>ammon@binky:~/test$ <b>svn diff one</b>
Index: one
===================================================================
--- one (revision 2)
+++ one (working copy)
@@ -1,11 +1,11 @@
-One is the loneliest number that you'll ever do
-Two can be as bad as one
-It's the loneliest number since the number one
-
-No is the saddest experience you'll ever know
-Yes, it's the saddest experience you'll ever know
-`Cause one is the loneliest number that you'll ever do
-One is the loneliest number, worse than two
-
-It's just no good anymore since she went away
-Now I spend my time just making rhymes of yesterday
+One is the loneliest number that you'll ever do
+Two can be as bad as one
+It's the loneliest number since the number one
+
+No is the saddest experience you'll ever know
+Yes, it's the saddest experience you'll ever know
+'cause one is the loneliest number that you'll ever do
+One is the loneliest number, worse than two
+
+It's just no good anymore since she went away
+Now I spend my time just making rhymes of yesterday
</code></pre>
<p>This is what happens when something changes the line endings of a file. In this case, the original file was created with LF endings and was then edited slightly by an application that converted them to CRLF.</p>
<p>Now&#8230; if this were a 1000 line perl script in stead of an 11 line lyrics snippet&#8230; it would be soulcrushingly difficult to find the one actual change in the file.</p>
<p>Most unix distros have at their disposal the dos2unix / unix2dos utilities. On Red Hat, you can <code>yum install dos2unix</code> to get them. On Debian/Ubuntu, you can <code>apt-get install tofrodos</code>. I don&#8217;t have any other unices lying around at present to check on, but you can always just get the source at <a href='http://www.thefreecountry.com/tofrodos/index.shtml'>http://www.thefreecountry.com/tofrodos</a>.</p>
<pre style='border: thin solid black; padding: 0.25em'><code>ammon@binky:~/test$ <b>dos2unix one</b>
ammon@binky:~/test$ <b>svn diff one</b>
Index: one
===================================================================
--- one (revision 2)
+++ one (working copy)
@@ -4,7 +4,7 @@

 No is the saddest experience you'll ever know
 Yes, it's the saddest experience you'll ever know
-`Cause one is the loneliest number that you'll ever do
+`cause one is the loneliest number that you'll ever do
 One is the loneliest number, worse than two

 It's just no good anymore since she went away
</code></pre>
<p>Much easier to figure out what has changed this way.</p>
<p>For extra credit, look into the <a href='http://svnbook.red-bean.com/en/1.4/svn.advanced.props.file-portability.html#svn.advanced.props.special.eol-style'>svn:eol-style</a> property. Set this on files as you commit them &#8211; or just use <a href='http://svnbook.red-bean.com/en/1.4/svn.advanced.props.html#svn.advanced.props.auto'>autoprops</a> to do the dirty work for you&#8230;</p>
<h3>diff-cmd</h3>
<p>Of course, some times it&#8217;s not line endings. Sometimes the problem is random meaningless whitespace changes. Maybe somebody used an editor that auto-indents with spaces when the file was already indented with tabs, etc&#8230;</p>
<p>Subversion allows you to specify an alternate command to use to generate your diffs (in stead of relying on svn&#8217;s internal diff generation). </p>
<pre style='border: thin solid black; padding: 0.25em'><code>ammon@binky:~/test$ <b>svn diff ----diff-cmd /usr/bin/diff -x -w one</b>
Index: one
===================================================================
7c7
< `Cause one is the loneliest number that you'll ever do
---
> `cause one is the loneliest number that you'll ever do
</code></pre>
<p>But what if (for some bizarre reason) you don&#8217;t care about the case of letters?</p>
<pre style='border: thin solid black; padding: 0.25em'><code>ammon@binky:~/test$ <b>svn diff ----diff-cmd /usr/bin/diff -x -iw one</b>
Index: one
===================================================================
</code></pre>
<p>If you always want to use your <a href='http://svnbook.red-bean.com/en/1.4/svn.advanced.externaldifftools.html#svn.advanced.externaldifftools.diff'>custom diff utility</a> you can set it in your runtime config to save yourself the hassle of having to type it manually each time.</p>
<p>For those using TortoiseSVN, you can always just specify graphical diff/merge utils to use in stead of Tortoise&#8217;s builtin ones. Personally, I&#8217;m a big fan of <a href='http://winmerge.org/'>WinMerge</a>, but there are several other good ones out there.</p>
]]></content:encoded>
			<wfw:commentRss>http://ammonlauritzen.com/blog/2008/03/18/svn-whitespace-blues/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>php post method</title>
		<link>http://ammonlauritzen.com/blog/2007/10/18/php-post-method/</link>
		<comments>http://ammonlauritzen.com/blog/2007/10/18/php-post-method/#comments</comments>
		<pubDate>Thu, 18 Oct 2007 18:52:51 +0000</pubDate>
		<dc:creator>Ammon</dc:creator>
				<category><![CDATA[programming]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[networking]]></category>
		<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://ammonlauritzen.com/blog/2007/10/18/php-post-method/</guid>
		<description><![CDATA[
Yes, I know you can do this via cURL. This was explicitly written for a case when that particular luxury was not available to me.

So&#8230; it&#8217;s been a while since I&#8217;ve written a post, and I&#8217;m feeling the withdrawals. I&#8217;ve got 16 half-written posts waiting in the queue and two more that I want to [...]]]></description>
			<content:encoded><![CDATA[<blockquote><p>
<i>Yes, I know you can do this via <a href='http://php.net/curl'>cURL</a>. This was explicitly written for a case when that particular luxury was not available to me.</i>
</p></blockquote>
<p>So&#8230; it&#8217;s been a while since I&#8217;ve written a post, and I&#8217;m feeling the withdrawals. I&#8217;ve got 16 half-written posts waiting in the queue and two more that I want to write but haven&#8217;t even started. It&#8217;s <u>also</u> time for another round of anime reviews; I&#8217;ve got two video games I want to review&#8230;</p>
<p>And I am having to play the &#8220;too busy with RL&#8221; card.</p>
<p>In stead, I present a function that I wrote this morning. It&#8217;s been done countless times before, and you can probably find incredibly similar code out there already, but it&#8217;s the first time I&#8217;ve ever actually needed something quite like this.</p>
<pre class="brush: php;">
/**
 * Send post data somewhere <img src='http://ammonlauritzen.com/blog/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' />
 *
 * @param $host The domain name of the host to send the data to.
 * @param $path The path of the script to receive the post.
 * @param $data An array of key/value pairs to send.
 * @return       The HTTP response, headers and all.
 */
function http_post( $host, $path, $data ) {
	// build a query string from the data array
	$arr = array();
	foreach( $data as $key =&gt; $val )
		array_push( $arr, &quot;$key=&quot;.urlencode($val) );
	$data = implode( &quot;&amp;&quot;, $arr );
	// send that post
	$fh = fsockopen( $host, 80 );
	fwrite( $fh, &quot;POST $path HTTP/1.1\\\r\\\n&quot; );
	fwrite( $fh, &quot;Host: $host\\\r\\\n&quot; );
	fwrite( $fh, &quot;Content-type: application/x-www-form-urlencoded\\\r\\\n&quot; );
	fwrite( $fh, &quot;Content-length: &quot;.strlen($data).&quot;\\\r\\\n&quot; );
	fwrite( $fh, &quot;Connection: close\\\r\\\n\\\r\\\n&quot; );
	fwrite( $fh, $data );
	// get the response
	while( !feof($fh) )
		$buf .= fgets( $fh );
	fclose( $fh );
	return $buf;
}// end: http_post
</pre>
<p>This method could easily be modified to send GET data or to talk over a different port. It could also probably actually do something with the response buffer (check for 200, etc&#8230;). It could be a bit more fault tolerant, etc&#8230; but that&#8217;s not what I need for the application at hand.</p>
<p>For other examples of how people have done similar/related things, take a look at the comments on the <a href='http://www.php.net/fsockopen'>fsockopen()</a> documentation page.</p>
]]></content:encoded>
			<wfw:commentRss>http://ammonlauritzen.com/blog/2007/10/18/php-post-method/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>
