<?xml version="1.0" encoding="UTF-8"?>
<!-- generator="wordpress/2.3.3" -->
<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/"
	>

<channel>
	<title>SellingSource Developer Blog</title>
	<link>http://dev.sellingsource.com</link>
	<description>Tutorials, Code Snippets and Useful Knowledge</description>
	<pubDate>Thu, 05 Jun 2008 21:27:45 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.3.3</generator>
	<language>en</language>
			<item>
		<title>PHP CLI: A Cinderella Story</title>
		<link>http://dev.sellingsource.com/2008/06/05/php-cli-a-cinderella-story/</link>
		<comments>http://dev.sellingsource.com/2008/06/05/php-cli-a-cinderella-story/#comments</comments>
		<pubDate>Thu, 05 Jun 2008 21:27:45 +0000</pubDate>
		<dc:creator>andrewm</dc:creator>
		
		<category><![CDATA[PHP]]></category>

		<category><![CDATA[Performance]]></category>

		<category><![CDATA[Slides]]></category>

		<category><![CDATA[dcphp2008]]></category>

		<guid isPermaLink="false">http://dev.sellingsource.com/2008/06/05/php-cli-a-cinderella-story/</guid>
		<description><![CDATA[This past Tuesday, Mike Lively and I presented "PHP CLI: A Cinderella Story" at the 2008 DC PHP conference. The presentation introduced the advantages of moving the heavy lifting from your web pages into backgrounded CLI scripts and ranged from the basics of writing backgrounded CLI scripts in PHP to more advanced multi-process and distributed [...]]]></description>
			<content:encoded><![CDATA[This past Tuesday, <a href="http://www.ds-o.com">Mike Lively</a> and I presented "PHP CLI: A Cinderella Story" at the <a href="http://www.dcphpconference.com/">2008 DC PHP conference</a>. The presentation introduced the advantages of moving the heavy lifting from your web pages into backgrounded CLI scripts and ranged from the basics of writing backgrounded CLI scripts in PHP to more advanced multi-process and distributed processing.<br />
<br />
The slides are embedded below.<br />
<br />
<div style="width:425px;text-align:left" id="__ss_446664"><object style="margin:0px" width="425" height="355"><param name="movie" value="http://static.slideshare.net/swf/ssplayer2.swf?doc=php-cli2-1212588120708000-8"/><param name="allowFullScreen" value="true"/><param name="allowScriptAccess" value="always"/><embed src="http://static.slideshare.net/swf/ssplayer2.swf?doc=php-cli2-1212588120708000-8" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"></embed></object><div style="font-size:11px;font-family:tahoma,arial;height:26px;padding-top:2px;"><a href="http://www.slideshare.net/?src=embed"><img src="http://static.slideshare.net/swf/logo_embd.png" style="border:0px none;margin-bottom:-5px" alt="SlideShare"/></a> | <a href="http://www.slideshare.net/mjlivelyjr/php-cli-a-cinderella-story?src=embed" title="View PHP CLI: A Cinderella Story on SlideShare">View</a> | <a href="http://www.slideshare.net/upload?src=embed">Upload your own</a></div></div><br />
<br />
We're still preparing the code examples that we were unable to show during the presentation. Stay tuned.]]></content:encoded>
			<wfw:commentRss>http://dev.sellingsource.com/2008/06/05/php-cli-a-cinderella-story/feed/</wfw:commentRss>
		</item>
		<item>
		<title>A Magical Lullaby</title>
		<link>http://dev.sellingsource.com/2007/11/07/a-magical-lullaby/</link>
		<comments>http://dev.sellingsource.com/2007/11/07/a-magical-lullaby/#comments</comments>
		<pubDate>Thu, 08 Nov 2007 01:40:33 +0000</pubDate>
		<dc:creator>andrewm</dc:creator>
		
		<category><![CDATA[PHP]]></category>

		<category><![CDATA[Patches]]></category>

		<guid isPermaLink="false">http://dev.sellingsource.com/2007/11/07/a-magical-lullaby/</guid>
		<description><![CDATA[When you want to take control over the state of your objects as they're serialized, PHP provides two magical functions to help you. As the documentation states:

The intended use of __sleep is to commit pending data or perform similar cleanup tasks. Also, the function is useful if you have very large objects which do not [...]]]></description>
			<content:encoded><![CDATA[When you want to take control over the state of your objects as they're serialized, PHP provides two <a href="http://www.php.net/manual/en/language.oop5.magic.php">magical functions</a> to help you. As the documentation states:<br />
<br />
<blockquote>The intended use of __sleep is to commit pending data or perform similar cleanup tasks. Also, the function is useful if you have very large objects which do not need to be saved completely. Conversely, [...] the intended use of __wakeup is to reestablish any database connections that may have been lost during serialization and perform other reinitialization tasks.</blockquote><br />
<br />
Unfortunately, there's one gotcha that severely limits the usefulness of this magic. Unless the __sleep method returns an array of the member names that you want serialized, the entire object gets serialized as null. This requirement is not only contradictory to the stated "intended use", it's nearly impossible to satisfy.<br />
<br />
To explore this further, consider the example given in the <a href="http://www.php.net/manual/en/language.oop5.magic.php">documentation</a>: a simple database wrapper. Now I'm not really sure why you'd want to serialize a database connection, but we'll assume you have to.  You can't actually serialize the underlying resource that the connection is using, so you'll need to disconnect it before serialization occurs. That's all we need the __sleep method to do.<br />
<br />
We could -- like the example -- disconnect and return a hard-coded list of our properties. Maintenance hell. So let's write a function that will properly build a list of all the properties (public, protected, AND private) in a child and all its ancestors.<br />
<br />
<div class="codeblock"><code><span class="synSpecial">&lt;?php</span><br />&nbsp; &nbsp; <span class="synType">class</span> Connection <span class="synSpecial">{</span><br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synSpecial">[</span><span class="synStatement">...</span><span class="synSpecial">]</span><br /><br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synType">public</span> <span class="synPreProc">function</span> <span class="synStatement">__sleep</span><span class="synSpecial">()</span><br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synSpecial">{</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synIdentifier">mysql_close</span><span class="synSpecial">(</span><span class="synStatement">$</span><span class="synIdentifier">this</span><span class="synType">-&gt;</span><span class="synIdentifier">link</span><span class="synSpecial">)</span>;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">return</span> <span class="synStatement">$</span><span class="synIdentifier">this</span><span class="synType">-&gt;</span>getPropertyNames<span class="synSpecial">()</span>;<br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synSpecial">}</span><br />&nbsp; &nbsp; &nbsp; &nbsp; <br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synType">public</span> <span class="synPreProc">function</span> getPropertyNames<span class="synSpecial">(</span><span class="synType">array</span> <span class="synStatement">$</span><span class="synIdentifier">filter</span> <span class="synStatement">=</span> <span class="synType">NULL</span><span class="synSpecial">)</span><br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synSpecial">{</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">$</span><span class="synIdentifier">rc</span> <span class="synStatement">=</span> <span class="synPreProc">new</span> <span class="synIdentifier">ReflectionObject</span><span class="synSpecial">(</span><span class="synStatement">$</span><span class="synIdentifier">this</span><span class="synSpecial">)</span>;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">$</span><span class="synIdentifier">names</span> <span class="synStatement">=</span> <span class="synType">array</span><span class="synSpecial">()</span>;<br /><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">while</span> <span class="synSpecial">(</span><span class="synStatement">$</span><span class="synIdentifier">rc</span> <span class="synStatement">instanceof</span> <span class="synIdentifier">ReflectionClass</span><span class="synSpecial">)</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synSpecial">{</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">foreach</span> <span class="synSpecial">(</span><span class="synStatement">$</span><span class="synIdentifier">rc</span><span class="synType">-&gt;</span>getProperties<span class="synSpecial">()</span> <span class="synStatement">as</span> <span class="synStatement">$</span><span class="synIdentifier">prop</span><span class="synSpecial">)</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synSpecial">{</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">if</span> <span class="synSpecial">(</span><span class="synStatement">!$</span><span class="synIdentifier">filter</span> <span class="synStatement">||</span> <span class="synStatement">!</span><span class="synIdentifier">in_array</span><span class="synSpecial">(</span><span class="synStatement">$</span><span class="synIdentifier">prop</span><span class="synType">-&gt;</span>getName<span class="synSpecial">()</span>, <span class="synStatement">$</span><span class="synIdentifier">filter</span><span class="synSpecial">))</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">$</span><span class="synIdentifier">names</span><span class="synSpecial">[]</span> <span class="synStatement">=</span> <span class="synStatement">$</span><span class="synIdentifier">prop</span><span class="synType">-&gt;</span>getName<span class="synSpecial">()</span>;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synSpecial">}</span><br /><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">$</span><span class="synIdentifier">rc</span> <span class="synStatement">=</span> <span class="synStatement">$</span><span class="synIdentifier">rc</span><span class="synType">-&gt;</span>getParentClass<span class="synSpecial">()</span>;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synSpecial">}</span><br /><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">return</span> <span class="synStatement">$</span><span class="synIdentifier">names</span>;<br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synSpecial">}</span><br /><br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synSpecial">[</span><span class="synStatement">...</span><span class="synSpecial">]</span><br />&nbsp; &nbsp; <span class="synSpecial">}</span><br /><span class="synSpecial">?&gt;</span><br /></code></div><br />
<br />
What a nightmare, and just to close a connection. That's why I created a patch that will allow __sleep to return NULL, in which case the object is serialized as usual. You can find it (for the PHP_5_3 branch and HEAD) attached to my <a href="http://news.php.net/php.internals/33041">message</a> to the internals list. Let's hope it gets committed.]]></content:encoded>
			<wfw:commentRss>http://dev.sellingsource.com/2007/11/07/a-magical-lullaby/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Multi-Process Persistent Applications: Part 2 - Multiple Children</title>
		<link>http://dev.sellingsource.com/2007/08/10/multi-process-persistent-applications-part-2-multiple-children/</link>
		<comments>http://dev.sellingsource.com/2007/08/10/multi-process-persistent-applications-part-2-multiple-children/#comments</comments>
		<pubDate>Fri, 10 Aug 2007 19:16:48 +0000</pubDate>
		<dc:creator>johnh</dc:creator>
		
		<category><![CDATA[Linux]]></category>

		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://dev.sellingsource.com/?p=16</guid>
		<description><![CDATA[Introduction
In the first part of this tutorial, we covered the basics of forking and detaching from the terminal. That tutorial was very procedural and straight forward.  In this tutorial we're going to be dealing with multiple child forks.  This part is going to be significantly more complicated than the previous, so don't feel [...]]]></description>
			<content:encoded><![CDATA[<h4>Introduction</h4><br />
In the first part of this tutorial, we covered the basics of forking and detaching from the terminal. That tutorial was very procedural and straight forward.  In this tutorial we're going to be dealing with multiple child forks.  This part is going to be significantly more complicated than the previous, so don't feel bad if you begin to feel overwhelmed at some point. It will all come to you in time!<br />
<br />
<h4>The Base Class: Forking, Signal Handling</h4><br />
The first step in handling multiple forks is going to be isolating the forking mechanism in a class, so that we can utilize it many times over.  The way I'm going to do this is by creating a base class that will handle the forking itself, and create a loop where child classes can implement functionality.  That is, my first class <b>ForkedProcess</b> will be abstract and never instantiated.  It will expect a child class to implement a method which will be executed <em>N</em> times per second.  It is at this point of execution that the child class can choose to do work, or it can do nothing.  This will be the persisting loop of that particular process, and upon being broken, that process will exit.  <br />
<br />
So, first off, let's create a class. I have created a fairly basic implementation which we will later expand to handle more complicated functionality.  For now, our goal is merely to create a class which handles forking.  It is not yet ready to be used.<br />
<br />
<b>ForkedProcess.php</b><br />
<div class="codeblock"><code><span class="synSpecial">&lt;?php</span><br />&nbsp; &nbsp; <span class="synStatement">declare</span> <span class="synSpecial">(</span>ticks <span class="synStatement">=</span> <span class="synConstant">1</span><span class="synSpecial">)</span>;<br />&nbsp; &nbsp; <span class="synType">abstract</span> <span class="synType">class</span> ForkedProcess<br />&nbsp; &nbsp; <span class="synSpecial">{</span><br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synType">protected</span> <span class="synStatement">$</span><span class="synIdentifier">continue_execution</span>;<br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synType">protected</span> <span class="synStatement">$</span><span class="synIdentifier">detached</span> <span class="synStatement">=</span> <span class="synConstant">FALSE</span>;<br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synType">protected</span> <span class="synStatement">$</span><span class="synIdentifier">sleep_time</span>;<br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synType">protected</span> <span class="synStatement">$</span><span class="synIdentifier">PID</span>;<br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synType">protected</span> <span class="synStatement">$</span><span class="synIdentifier">signal_cache</span> <span class="synStatement">=</span> <span class="synType">array</span><span class="synSpecial">()</span>;<br /><br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synComment">/**</span><br /><span class="synComment">&nbsp; &nbsp; &nbsp; &nbsp;  * @param int $sleep_time Time to sleep between each poll</span><br /><span class="synComment">&nbsp; &nbsp; &nbsp; &nbsp;  */</span><br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synType">public</span> <span class="synPreProc">function</span> <span class="synStatement">__construct</span><span class="synSpecial">(</span><span class="synStatement">$</span><span class="synIdentifier">sleep_time</span> <span class="synStatement">=</span> <span class="synConstant">100000</span><span class="synSpecial">)</span><br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synSpecial">{</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">$</span><span class="synIdentifier">this</span><span class="synType">-&gt;</span>sleep_time <span class="synStatement">=</span> <span class="synStatement">$</span><span class="synIdentifier">sleep_time</span>;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">$</span><span class="synIdentifier">this</span><span class="synType">-&gt;</span>signal_cache <span class="synStatement">=</span> <span class="synIdentifier">array_fill</span><span class="synSpecial">(</span><span class="synConstant">0</span>, <span class="synConstant">64</span>, <span class="synConstant">FALSE</span><span class="synSpecial">)</span>;<br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synSpecial">}</span><br /><br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synComment">/**</span><br /><span class="synComment">&nbsp; &nbsp; &nbsp; &nbsp;  * Function that stores signals very quickly. Acts as the signal handler for php.</span><br /><span class="synComment">&nbsp; &nbsp; &nbsp; &nbsp;  *</span><br /><span class="synComment">&nbsp; &nbsp; &nbsp; &nbsp;  * @param int $signal</span><br /><span class="synComment">&nbsp; &nbsp; &nbsp; &nbsp;  */</span><br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synType">protected</span> <span class="synPreProc">function</span> handleSignal<span class="synSpecial">(</span><span class="synStatement">$</span><span class="synIdentifier">signal</span><span class="synSpecial">)</span><br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synSpecial">{</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">$</span><span class="synIdentifier">this</span><span class="synType">-&gt;</span>signal_cache<span class="synSpecial">[</span><span class="synStatement">$</span><span class="synIdentifier">signal</span><span class="synSpecial">]</span> <span class="synStatement">=</span> <span class="synConstant">TRUE</span>;<br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synSpecial">}</span><br /><br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synComment">/**</span><br /><span class="synComment">&nbsp; &nbsp; &nbsp; &nbsp;  * @param int $signal</span><br /><span class="synComment">&nbsp; &nbsp; &nbsp; &nbsp;  */</span><br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synType">protected</span> <span class="synPreProc">function</span> enableSignal<span class="synSpecial">(</span><span class="synStatement">$</span><span class="synIdentifier">signal</span><span class="synSpecial">)</span><br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synSpecial">{</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synIdentifier">pcntl_signal</span><span class="synSpecial">(</span><span class="synStatement">$</span><span class="synIdentifier">signal</span>, <span class="synType">array</span><span class="synSpecial">(</span><span class="synStatement">$</span><span class="synIdentifier">this</span>, &quot;<span class="synConstant">handleSignal</span>&quot;<span class="synSpecial">))</span>;<br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synSpecial">}</span><br /><br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synComment">/**</span><br /><span class="synComment">&nbsp; &nbsp; &nbsp; &nbsp;  * returns TRUE if the signal has been received. If it has been received,</span><br /><span class="synComment">&nbsp; &nbsp; &nbsp; &nbsp;  * the signal is reset in the signal cache.</span><br /><span class="synComment">&nbsp; &nbsp; &nbsp; &nbsp;  *</span><br /><span class="synComment">&nbsp; &nbsp; &nbsp; &nbsp;  * @param int $signal</span><br /><span class="synComment">&nbsp; &nbsp; &nbsp; &nbsp;  * @return bool</span><br /><span class="synComment">&nbsp; &nbsp; &nbsp; &nbsp;  */</span><br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synType">protected</span> <span class="synPreProc">function</span> hasSignal<span class="synSpecial">(</span><span class="synStatement">$</span><span class="synIdentifier">signal</span><span class="synSpecial">)</span><br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synSpecial">{</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">if</span> <span class="synSpecial">(</span><span class="synStatement">$</span><span class="synIdentifier">this</span><span class="synType">-&gt;</span>signal_cache<span class="synSpecial">[</span><span class="synStatement">$</span><span class="synIdentifier">signal</span><span class="synSpecial">])</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synSpecial">{</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">$</span><span class="synIdentifier">this</span><span class="synType">-&gt;</span>signal_cache<span class="synSpecial">[</span><span class="synStatement">$</span><span class="synIdentifier">signal</span><span class="synSpecial">]</span> <span class="synStatement">=</span> <span class="synConstant">FALSE</span>;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">return</span> <span class="synConstant">TRUE</span>;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synSpecial">}</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">return</span> <span class="synConstant">FALSE</span>;<br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synSpecial">}</span><br /><br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synComment">/**</span><br /><span class="synComment">&nbsp; &nbsp; &nbsp; &nbsp;  * @param string $message</span><br /><span class="synComment">&nbsp; &nbsp; &nbsp; &nbsp;  */</span><br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synType">protected</span> <span class="synPreProc">function</span> debug<span class="synSpecial">(</span><span class="synStatement">$</span><span class="synIdentifier">message</span><span class="synSpecial">)</span><br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synSpecial">{</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synPreProc">echo</span> &quot;<span class="synSpecial">{</span><span class="synStatement">$</span><span class="synIdentifier">this</span><span class="synType">-&gt;</span>PID<span class="synSpecial">}\\</span>&quot;<span class="synStatement">.</span><span class="synIdentifier">get_class</span><span class="synSpecial">(</span><span class="synStatement">$</span><span class="synIdentifier">this</span><span class="synSpecial">)</span><span class="synStatement">.</span>&quot;<span class="synConstant">&gt; </span>&quot; <span class="synStatement">.</span> <span class="synStatement">$</span><span class="synIdentifier">message</span> <span class="synStatement">.</span> &quot;<span class="synSpecial">\n</span>&quot;;<br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synSpecial">}</span><br /><br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synComment">/**</span><br /><span class="synComment">&nbsp; &nbsp; &nbsp; &nbsp;  * Create background fork.</span><br /><span class="synComment">&nbsp; &nbsp; &nbsp; &nbsp;  * @return int The PID of the child process</span><br /><span class="synComment">&nbsp; &nbsp; &nbsp; &nbsp;  */</span><br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synType">public</span> <span class="synPreProc">function</span> fork<span class="synSpecial">(</span><span class="synStatement">$</span><span class="synIdentifier">detach</span> <span class="synStatement">=</span> <span class="synConstant">TRUE</span><span class="synSpecial">)</span><br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synSpecial">{</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">$</span><span class="synIdentifier">PID</span> <span class="synStatement">=</span> <span class="synIdentifier">pcntl_fork</span><span class="synSpecial">()</span>;<br /><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">if</span> <span class="synSpecial">(</span><span class="synStatement">$</span><span class="synIdentifier">PID</span> <span class="synStatement">==</span> <span class="synConstant">-1</span><span class="synSpecial">)</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synSpecial">{</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">throw</span> <span class="synPreProc">new</span> <span class="synIdentifier">Exception</span><span class="synSpecial">(</span>&quot;<span class="synConstant">Unable to fork</span>&quot;<span class="synSpecial">)</span>;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synSpecial">}</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">else</span> <span class="synStatement">if</span> <span class="synSpecial">(</span><span class="synStatement">$</span><span class="synIdentifier">PID</span> <span class="synStatement">&gt;</span> <span class="synConstant">0</span><span class="synSpecial">)</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synSpecial">{</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">return</span> <span class="synStatement">$</span><span class="synIdentifier">PID</span>;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synSpecial">}</span><br /><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">$</span><span class="synIdentifier">this</span><span class="synType">-&gt;</span>enableSignal<span class="synSpecial">(</span>SIGTERM<span class="synSpecial">)</span>;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">$</span><span class="synIdentifier">this</span><span class="synType">-&gt;</span>enableSignal<span class="synSpecial">(</span>SIGINT<span class="synSpecial">)</span>;<br /><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">if</span> <span class="synSpecial">(</span><span class="synStatement">$</span><span class="synIdentifier">detach</span> <span class="synStatement">==</span> <span class="synConstant">TRUE</span><span class="synSpecial">)</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synSpecial">{</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">if</span> <span class="synSpecial">(</span><span class="synIdentifier">posix_setsid</span><span class="synSpecial">()</span> <span class="synStatement">==</span> <span class="synConstant">-1</span><span class="synSpecial">)</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synSpecial">{</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">throw</span> <span class="synPreProc">new</span> <span class="synIdentifier">Exception</span><span class="synSpecial">(</span>&quot;<span class="synConstant">Unable to detach from controlling terminal!</span>&quot;<span class="synSpecial">)</span>;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synSpecial">}</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">$</span><span class="synIdentifier">this</span><span class="synType">-&gt;</span>detached <span class="synStatement">=</span> <span class="synConstant">TRUE</span>;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synSpecial">}</span><br /><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">$</span><span class="synIdentifier">this</span><span class="synType">-&gt;</span>PID <span class="synStatement">=</span> <span class="synIdentifier">posix_getpid</span><span class="synSpecial">()</span>;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">$</span><span class="synIdentifier">this</span><span class="synType">-&gt;</span>continue_execution <span class="synStatement">=</span> <span class="synConstant">TRUE</span>;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">$</span><span class="synIdentifier">this</span><span class="synType">-&gt;</span>onStartup<span class="synSpecial">()</span>;<br /><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">while</span> <span class="synSpecial">(</span><span class="synStatement">$</span><span class="synIdentifier">this</span><span class="synType">-&gt;</span>continue_execution<span class="synSpecial">)</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synSpecial">{</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">if</span> <span class="synSpecial">(</span><span class="synStatement">$</span><span class="synIdentifier">this</span><span class="synType">-&gt;</span>hasSignal<span class="synSpecial">(</span>SIGTERM<span class="synSpecial">)</span> <span class="synStatement">||</span> <span class="synStatement">$</span><span class="synIdentifier">this</span><span class="synType">-&gt;</span>hasSignal<span class="synSpecial">(</span>SIGINT<span class="synSpecial">))</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synSpecial">{</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">$</span><span class="synIdentifier">this</span><span class="synType">-&gt;</span>quit<span class="synSpecial">()</span>;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synSpecial">}</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">$</span><span class="synIdentifier">this</span><span class="synType">-&gt;</span>tick<span class="synSpecial">()</span>;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synIdentifier">usleep</span><span class="synSpecial">(</span><span class="synStatement">$</span><span class="synIdentifier">this</span><span class="synType">-&gt;</span>sleep_time<span class="synSpecial">)</span>;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synSpecial">}</span><br /><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">exit</span><span class="synSpecial">(</span><span class="synConstant">0</span><span class="synSpecial">)</span>;<br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synSpecial">}</span><br /><br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synType">protected</span> <span class="synPreProc">function</span> quit<span class="synSpecial">()</span><br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synSpecial">{</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">$</span><span class="synIdentifier">this</span><span class="synType">-&gt;</span>continue_execution <span class="synStatement">=</span> <span class="synConstant">FALSE</span>;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">$</span><span class="synIdentifier">this</span><span class="synType">-&gt;</span>onExit<span class="synSpecial">()</span>;<br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synSpecial">}</span><br /><br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synType">protected</span> <span class="synType">abstract</span> <span class="synPreProc">function</span> onStartup<span class="synSpecial">()</span>;<br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synType">protected</span> <span class="synType">abstract</span> <span class="synPreProc">function</span> onExit<span class="synSpecial">()</span>;<br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synType">protected</span> <span class="synType">abstract</span> <span class="synPreProc">function</span> tick<span class="synSpecial">()</span>;<br />&nbsp; &nbsp; <span class="synSpecial">}</span><br /><span class="synSpecial">?&gt;</span><br /></code></div><br />
<br />
You'll notice a few very important additions to the functionality, as well as some simple event handler prototypes which do nothing.   The big addition here is the handling of signals.  Signals are sent to the process by the operating system and act as instructions to do something. Usually, this is a kill order.  There are constants in PHP which represent integer values of the signals typically sent. To see a full list of the signals on your system, you can run the following command:<br />
<br />
<div class="codeblock"><code>root@localhost ~ # kill -l<br /> 1) SIGHUP&nbsp; &nbsp; &nbsp;  2) SIGINT&nbsp; &nbsp; &nbsp;  3) SIGQUIT&nbsp; &nbsp; &nbsp; 4) SIGILL<br /> 5) SIGTRAP&nbsp; &nbsp; &nbsp; 6) SIGABRT&nbsp; &nbsp; &nbsp; 7) SIGBUS&nbsp; &nbsp; &nbsp;  8) SIGFPE<br /> 9) SIGKILL&nbsp; &nbsp;  10) SIGUSR1&nbsp; &nbsp;  11) SIGSEGV&nbsp; &nbsp;  12) SIGUSR2<br />13) SIGPIPE&nbsp; &nbsp;  14) SIGALRM&nbsp; &nbsp;  15) SIGTERM&nbsp; &nbsp;  16) SIGSTKFLT<br />17) SIGCHLD&nbsp; &nbsp;  18) SIGCONT&nbsp; &nbsp;  19) SIGSTOP&nbsp; &nbsp;  20) SIGTSTP<br />21) SIGTTIN&nbsp; &nbsp;  22) SIGTTOU&nbsp; &nbsp;  23) SIGURG&nbsp; &nbsp; &nbsp; 24) SIGXCPU<br />25) SIGXFSZ&nbsp; &nbsp;  26) SIGVTALRM&nbsp;  27) SIGPROF&nbsp; &nbsp;  28) SIGWINCH<br />29) SIGIO&nbsp; &nbsp; &nbsp;  30) SIGPWR&nbsp; &nbsp; &nbsp; 31) SIGSYS&nbsp; &nbsp; &nbsp; 34) SIGRTMIN<br />35) SIGRTMIN+1&nbsp; 36) SIGRTMIN+2&nbsp; 37) SIGRTMIN+3&nbsp; 38) SIGRTMIN+4<br />39) SIGRTMIN+5&nbsp; 40) SIGRTMIN+6&nbsp; 41) SIGRTMIN+7&nbsp; 42) SIGRTMIN+8<br />43) SIGRTMIN+9&nbsp; 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12<br />47) SIGRTMIN+13 48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14<br />51) SIGRTMAX-13 52) SIGRTMAX-12 53) SIGRTMAX-11 54) SIGRTMAX-10<br />55) SIGRTMAX-9&nbsp; 56) SIGRTMAX-8&nbsp; 57) SIGRTMAX-7&nbsp; 58) SIGRTMAX-6<br />59) SIGRTMAX-5&nbsp; 60) SIGRTMAX-4&nbsp; 61) SIGRTMAX-3&nbsp; 62) SIGRTMAX-2<br />63) SIGRTMAX-1&nbsp; 64) SIGRTMAX<br /></code></div><br />
<br />
The signals we care the most about are <b>SIGTERM</b> <em>(OS telling us to exit)</em> and <b>SIGINT</b> <em>(Similar to SIGTERM but usually caused by Ctrl+C from the terminal)</em>.  Typically, PHP handles these for us.  The reason we're taking over this process is to create a standard way of handling shutdown tasks within an object, without using <b>register_shutdown_function</b>, destructors, or anything like that. We specifically want to do fork-specific shutdown tasks which should not happen in certain situations.  The base class itself does not have any shutdown tasks, but it expects the child class to implement a couple of functions: <b>onExit()</b> and <b>onStartup()</b> which is meant to be overriden in child classes, so that those classes can do special clean up. The <b>ForkedParentProcess</b>, for example, will want to clean up child processes before it is allowed to exit. PHP provides access to this functionality through the <b>pcntl_signal()</b> function, which we wrap for ease of use.  An important thing to remember is that a signal handler should always exit <em>as quickly as possible</em>.  That is why we keep a private variable ($signal_cache) which represents any signals received.<br />
<br />
Another thing you should notice is this line:<br />
<div class="codeblock"><code>declare(ticks = 1);<br /></code></div><br />
PHP has a method of invoking function known as <em>tick functions</em>. I won't go into grave detail here as it's not really important, but you can read about them in the documentation <a href="http://www.php.net/manual/en/control-structures.declare.php">here</a>.<br />
<br />
Now that we have our base functionality, we need to define what types of forked processes we need.  The way we handle multiple forked child processes is by having a common parent which manages all of these children. This way, we can issue a kill to the parent process, and it will happily tell all of its children to exit as well.  In addition to that necessary functionality, it provides a common point of communication.  If we have work to delegate, the parent process can handle that.  So, we need a type of forked process that can, itself, create forks.  We can implement this by extending the base forked class to create a <b>ForkedParentProcess</b>.  We will also implement a <b>ForkedWorkerProcess</b>.  Below is a diagram to help illustrate the relationships of these processes.  <br />
<br />
<div style="text-align: center"><br />
<img src='http://dev.sellingsource.com/wp-content/uploads/2007/09/forking1.png' alt='Basic Process Layout' /><br />
</div><br />
<br />
In this diagram, the Starter Process is the process which merely starts, forks and backgrounds the Controlling Process, which is a <b>ForkedParentProcess</b>. The Starter Process then terminates, leaving the Controlling Process to create its own pool of children and to more or less <em>be</em> our persistent process. The Worker Processes in the diagram are represented in our code by the <b>ForkedWorkerProcess</b>. If the Controlling process exits, the children must be instructed to exit as well, since they are useless without a parent and will become rogue processes if we do not deal with them properly.  Below is another diagram which shows the flow of the individual processes, from inception to termination.<br />
<br />
<div style="text-align: center"><br />
<img src='http://dev.sellingsource.com/wp-content/uploads/2007/09/forking2.png' alt='Forking Flow' /><br />
</div><br />
<br />
<h4>Parent Process, Child Reaping</h4><br />
Now that we have a firm understanding of how our processes should work, we can move forward actually writing the code for them.  In this next section of code, I will introduce the concept of <em>reaping</em> which is the process of properly cleaning up exited child processes.  There's a lot of code below, so take some time to soak it up.  I will explain it all.<br />
<br />
<b>ForkedParentProcess.php</b><br />
<div class="codeblock"><code><span class="synSpecial">&lt;?php</span><br />&nbsp; &nbsp; <span class="synPreProc">require_once</span> '<span class="synConstant">ForkedProcess.php</span>';<br />&nbsp; &nbsp; <span class="synPreProc">require_once</span> '<span class="synConstant">ForkedWorkerProcess.php</span>';<br /><br />&nbsp; &nbsp; <span class="synComment">/**</span><br /><span class="synComment">&nbsp; &nbsp;  * Represents a process which spawns other (worker) processes</span><br /><span class="synComment">&nbsp; &nbsp;  */</span><br />&nbsp; &nbsp; <span class="synType">class</span> ForkedParentProcess <span class="synType">extends</span> ForkedProcess<br />&nbsp; &nbsp; <span class="synSpecial">{</span><br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synComment">/**</span><br /><span class="synComment">&nbsp; &nbsp; &nbsp; &nbsp;  * Max number of workers to maintain</span><br /><span class="synComment">&nbsp; &nbsp; &nbsp; &nbsp;  * @var int</span><br /><span class="synComment">&nbsp; &nbsp; &nbsp; &nbsp;  */</span><br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synType">private</span> <span class="synStatement">$</span><span class="synIdentifier">worker_count</span>;<br /><br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synComment">/**</span><br /><span class="synComment">&nbsp; &nbsp; &nbsp; &nbsp;  * PIDs of our child workers</span><br /><span class="synComment">&nbsp; &nbsp; &nbsp; &nbsp;  * @var array</span><br /><span class="synComment">&nbsp; &nbsp; &nbsp; &nbsp;  */</span><br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synType">private</span> <span class="synStatement">$</span><span class="synIdentifier">children</span> <span class="synStatement">=</span> <span class="synType">array</span><span class="synSpecial">()</span>;<br /><br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synComment">/**</span><br /><span class="synComment">&nbsp; &nbsp; &nbsp; &nbsp;  * @param int $worker_count Number of workers</span><br /><span class="synComment">&nbsp; &nbsp; &nbsp; &nbsp;  * @param int $sleep_time Number of microseconds to sleep between each tick</span><br /><span class="synComment">&nbsp; &nbsp; &nbsp; &nbsp;  */</span><br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synType">public</span> <span class="synPreProc">function</span> <span class="synStatement">__construct</span><span class="synSpecial">(</span><span class="synStatement">$</span><span class="synIdentifier">worker_count</span> <span class="synStatement">=</span> <span class="synConstant">5</span>, <span class="synStatement">$</span><span class="synIdentifier">sleep_time</span> <span class="synStatement">=</span> <span class="synConstant">100000</span><span class="synSpecial">)</span><br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synSpecial">{</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synType">parent</span><span class="synStatement">::__construct</span><span class="synSpecial">(</span><span class="synStatement">$</span><span class="synIdentifier">sleep_time</span><span class="synSpecial">)</span>;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">$</span><span class="synIdentifier">this</span><span class="synType">-&gt;</span>worker_count <span class="synStatement">=</span> <span class="synStatement">$</span><span class="synIdentifier">worker_count</span>;<br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synSpecial">}</span><br /><br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synComment">/**</span><br /><span class="synComment">&nbsp; &nbsp; &nbsp; &nbsp;  * Called when the process is exiting</span><br /><span class="synComment">&nbsp; &nbsp; &nbsp; &nbsp;  */</span><br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synType">public</span> <span class="synPreProc">function</span> onExit<span class="synSpecial">()</span><br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synSpecial">{</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">$</span><span class="synIdentifier">this</span><span class="synType">-&gt;</span>killChildren<span class="synSpecial">()</span>;<br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synSpecial">}</span><br /><br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synComment">/**</span><br /><span class="synComment">&nbsp; &nbsp; &nbsp; &nbsp;  * Called when the process has just started</span><br /><span class="synComment">&nbsp; &nbsp; &nbsp; &nbsp;  */</span><br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synType">public</span> <span class="synPreProc">function</span> onStartup<span class="synSpecial">()</span><br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synSpecial">{</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">$</span><span class="synIdentifier">this</span><span class="synType">-&gt;</span>debug<span class="synSpecial">(</span>&quot;<span class="synConstant">Alive</span>&quot;<span class="synSpecial">)</span>;<br /><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">while</span> <span class="synSpecial">(</span><span class="synIdentifier">count</span><span class="synSpecial">(</span><span class="synStatement">$</span><span class="synIdentifier">this</span><span class="synType">-&gt;</span><span class="synIdentifier">children</span><span class="synSpecial">)</span> <span class="synStatement">&lt;</span> <span class="synStatement">$</span><span class="synIdentifier">this</span><span class="synType">-&gt;</span>worker_count<span class="synSpecial">)</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synSpecial">{</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">$</span><span class="synIdentifier">worker</span> <span class="synStatement">=</span> <span class="synPreProc">new</span> ForkedWorkerProcess<span class="synSpecial">()</span>;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">$</span><span class="synIdentifier">this</span><span class="synType">-&gt;</span><span class="synIdentifier">children</span><span class="synSpecial">[]</span> <span class="synStatement">=</span> <span class="synStatement">$</span><span class="synIdentifier">worker</span><span class="synType">-&gt;</span>fork<span class="synSpecial">(</span><span class="synConstant">FALSE</span><span class="synSpecial">)</span>;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synSpecial">}</span><br /><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">$</span><span class="synIdentifier">this</span><span class="synType">-&gt;</span>enableSignal<span class="synSpecial">(</span>SIGCHLD<span class="synSpecial">)</span>;<br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synSpecial">}</span><br /><br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synComment">/**</span><br /><span class="synComment">&nbsp; &nbsp; &nbsp; &nbsp;  * Issues SIGTERM to all workers</span><br /><span class="synComment">&nbsp; &nbsp; &nbsp; &nbsp;  */</span><br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synType">protected</span> <span class="synPreProc">function</span> killChildren<span class="synSpecial">()</span><br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synSpecial">{</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">foreach</span> <span class="synSpecial">(</span><span class="synStatement">$</span><span class="synIdentifier">this</span><span class="synType">-&gt;</span><span class="synIdentifier">children</span> <span class="synStatement">as</span> <span class="synStatement">$</span><span class="synIdentifier">child_pid</span><span class="synSpecial">)</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synSpecial">{</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synIdentifier">posix_kill</span><span class="synSpecial">(</span><span class="synStatement">$</span><span class="synIdentifier">child_pid</span>, SIGTERM<span class="synSpecial">)</span>;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synSpecial">}</span><br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synSpecial">}</span><br /><br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synComment">/**</span><br /><span class="synComment">&nbsp; &nbsp; &nbsp; &nbsp;  * Find any exited workers and clean them up</span><br /><span class="synComment">&nbsp; &nbsp; &nbsp; &nbsp;  *</span><br /><span class="synComment">&nbsp; &nbsp; &nbsp; &nbsp;  */</span><br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synType">protected</span> <span class="synPreProc">function</span> reapChildren<span class="synSpecial">()</span><br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synSpecial">{</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">while</span> <span class="synSpecial">(</span><span class="synStatement">$</span><span class="synIdentifier">return_code</span> <span class="synStatement">=</span> pcntl_wait<span class="synSpecial">(</span><span class="synStatement">$</span><span class="synIdentifier">status</span>, WNOHANG <span class="synStatement">|</span> WUNTRACED<span class="synSpecial">))</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synSpecial">{</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">$</span><span class="synIdentifier">this</span><span class="synType">-&gt;</span>debug<span class="synSpecial">(</span>&quot;<span class="synConstant">reaping child </span>&quot; <span class="synStatement">.</span> <span class="synStatement">$</span><span class="synIdentifier">return_code</span><span class="synSpecial">)</span>;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synSpecial">}</span><br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synSpecial">}</span><br /><br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synComment">/**</span><br /><span class="synComment">&nbsp; &nbsp; &nbsp; &nbsp;  * Called each cycle</span><br /><span class="synComment">&nbsp; &nbsp; &nbsp; &nbsp;  */</span><br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synType">protected</span> <span class="synPreProc">function</span> tick<span class="synSpecial">()</span><br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synSpecial">{</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">if</span> <span class="synSpecial">(</span><span class="synStatement">$</span><span class="synIdentifier">this</span><span class="synType">-&gt;</span>hasSignal<span class="synSpecial">(</span>SIGCHLD<span class="synSpecial">))</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synSpecial">{</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">$</span><span class="synIdentifier">this</span><span class="synType">-&gt;</span>reapChildren<span class="synSpecial">()</span>;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synSpecial">}</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synComment">/**</span><br /><span class="synComment">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  * </span><span class="synTodo">TODO</span><span class="synComment">: Distribute work.</span><br /><span class="synComment">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  */</span><br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synSpecial">}</span><br />&nbsp; &nbsp; <span class="synSpecial">}</span><br /><span class="synSpecial">?&gt;</span><br /></code></div><br />
<br />
Most of this should be fairly obvious.  We have an object which represents the leader of a pool of workers.  When the process first starts up, it spawns all of its workers.  An interesting piece of code here is the concept of <i>"reaping"</i>, which is the act of cleaning up a process which you own, after it has exited.  When a child process has exited, a signal is sent to the parent process by the operating system: <b>SIGCHLD</b>. We look for this signal, and when it occurs, we clean up the child.  This is done using the process control function <b>pcntl_wait()</b> (<a href="http://php.net/pcntl_wait">http://php.net/pcntl_wait</a>). We're not expecting a specific child to exit, and we don't want to block if no process has exited.  This function will clean up <em>all</em> dead child processes.  If you fail to clean up child processes, you will be left with defunct processes (also called zombie processes). <br />
<br />
<h4>The Worker Process</h4><br />
The following code is for the worker process.  It's more or less empty, but it prepares us for the next steps of this system.<br />
<br />
<b>ForkedWorkerProcess</b><br />
<div class="codeblock"><code><span class="synSpecial">&lt;?php</span><br />&nbsp; &nbsp; <span class="synPreProc">require_once</span> '<span class="synConstant">ForkedProcess.php</span>';<br /><br />&nbsp; &nbsp; <span class="synComment">/**</span><br /><span class="synComment">&nbsp; &nbsp;  * Class representing a single worker process</span><br /><span class="synComment">&nbsp; &nbsp;  */</span><br />&nbsp; &nbsp; <span class="synType">class</span> ForkedWorkerProcess <span class="synType">extends</span> ForkedProcess<br />&nbsp; &nbsp; <span class="synSpecial">{</span><br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synComment">/**</span><br /><span class="synComment">&nbsp; &nbsp; &nbsp; &nbsp;  * Called when the process starts</span><br /><span class="synComment">&nbsp; &nbsp; &nbsp; &nbsp;  */</span><br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synType">public</span> <span class="synPreProc">function</span> onStartup<span class="synSpecial">()</span><br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synSpecial">{</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">$</span><span class="synIdentifier">this</span><span class="synType">-&gt;</span>debug<span class="synSpecial">(</span>&quot;<span class="synConstant">Alive</span>&quot;<span class="synSpecial">)</span>;<br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synSpecial">}</span><br /><br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synComment">/**</span><br /><span class="synComment">&nbsp; &nbsp; &nbsp; &nbsp;  * Called when the process is exiting.</span><br /><span class="synComment">&nbsp; &nbsp; &nbsp; &nbsp;  */</span><br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synType">public</span> <span class="synPreProc">function</span> onExit<span class="synSpecial">()</span><br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synSpecial">{</span><br /><br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synSpecial">}</span><br /><br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synComment">/**</span><br /><span class="synComment">&nbsp; &nbsp; &nbsp; &nbsp;  * Called each cycle</span><br /><span class="synComment">&nbsp; &nbsp; &nbsp; &nbsp;  */</span><br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synType">public</span> <span class="synPreProc">function</span> tick<span class="synSpecial">()</span><br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synSpecial">{</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synComment">/**</span><br /><span class="synComment">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  * </span><span class="synTodo">TODO</span><span class="synComment">: Check for work</span><br /><span class="synComment">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  */</span><br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synSpecial">}</span><br />&nbsp; &nbsp; <span class="synSpecial">}</span><br /><span class="synSpecial">?&gt;</span><br /></code></div><br />
<br />
Pretty self-explanatory.  You notice I left behind a couple "TODO" points in the code.  Those represent the place where we're going to implement the interprocess communication (IPC) functions.  For now, we simply have a parent and a bunch of workers.  We do not have a way to tell our workers to do things.  I will cover this in the next section.<br />
<br />
<h4>Checkpoint: Testing Our Classes</h4><br />
<br />
We have 3 classes above.  Let's try a little test.  Create a new php file.  <br />
<br />
<b>example3.php</b><br />
<div class="codeblock"><code><span class="synSpecial">&lt;?php</span><br />&nbsp; &nbsp; <span class="synPreProc">require_once</span> '<span class="synConstant">ForkedParentProcess.php</span>';<br /><br />&nbsp; &nbsp; <span class="synStatement">$</span><span class="synIdentifier">parent</span> <span class="synStatement">=</span> <span class="synPreProc">new</span> ForkedParentProcess<span class="synSpecial">(</span><span class="synConstant">3</span><span class="synSpecial">)</span>;<br />&nbsp; &nbsp; <span class="synStatement">$</span><span class="synIdentifier">parent</span><span class="synType">-&gt;</span>fork<span class="synSpecial">()</span>;<br /><span class="synSpecial">?&gt;</span><br /></code></div><br />
<br />
If you run this script you should see output similar to this:<br />
<br />
<div class="codeblock"><code>root@localhost ~/process_tutorial # php example3.php <br />20634\ForkedParentProcess&gt; Alive<br />20635\ForkedWorkerProcess&gt; Alive<br />20636\ForkedWorkerProcess&gt; Alive<br />20637\ForkedWorkerProcess&gt; Alive<br /></code></div><br />
<br />
In short, you have spawned a parent process (20634), with 3 child processes (20635 through 20637).  Your process IDs will naturally be different, but the idea is the same.  If you use the <b>ps</b> command, you can view your PHP processes. See below:<br />
<br />
<div class="codeblock"><code>root@localhost ~/process_tutorial # ps -ef | grep php<br />root&nbsp; &nbsp;  20634&nbsp; &nbsp;  1&nbsp; 0 10:31 ?&nbsp; &nbsp; &nbsp; &nbsp; 00:00:00 php example3.php<br />root&nbsp; &nbsp;  20635 20634&nbsp; 0 10:31 ?&nbsp; &nbsp; &nbsp; &nbsp; 00:00:00 php example3.php<br />root&nbsp; &nbsp;  20636 20634&nbsp; 0 10:31 ?&nbsp; &nbsp; &nbsp; &nbsp; 00:00:00 php example3.php<br />root&nbsp; &nbsp;  20637 20634&nbsp; 0 10:31 ?&nbsp; &nbsp; &nbsp; &nbsp; 00:00:00 php example3.php<br /></code></div><br />
<br />
If you issue a kill to the parent process, it should exit and take its children with it:<br />
<br />
<div class="codeblock"><code>root@localhost ~/process_tutorial # ps -ef | grep php<br />root&nbsp; &nbsp;  20634&nbsp; &nbsp;  1&nbsp; 0 10:31 ?&nbsp; &nbsp; &nbsp; &nbsp; 00:00:00 php example3.php<br />root&nbsp; &nbsp;  20635 20634&nbsp; 0 10:31 ?&nbsp; &nbsp; &nbsp; &nbsp; 00:00:00 php example3.php<br />root&nbsp; &nbsp;  20636 20634&nbsp; 0 10:31 ?&nbsp; &nbsp; &nbsp; &nbsp; 00:00:00 php example3.php<br />root&nbsp; &nbsp;  20637 20634&nbsp; 0 10:31 ?&nbsp; &nbsp; &nbsp; &nbsp; 00:00:00 php example3.php<br />root&nbsp; &nbsp;  20649 13958&nbsp; 0 10:35 pts/0&nbsp; &nbsp; 00:00:00 grep --color php<br />root@localhost ~/process_tutorial # kill 20634<br />root@localhost ~/process_tutorial # ps -ef | grep php<br />root@localhost ~/process_tutorial # <br /></code></div><br />
<br />
<h4>Conclusion</h4><br />
In summation, this article has covered a variety of features.  We learned how to manage multiple children, handle signals and properly clean up after our child processes.  We have laid the framework for a basic workload distribution system.  This is a very useful starting point, but it is missing a key element: The ability to communicate.  Once the child processes have spawned, they become autonomous, taking direction from no one.  In the next part of this tutorial, I will continue developing these classes (and adding a couple new classes) to provide this functionality.  I will introduce the concept of <b>message queues</b>.<br />
]]></content:encoded>
			<wfw:commentRss>http://dev.sellingsource.com/2007/08/10/multi-process-persistent-applications-part-2-multiple-children/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Multi-Process Persistent Applications: Part 1 - Forking</title>
		<link>http://dev.sellingsource.com/2007/07/07/multi-process-persistent-applications-part-1-forking/</link>
		<comments>http://dev.sellingsource.com/2007/07/07/multi-process-persistent-applications-part-1-forking/#comments</comments>
		<pubDate>Sat, 07 Jul 2007 19:53:25 +0000</pubDate>
		<dc:creator>johnh</dc:creator>
		
		<category><![CDATA[Linux]]></category>

		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://dev.sellingsource.com/?p=9</guid>
		<description><![CDATA[Introduction
Recently I was confronted with a problem.  We needed to develop an application which could handle large amounts of data, fire off thousands of requests to other servers via http every few minutes, and not let any one thing slow this whole process down. That last part is important.  The data being funneled [...]]]></description>
			<content:encoded><![CDATA[<h4>Introduction</h4><br />
Recently I was confronted with a problem.  We needed to develop an application which could handle large amounts of data, fire off thousands of requests to other servers via http every few minutes, and not let any one thing slow this whole process down. That last part is important.  The data being funneled is coming from multiple customers, and heading out to multiple destinations.  Moreover, there's an intermediate step that requires the data to be pre-packaged.  That step required communication with a large set of database of customers.  So, you can see a few things from this.<br />
<br />
Our application takes multiple inputs, processes the data against multiple databases and then sends that data to multiple outputs.  As you can see, this   creates a huge number of potential bottlenecks.  I don't want customer A's data slowing down customer B's data, and likewise I don't want the performance of Output A getting in the way of Output B's performance.  How do we handle this?  There's a number of ways to do this.  The solution I went with was one of forking and shared memory, and everything that comes with that (such as System V IPC message queues and Semaphores).<br />
<h4>Some Questions Answered</h4><br />
Where do you start?  The first step is to install the necessary PHP extensions, and then get a basic understanding of forking.<br />
<br />
What happens when you fork? Generally, forking is a sort of "process copying".  This is dissimilar from how you'd probably handle this Windows, where creating a separate thread is the way to do it.  There are threading libraries for linux, but none of which are well implemented and supported in PHP.<br />
<br />
Does it work under Apache?  Because forking creates a copy of the process this will not work unless you are running from the command line in a CLI version of PHP.<br />
<br />
Is forking expensive? Yes, forking is an expensive process.  The best way to handle forking is by forking early, and keeping processes running, rather than creating and terminating processes frequently.  If you fork very infrequently, however, it may be more economical to start them and stop them. You will likely have to tune this to your specific application.  There are ups and downs to both.  Forking more means using more CPU, keeping processes around means more RAM.  The decision is yours.<br />
<h4>Enabling the Right Extensions</h4><br />
There are a few extensions that will be useful in this adventure. You need not install all of them immediately, but it's worth getting them all out of the way ahead of time.  The only extension you need to fork is <strong>pcntl</strong> (<a href="http://php.net/pcntl" target="_blank">http://php.net/pcntl</a>), the process control extension.  I will frequently also use functions that exist in the <strong>posix</strong> (<a href="http://php.net/posix">http://php.net/posix</a>), so install that as well. Later on in this tutorial I'll be covering shared memory, message queues and semaphores, which are all covered by the <strong>sysvipc</strong> (<a href="http://www.php.net/manual/en/ref.sem.php" target="_blank">http://www.php.net/manual/en/ref.sem.php</a>) extension.<br />
<h4>Step 1: A Simple Forking Application</h4><br />
Below is an example a very simple forking application. The program starts, forks, and both processes report some information about themselves before exiting.<br />
<br />
<b>example1.php</b><br />
<div class="codeblock"><code><span class="synSpecial">&lt;?php</span><br />&nbsp; &nbsp; <span class="synStatement">$</span><span class="synIdentifier">PID</span> <span class="synStatement">=</span> <span class="synIdentifier">pcntl_fork</span><span class="synSpecial">()</span>;<br /><br />&nbsp; &nbsp; <span class="synStatement">if</span> <span class="synSpecial">(</span><span class="synStatement">$</span><span class="synIdentifier">PID</span> <span class="synStatement">==</span> <span class="synConstant">-1</span><span class="synSpecial">)</span><br />&nbsp; &nbsp; <span class="synSpecial">{</span><br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synComment">// We were unable to fork</span><br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">die</span><span class="synSpecial">(</span>&quot;<span class="synConstant">Error forking.</span>&quot;<span class="synSpecial">)</span>;<br />&nbsp; &nbsp; <span class="synSpecial">}</span><br />&nbsp; &nbsp; <span class="synStatement">else</span> <span class="synStatement">if</span> <span class="synSpecial">(</span><span class="synStatement">$</span><span class="synIdentifier">PID</span> <span class="synStatement">&gt;</span> <span class="synConstant">0</span><span class="synSpecial">)</span><br />&nbsp; &nbsp; <span class="synSpecial">{</span><br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synPreProc">echo</span> &quot;<span class="synConstant">I am the parent process, and my ID is: </span>&quot; <span class="synStatement">.</span> <span class="synIdentifier">posix_getpid</span><span class="synSpecial">()</span> <span class="synStatement">.</span> &quot;<span class="synConstant">. My child ID is: </span><span class="synStatement">$</span><span class="synIdentifier">PID</span><span class="synSpecial">\n</span>&quot;;<br />&nbsp; &nbsp; <span class="synSpecial">}</span><br />&nbsp; &nbsp; <span class="synStatement">else</span><br />&nbsp; &nbsp; <span class="synSpecial">{</span><br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synPreProc">echo</span> &quot;<span class="synConstant">I am the child process, and my ID is: </span>&quot; <span class="synStatement">.</span> <span class="synIdentifier">posix_getpid</span><span class="synSpecial">()</span> <span class="synStatement">.</span> &quot;<span class="synConstant">. My parent ID is: </span>&quot; <span class="synStatement">.</span> <span class="synIdentifier">posix_getppid</span><span class="synSpecial">()</span> <span class="synStatement">.</span> &quot;<span class="synSpecial">\n</span>&quot;;<br />&nbsp; &nbsp; <span class="synSpecial">}</span><br /><span class="synSpecial">?&gt;</span><br /></code></div><br />
Put this code in a simple file, let's call it example1.php. You should see output similar to this when executing it:<br />
<div class="codeblock"><code>root@localhost ~/process_tutorial # php example1.php<br />I am the child process, and my ID is: 1487. My parent ID is: 1486<br />I am the parent process, and my ID is: 1486. My child ID is: 1487<br /></code></div><br />
We used a few important functions here.<strong> pcntl_fork()</strong> is the function used to fork. What happens here is the process is split, and in the parent process, shown here as process id #1486, the call to <strong>pcntl_fork()</strong> returns the process ID of the child process.  If the return value is -1, something has gone haywire.  This is likely a system configuration issue, and not something I can really assist with.  In the child process, shown here as process id #1487, the call to <strong>pcntl_fork()</strong> returns 0.  The return value of this function is ultimately how you direct code flow in the two processes. The other two important functions we used are <strong>posix_getpid()</strong> and <strong>posix_getppid()</strong>, which return the ID of the current process and the ID of the parent to this process, respectively.<br />
<h4>Step 2: Starting a Background Process and Exiting</h4><br />
One of the common things people use forking for is to make an application that automatically backgrounds itself.  This is fairly common practice and you see it in a lot of applications, such as VPNC. This allows an application started from the command line to persist even after the controlling terminal has exited.  A few things have to happen.  Firstly, the parent can just exit. However, the child process will still be attached to the terminal from which the parent was executed.<br />
<br />
In order to detach, we make use of a POSIX linux command called <strong>setsid()</strong>. In PHP, we are given access to this function through the POSIX extension, and the name of the function is <strong>posix_setsid()</strong>.  What this function does, in general terms, is turns the process from which it is being called into an independent process with its own process group.  You're probably asking why we need to fork in the first place.  Why can't we just detach the process we started from the terminal?  The answer to that question lies in the man pages.<br />
<blockquote><em><br />
The setsid() function shall fail if:</em><br />
<br />
<em>    [EPERM]<br />
The calling process is already a process group leader, or the process group ID of a process other than the calling process matches the process ID of the calling process.</em></blockquote><br />
That is, when we start php using the command line, we are effectively creating a new process, which is the leader of its process group, and thus we must make another process using <strong>pcntl_fork()</strong> if we wish to detach.<br />
<br />
In the example below, we create a new process, detach it from the controlling terminal, and exit the parent process. The child process will exit after 30 seconds.  You could also issue a SIGTERM to the process with the <strong>kill</strong> command in linux.<br />
<br />
<b>example2.php</b><br />
<div class="codeblock"><code><span class="synSpecial">&lt;?php</span><br />&nbsp; &nbsp; <span class="synStatement">$</span><span class="synIdentifier">PID</span> <span class="synStatement">=</span> <span class="synIdentifier">pcntl_fork</span><span class="synSpecial">()</span>;<br /><br />&nbsp; &nbsp; <span class="synStatement">if</span> <span class="synSpecial">(</span><span class="synStatement">$</span><span class="synIdentifier">PID</span> <span class="synStatement">==</span> <span class="synConstant">-1</span><span class="synSpecial">)</span><br />&nbsp; &nbsp; <span class="synSpecial">{</span><br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synComment">// We were unable to fork</span><br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">die</span><span class="synSpecial">(</span>&quot;<span class="synConstant">Error forking.</span>&quot;<span class="synSpecial">)</span>;<br />&nbsp; &nbsp; <span class="synSpecial">}</span><br />&nbsp; &nbsp; <span class="synStatement">else</span> <span class="synStatement">if</span> <span class="synSpecial">(</span><span class="synStatement">$</span><span class="synIdentifier">PID</span> <span class="synStatement">&gt;</span> <span class="synConstant">0</span><span class="synSpecial">)</span><br />&nbsp; &nbsp; <span class="synSpecial">{</span><br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synComment">// Exit the parent process</span><br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">die</span><span class="synSpecial">(</span>&quot;<span class="synConstant">Parent exiting. Process started in background (pid: </span><span class="synStatement">$</span><span class="synIdentifier">PID</span><span class="synConstant">)</span>&quot;<span class="synSpecial">)</span>;<br />&nbsp; &nbsp; <span class="synSpecial">}</span><br />&nbsp; &nbsp; <span class="synPreProc">echo</span> &quot;<span class="synConstant">Detaching from terminal.</span><span class="synSpecial">\n</span>&quot;;<br /><br />&nbsp; &nbsp; <span class="synComment">// Create a new session (Detach from terminal)</span><br />&nbsp; &nbsp; <span class="synStatement">if</span> <span class="synSpecial">(</span><span class="synIdentifier">posix_setsid</span><span class="synSpecial">()</span> <span class="synStatement">==</span> <span class="synConstant">-1</span><span class="synSpecial">)</span><br />&nbsp; &nbsp; <span class="synSpecial">{</span><br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">die</span><span class="synSpecial">(</span>&quot;<span class="synConstant">Unable to detach from controlling terminal!</span>&quot;<span class="synSpecial">)</span>;<br />&nbsp; &nbsp; <span class="synSpecial">}</span><br /><br />&nbsp; &nbsp; <span class="synComment">// Wait 30 seconds before exiting so we view this process running in the background, for testing purposes.</span><br />&nbsp; &nbsp; <span class="synStatement">$</span><span class="synIdentifier">timer</span> <span class="synStatement">=</span> <span class="synConstant">30</span>;<br />&nbsp; &nbsp; <span class="synStatement">while</span> <span class="synSpecial">(</span><span class="synStatement">$</span><span class="synIdentifier">timer</span><span class="synStatement">--</span><span class="synSpecial">)</span> <span class="synIdentifier">sleep</span><span class="synSpecial">(</span><span class="synConstant">1</span><span class="synSpecial">)</span>;<br /><span class="synSpecial">?&gt;</span><br /></code></div><br />
<br />
Executing this code should present an output similar to this:<br />
<div class="codeblock"><code>root@localhost ~/process_tutorial # php example2.php<br />Detaching from terminal.<br />Parent exiting. Process started in background (pid: 2131)<br /><br />root@localhost ~/process_tutorial # ps -ef | grep php<br />root&nbsp; &nbsp; &nbsp; 2131&nbsp; &nbsp;  1&nbsp; 0 12:43 ?&nbsp; &nbsp; &nbsp; &nbsp; 00:00:00 php example2.php<br /></code></div><br />
And about 30 seconds later, the process is gone:<br />
<div class="codeblock"><code> root@localhost ~/process_tutorial # ps -ef | grep php<br />root@localhost ~/process_tutorial #<br /></code></div><br />
Your background process has started, spent 30 seconds doing some things, and exited.  That is the basic way to fork and background.<br />
<h4>Conclusion</h4><br />
In the next part of this series I'll talk about how to manage multiple child processes. In the third, I will cover how to communicate between processes using message queues.  The fourth part will cover shared memory and semaphores.]]></content:encoded>
			<wfw:commentRss>http://dev.sellingsource.com/2007/07/07/multi-process-persistent-applications-part-1-forking/feed/</wfw:commentRss>
		</item>
		<item>
		<title>WAP: Part 6 - Microbrowser content in WML / XHTML MP</title>
		<link>http://dev.sellingsource.com/2007/03/24/microbrowser-content-with-wml-and-xhtml-mp/</link>
		<comments>http://dev.sellingsource.com/2007/03/24/microbrowser-content-with-wml-and-xhtml-mp/#comments</comments>
		<pubDate>Sat, 24 Mar 2007 18:04:23 +0000</pubDate>
		<dc:creator>justinf</dc:creator>
		
		<category><![CDATA[PHP]]></category>

		<category><![CDATA[WAP]]></category>

		<guid isPermaLink="false">http://dev.sellingsource.com/?p=15</guid>
		<description><![CDATA[WML
WML is probably the lowest common denominator of microbrowser content formats.  If you can assume you're not going to support older phones that only can display WML, you might decide to only display your content in XHTML MP (Mobile Profile). 

WML is a different paradigm of web design, which encompasses multiple pages (cards) contained [...]]]></description>
			<content:encoded><![CDATA[<h4>WML</h4><br />
WML is probably the lowest common denominator of microbrowser content formats.  If you can assume you're not going to support older phones that only can display WML, you might decide to only display your content in XHTML MP (Mobile Profile). <br />
<br />
WML is a different paradigm of web design, which encompasses multiple pages (cards) contained in a single document (deck).  A brief and easy introduction into WAP and WML can be found at <a href="http://www.w3schools.com/wap/default.asp">w3schools</a>.  Read all of it.<br />
<br />
Once you've read all of that, there's more in-depth WML information and tutorials at <a href="http://www.developershome.com/wap/wml/">http://www.developershome.com/wap/wml/</a>. Specifically you'll at least want to check out <a href="http://www.developershome.com/wap/wml/wmlSendingData.asp">how to submit form data in WML</a>.<br />
<h4>WML in Firefox</h4><br />
To test WML in Firefox, you'll want two plugins: <a href="https://addons.mozilla.org/en-US/firefox/addon/62">WML Browser</a> and <a href="https://addons.mozilla.org/en-US/firefox/addon/967">Modify Headers</a>.  Modify Headers is used to append 'text/vnd.wap.wml' to the Accept header -- indicating that Firefox somehow now knows how to render WML.  You can also use Modify Headers to change the User-Agent header, which is not strictly needed, but if your WAP site is utilizing the WURFL to determine device capabilities, then it may be useful to 'virtually' test different devices (<a href="http://dev.sellingsource.com/?p=14">see my previous WURFL article</a>).  WML has an extremely strict syntax, so it is best to test pages in Firefox using the WML Browser as it will more verbose in reporting errors, where as your phone will probably just display nothing.<br />
<h4>XHTML MP</h4><br />
XHTML MP is really just strict XHTML with some limitations.  You must always close your tags, they must be in lower case, attributes must be<br />
enclosed in quotes, etc. etc.  Go through the documentation provided <a href="http://www.developershome.com/wap/xhtmlmp/">here</a> for details.<br />
<br />
To test XHTML MP in a 'big' browser you don't have to do anything in particular since XHTML MP is really a subset of XHTML.  If you're using something like the WURFL to redirect to a 'full' site based on User-Agent, you might add something in your code to force to XHTML MP mode.<br />
<h4>Dynamically changing format with XSLT</h4><br />
You could probably dynamically change from WML to XHTML MP by using XSLT but I've found it simpler to maintain seperate files.  In a<br />
multi-page site this could quickly get out of hand.  So for a primer <a href="http://www.xml.com/pub/a/2004/04/14/mobile.html">here is an article</a> that uses PHP, WURFL &#038; XSLT to translate pages between XHTML MP and WML.<br />
<br />
<h4>Articles In This Series:</h4><br />
<a href="http://dev.sellingsource.com/?p=4">WAP: Part 1 - MultiTech USB GPRS Modem in Linux</a><br />
<a href="http://dev.sellingsource.com/?p=8">WAP: Part 2 - Send SMS from Kannel</a><br />
<a href="http://dev.sellingsource.com/?p=10">WAP: Part 3 - WAP Push with Kannel &#038; PHP</a><br />
<a href="http://dev.sellingsource.com/?p=13">WAP: Part 4 - Send SMS from PHP</a><br />
<a href="http://dev.sellingsource.com/?p=14">WAP: Part 5 - Customizing content with WURFL</a><br />
WAP: Part 6 - Microbrowser content in WML / XHTML MP<br />
]]></content:encoded>
			<wfw:commentRss>http://dev.sellingsource.com/2007/03/24/microbrowser-content-with-wml-and-xhtml-mp/feed/</wfw:commentRss>
		</item>
		<item>
		<title>WAP: Part 5 - Customizing content with WURFL</title>
		<link>http://dev.sellingsource.com/2007/02/05/customizing-wap-content-with-wurfl/</link>
		<comments>http://dev.sellingsource.com/2007/02/05/customizing-wap-content-with-wurfl/#comments</comments>
		<pubDate>Mon, 05 Feb 2007 16:35:22 +0000</pubDate>
		<dc:creator>justinf</dc:creator>
		
		<category><![CDATA[Linux]]></category>

		<category><![CDATA[PHP]]></category>

		<category><![CDATA[WAP]]></category>

		<guid isPermaLink="false">http://dev.sellingsource.com/?p=14</guid>
		<description><![CDATA[We've covered (in-depth) the delivery side of getting URLs to phones using Kannel.  Now it's time to cover the content you'd like to
display on the phone.  One tool that I've found to be the best single database of what phones can do is the WURFL.  WURFL stands for Wireless Universal Resource File, [...]]]></description>
			<content:encoded><![CDATA[We've covered (in-depth) the delivery side of getting URLs to phones using Kannel.  Now it's time to cover the content you'd like to<br />
display on the phone.  One tool that I've found to be the best single database of what phones can do is the <a href="http://wurfl.sourceforge.net/">WURFL</a>.  WURFL stands for Wireless Universal Resource File, and it is simply and XML 'database' of phones, their families, and their capabilities.  You can get the XML file <a href="http://wurfl.sourceforge.net/wurfl.zip">here</a>. There's also a <a href="http://wurfl.sourceforge.net/php/">WURLF PHP toolkit</a> for incorporating the WURFL into your project, download it <a href="http://downloads.sourceforge.net/wurfl/wurfl_php_tools_21.zip">here</a>.<br />
<h4>Installing and Configuring the WURFL</h4><br />
To start, unzip the wurfl toolkit and then download the wurfl file and unzip it as well.  Then set up the WURFL config file and update the<br />
WURFL cache.<br />
<br />
<div class="codeblock"><code>/ $ cd<br />~ $ mkdir -p ~/src/wurfl<br />~ $ cd ~/src/wurfl<br />~/src/wurfl $ wget http://downloads.sourceforge.net/wurfl/wurfl_php_tools_21.zip<br />~/src/wurfl $ unzip wurfl_php_tools_21.zip<br />~/src/wurfl $ wget http://wurfl.sourceforge.net/wurfl.zip<br />~/src/wurfl $ unzip wurfl.zip<br />~/src/wurfl $ vi wurfl_config.php<br /></code></div><br />
<br />
<strong>wurfl_config.php</strong><br />
<div class="codeblock"><code><span class="synSpecial">&lt;?php</span><br /><span class="synStatement">...</span><br /><span class="synIdentifier">define</span><span class="synSpecial">(</span>&quot;<span class="synConstant">DATADIR</span>&quot;, <span class="synIdentifier">dirname</span><span class="synSpecial">(</span><span class="synConstant">__FILE__</span><span class="synSpecial">))</span>;<br /><span class="synIdentifier">define</span><span class="synSpecial">(</span>&quot;<span class="synConstant">WURFL_PARSER_FILE</span>&quot;, DATADIR <span class="synStatement">.</span> '<span class="synConstant">wurfl_parser.php</span>'<span class="synSpecial">)</span>;<br /><span class="synIdentifier">define</span><span class="synSpecial">(</span>&quot;<span class="synConstant">WURFL_CLASS_FILE</span>&quot;, DATADIR <span class="synStatement">.</span> '<span class="synConstant">wurfl_class.php</span>'<span class="synSpecial">)</span>;<br /><span class="synStatement">...</span><br /><span class="synSpecial">?&gt;</span><br /></code></div><h4>Updating the cache</h4><br />
To build the cache, run update_cache.php.  <br />
<div class="codeblock"><code>~/src/wurfl $ php update_cache.php<br /></code></div><br />
<br />
If you're planning on running update_cache.php from a web browser after periodically updating wurfl.xml, you may want to change<br />
permissions so they're apache friendly:<br />
<div class="codeblock"><code>/ # cd &amp;lt;wurfl dir&amp;gt;<br />wurfl # chown -R :apache . <br />wurfl # chmod 664 cache.php<br />wurfl # chmod 2775 . <br />wurfl # sudo -u apache php ./update_cache.php<br /></code></div><br />
WURFL and the toolkit simply work by analizing the User-Agent header to determine what type of device is connecting and what capabilities it has.  The cache groups phone families logically so it only loads a portion of the WURFL database... only that which is needed. It also stores device info from previously connected devices, to negate the need of an additional lookup in the future.<br />
<h4>Using the WURFL</h4><br />
Here is a simple example of using the WURFL to determine if the "device" is a WAP browser (a phone) or not (a full-fledged browser<br />
such as IE or Firefox).<br />
<br />
<div class="codeblock"><code><span class="synSpecial">&lt;?php</span><br /><br /><span class="synPreProc">require_once</span> '<span class="synConstant">wurfl_config.php</span>';<br /><span class="synPreProc">require_once</span> WURFL_CLASS_FILE;<br /><br /><span class="synComment">//new up the wurfl class</span><br /><span class="synStatement">$</span><span class="synIdentifier">device</span> <span class="synStatement">=</span> <span class="synPreProc">new</span> wurfl_class<span class="synSpecial">()</span>;<br /><br /><span class="synComment">//have it load it's information based on the user agent</span><br /><span class="synStatement">$</span><span class="synIdentifier">device</span><span class="synType">-&gt;</span>GetDeviceCapabilitiesFromAgent<span class="synSpecial">(</span><span class="synStatement">$</span><span class="synIdentifier">_SERVER</span><span class="synSpecial">[</span>'<span class="synConstant">HTTP_USER_AGENT</span>'<span class="synSpecial">])</span>;<br /><br /><span class="synStatement">if</span><span class="synSpecial">(</span><span class="synStatement">!$</span><span class="synIdentifier">device</span><span class="synType">-&gt;</span>browser_is_wap<span class="synSpecial">)</span><br /><span class="synSpecial">{</span><br />&nbsp; &nbsp; <span class="synIdentifier">header</span><span class="synSpecial">(</span>'<span class="synConstant">Location: http://www.yahoo.com</span>'<span class="synSpecial">)</span>;<br />&nbsp; &nbsp; <span class="synStatement">exit</span>;<br /><span class="synSpecial">}</span><br /><br /><span class="synSpecial">?&gt;</span><br /></code></div><br />
Note that many "smart" phones will not return TRUE for 'browser_is_wap'. You may or may not want to send them to a full-sized site due to screen size, download speeds, etc.  There is a boatload of additional information that can be gleamed from the WURFL PHP toolkit from inspecting the <strong>$device->capabilities</strong> array.  <br />
<br />
For determining content format, as I see it you have 3 basic choices:<br />
<ol><li>Full-fledged pages displayed by smart phones or "big" browsers (from above example)</li><br />
<li>XHTML Mobile Profile (MP), determined by <strong>$device->capabilities['markup']['preferred_markup'] = 'html_wi_oma_xhtmlmp_1_0'</strong></li><br />
<li>WML, determined by <strong>$device->capabilities['markup']['preferred_markup'] = 'wml_1_1'</strong></li></ol><br />
There are other capabilities such as 'flash_lite' which I will not get into as I'm focusing on the lowest common denominator of phone, hoping to deliver the most content quickly, easily, and reliably.<br />
<br />
Another thing to consider that is not neccessarily dependent on the format is the screen size.  I used <strong>$device->capabilities['display']['max_image_width']</strong> and <strong>'max_image_height'</strong> to scale images to the phone's screen.  You can also use the <strong>$device->capabilities['image_format']</strong> array to determine what type (jpg, gif, wbmp, etc.) of images the phone can display.<br />
<br />
In my next article I'll talk about the ups and downs of <a href="http://dev.sellingsource.com/?p=15">microbrowser content in WML / XHTML MP</a>.<br />
<br />
<h4>Articles In This Series:</h4><br />
<a href="http://dev.sellingsource.com/?p=4">WAP: Part 1 - MultiTech USB GPRS Modem in Linux</a><br />
<a href="http://dev.sellingsource.com/?p=8">WAP: Part 2 - Send SMS from Kannel</a><br />
<a href="http://dev.sellingsource.com/?p=10">WAP: Part 3 - WAP Push with Kannel &#038; PHP</a><br />
<a href="http://dev.sellingsource.com/?p=13">WAP: Part 4 - Send SMS from PHP</a><br />
WAP: Part 5 - Customizing content with WURFL<br />
<a href="http://dev.sellingsource.com/?p=15">WAP: Part 6 - Microbrowser content in WML / XHTML MP</a>]]></content:encoded>
			<wfw:commentRss>http://dev.sellingsource.com/2007/02/05/customizing-wap-content-with-wurfl/feed/</wfw:commentRss>
		</item>
		<item>
		<title>WAP: Part 4 - Send SMS from PHP</title>
		<link>http://dev.sellingsource.com/2007/01/05/sending-sms-messages-with-kannel-php/</link>
		<comments>http://dev.sellingsource.com/2007/01/05/sending-sms-messages-with-kannel-php/#comments</comments>
		<pubDate>Fri, 05 Jan 2007 17:46:21 +0000</pubDate>
		<dc:creator>justinf</dc:creator>
		
		<category><![CDATA[Kannel]]></category>

		<category><![CDATA[PHP]]></category>

		<category><![CDATA[WAP]]></category>

		<guid isPermaLink="false">http://dev.sellingsource.com/?p=13</guid>
		<description><![CDATA[Finally, let's send SMS messages to mobile phones with links in them. This is the most simple and most reliable way to get a URL to a phone. Most modern phones are smart enough to be able to pick out a URL and give you an option to visit it.  Granted, the "GOTO" option [...]]]></description>
			<content:encoded><![CDATA[Finally, let's send SMS messages to mobile phones with links in them. This is the most simple and most reliable way to get a URL to a phone. Most modern phones are smart enough to be able to pick out a URL and give you an option to visit it.  Granted, the "GOTO" option may be buried in a menu somewhere, but for now it's the best we can do to reach the broadest audience.<br />
<br />
If you haven't set up Kannel yet, you'll want to do that.  You can refer to my previous article <a href="http://dev.sellingsource.com/?p=8">WAP: Part 2 - Send SMS from Kannel</a>.  It includes information on a basic setup and also how to send a test SMS message on the command line so you know it works before we get into doing with PHP.<br />
<br />
This process is also the easiest to construct using PHP.  Since Kannel does all of it's calls using the HTTP protocol, we'll simply turn on allow_url_fopen in our PHP ini and then we can use file() to make the Kannel requests.  You could also use curl or a socket connection if you'd like.<br />
<br />
Since this example so simple, I'll let you download the example code to look at the actual call, but essentially we're doing:<br />
<br />
<div class="codeblock"><code><span class="synSpecial">&lt;?php</span><br /><br /><span class="synStatement">$</span><span class="synIdentifier">result</span> <span class="synStatement">=</span> <span class="synIdentifier">file</span><span class="synSpecial">(</span><br />&nbsp; &nbsp; '<span class="synConstant">http://localhost:13013/cgi-bin/sendsms</span>' <span class="synStatement">.</span> <br />&nbsp; &nbsp; '<span class="synConstant">?user=sms_user</span>' <span class="synStatement">.</span> <br />&nbsp; &nbsp; '<span class="synConstant">&amp;pass=sms_pass</span>' <span class="synStatement">.</span> <br />&nbsp; &nbsp; '<span class="synConstant">&amp;to=7025551212</span>' <span class="synStatement">.</span><br />&nbsp; &nbsp; '<span class="synConstant">&amp;text=Go+to+Yahoo%21+on+your+phone+by+visiting+http%3A%2F%2Fwap.yahoo.com</span>'<br /><span class="synSpecial">)</span>;<br /><br /><span class="synSpecial">?&gt;</span><br /></code></div><br />
If you're using the example index to send, don't forget to change the message to include the URL in the message itself.  Unlike sending a<br />
WAP Push message, there is no URL directly associated with the message.<br />
<br />
<a href="http://dev.sellingsource.com/wp-content/uploads/2007/09/wapsendertar.bz2">Download the example</a><br />
<br />
<h4>Articles In This Series:</h4><br />
<a href="http://dev.sellingsource.com/?p=4">WAP: Part 1 - MultiTech USB GPRS Modem in Linux</a><br />
<a href="http://dev.sellingsource.com/?p=8">WAP: Part 2 - Send SMS from Kannel</a><br />
<a href="http://dev.sellingsource.com/?p=10">WAP: Part 3 - WAP Push with Kannel &#038; PHP</a><br />
WAP: Part 4 - Send SMS from PHP<br />
<a href="http://dev.sellingsource.com/?p=14">WAP: Part 5 - Customizing content with WURFL</a><br />
<a href="http://dev.sellingsource.com/?p=15">WAP: Part 6 - Microbrowser content in WML / XHTML MP</a><br />
]]></content:encoded>
			<wfw:commentRss>http://dev.sellingsource.com/2007/01/05/sending-sms-messages-with-kannel-php/feed/</wfw:commentRss>
		</item>
		<item>
		<title>WAP: Part 3 - WAP Push with Kannel &#038; PHP</title>
		<link>http://dev.sellingsource.com/2006/12/07/sending-wap-push-messages-with-kannel-php/</link>
		<comments>http://dev.sellingsource.com/2006/12/07/sending-wap-push-messages-with-kannel-php/#comments</comments>
		<pubDate>Thu, 07 Dec 2006 16:14:59 +0000</pubDate>
		<dc:creator>justinf</dc:creator>
		
		<category><![CDATA[Kannel]]></category>

		<category><![CDATA[Linux]]></category>

		<category><![CDATA[PHP]]></category>

		<category><![CDATA[WAP]]></category>

		<guid isPermaLink="false">http://dev.sellingsource.com/?p=10</guid>
		<description><![CDATA[This article will go through setting up Kannel to send "WAP Push" messages to mobile phones.  It assumes you have a working Kannel
installation with a real modem -- see parts 1 &#38; 2 of this series for more information.

Before we continue with this article, let me save you some time.  I have found [...]]]></description>
			<content:encoded><![CDATA[This article will go through setting up Kannel to send "WAP Push" messages to mobile phones.  It assumes you have a working Kannel<br />
installation with a real modem -- see parts <a href="http://dev.sellingsource.com/?p=4">1</a> &amp; <a href="http://dev.sellingsource.com/?p=8">2</a> of this series for more information.<br />
<br />
Before we continue with this article, let me save you some time.  I have found WAP Push messages to be very unreliable.  Specifically I was only able to get a WAP Push message sent to a T-Mobile phone from my GSM modem with a T-Mobile SIM card.  I tried a Cingular SIM card in the modem, but was unable to successfully send a WAP Push message to a Cingular or other network phone.<br />
<br />
I searched for 3rd party companies that will send WAP Push messages, and contacting a few of them.  It seems here in the U.S. this type of service is relatively unreliable and sometimes only the network providers themselves can send WAP Push messages that will get through.  Case in point: I couldn't get a WAP Push message to a Cingular phone, but you can download ringtones from cingular.com, for which the URL is sent to the phone via WAP Push.<br />
<br />
So, if you want to send WAP Push messages from a T-Mobile modem to only T-Mobile phones, read on!  If not, you might save yourself the headache and time and skip the next article of my WAP series: <a href="http://dev.sellingsource.com/?p=13">Send SMS from PHP</a>.<br />
<h4>Sending WAP Push from the command line</h4><br />
To our working configuration file from <a href="http://dev.sellingsource.com/?p=8">WAP: Part 2 - Send SMS from Kannel</a>, we'll add the ppg and wap-push-user groups.  Also add <strong>wapbox</strong> to the startup file and restart Kannel.<br />
<br />
<strong>/etc/kannel/kannel.conf</strong><br />
<div class="codeblock"><code>...<br /><span class="synComment"># PUSH PROXY GATEWAY CONFIG</span><br />group = ppg<br />ppg-url = /wappush<br />ppg-port = 8080<br />service-name = ppg<br />trusted-pi = true <br /><br /><span class="synComment"># WAP USER</span><br />group = wap-push-user<br />wap-push-user = SellingSource<br />ppg-username = sellingsource<br />ppg-password = sellingsource<br /></code></div><br />
<br />
<strong>start_kannel.sh</strong><br />
<div class="codeblock"><code><span class="synComment">#!/bin/sh</span><br /><br /><span class="synStatement">rm</span> /var/log/kannel/*<br />bearerbox <span class="synSpecial">--verbosity</span> <span class="synConstant">4</span> <span class="synSpecial">--logfile</span> /var/log/kannel/bearerbox.log /etc/kannel/kannel.conf &amp;<br /><span class="synStatement">sleep</span> <span class="synConstant">10</span><br />smsbox <span class="synSpecial">--verbosity</span> <span class="synConstant">4</span> <span class="synSpecial">--logfile</span> /var/log/kannel/smsbox.log /etc/kannel/kannel.conf &amp;<br />wapbox <span class="synSpecial">--verbosity</span> <span class="synConstant">4</span> <span class="synSpecial">--logfile</span> /var/log/kannel/wapbox.log /etc/kannel/kannel.conf &amp;<br /></code></div><br />
<br />
I initially tested WAP Push using the included <strong>test_ppg</strong> executable included with the Kannel source.  If you don't want/need to test it from the command line you can skip to the <a href="#php">PHP segment</a>.<br />
<br />
Unfortunately the test programs are not included with the Gentoo/portage installation of Kannel.  So I downloaded the source and<br />
compiled (but did not install) it to get the test programs.  Then I copied the example xml files used by <strong>test_ppg</strong> to my home directory for modification.<br />
<br />
<div class="codeblock"><code>~ # cd ~/src<br />src # wget http://kannel.org/download/1.4.1/gateway-1.4.1.tar.bz2<br />src # tar -jxvf gateway-1.4.1.tar.bz2<br />src # cd gateway-1.4.1<br />gateway-1.4.1 # ./configure &amp;&amp; make<br />gateway-1.4.1 # cp test/si.txt ~/si.xml<br />gateway-1.4.1 # cp test/smstestppg.txt ~/pap.xml<br /></code></div><br />
In si.xml I removed the created and si-expires attributes so there's no delivery timing issues (deliver immediately).  The indication href<br />
is a URL that will be shown as the 'From:' in the message, and is where the message will take them.  The si-id is a unique message<br />
identifier and should be changed everytime the message is sent.  I like to use number@domain and up the number once before sending.<br />
Change the message to something suitable, hopefully describing where the href URL will take them.<br />
<br />
<strong>si.xml</strong><br />
<div class="codeblock"><code><span class="synComment">&lt;?</span><span class="synType">xml version</span>=<span class="synConstant">&quot;1.0&quot;</span><span class="synComment">?&gt;</span><br /><span class="synIdentifier">&lt;!</span><span class="synStatement">DOCTYPE</span> si <span class="synStatement">PUBLIC</span> <span class="synConstant">&quot;-//WAPFORUM//DTD SI 1.0//EN&quot;</span><br /><span class="synConstant">&quot;http://www.wapforum.org/DTD/si.dtd&quot;</span><span class="synIdentifier">&gt;</span><br /><span class="synIdentifier">&lt;si&gt;</span><br />&nbsp; &nbsp; <span class="synIdentifier">&lt;indication </span><span class="synType">href</span>=<span class="synConstant">&quot;http://wap.yahoo.com&quot;</span><br /><span class="synIdentifier">&nbsp; &nbsp; &nbsp; &nbsp; </span><span class="synType">si-id</span>=<span class="synConstant">&quot;01@sellingsource.com&quot;</span><br /><span class="synIdentifier">&nbsp; &nbsp; &nbsp; &nbsp; </span><span class="synType">action</span>=<span class="synConstant">&quot;signal-high&quot;</span><span class="synIdentifier">&gt;</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Visit Yahoo! on your phone<br />&nbsp; &nbsp; <span class="synIdentifier">&lt;/indication&gt;</span><br /><span class="synIdentifier">&lt;/si&gt;</span><br /></code></div><br />
In pap.xml, I changed to the push-id to the same as the si-id, this value should change per message as well.  I changed the WAPPUSH number to my own, this time with country code (leading "+1").  I also changed the "carrier" after the 'PLMN@' to be our domain.<br />
<br />
<strong>pap.xml</strong><br />
<div class="codeblock"><code><span class="synComment">&lt;?</span><span class="synType">xml version</span>=<span class="synConstant">&quot;1.0&quot;</span><span class="synComment">?&gt;</span><br /><span class="synIdentifier">&lt;!</span><span class="synStatement">DOCTYPE</span> pap <span class="synStatement">PUBLIC</span> <span class="synConstant">&quot;-//WAPFORUM//DTD PAP//EN&quot;</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synConstant">&quot;http://www.wapforum.org/DTD/pap_1.0.dtd&quot;</span><span class="synIdentifier">&gt;</span><br /><span class="synIdentifier">&lt;pap&gt;</span><br />&nbsp; <span class="synIdentifier">&lt;push-message </span><span class="synType">push-id</span>=<span class="synConstant">&quot;01@sellingsource.com&quot;</span><br /><span class="synIdentifier">&nbsp; </span><span class="synType">deliver-after-timestamp</span>=<span class="synConstant">&quot;2001-02-28T06:45:00Z&quot;</span><br /><span class="synIdentifier">&nbsp; </span><span class="synType">progress-notes-requested</span>=<span class="synConstant">&quot;false&quot;</span><span class="synIdentifier">&gt;</span><br />&nbsp; &nbsp; <span class="synIdentifier">&lt;address </span><span class="synType">address-value</span>=<span class="synConstant">&quot;WAPPUSH=+17025551212/TYPE=PLMN@sellingsource.com&quot;</span><span class="synIdentifier">&gt;</span><br />&nbsp; &nbsp; <span class="synIdentifier">&lt;/address&gt;</span><br />&nbsp; &nbsp; <span class="synIdentifier">&lt;quality-of-service</span><br /><span class="synIdentifier">&nbsp; &nbsp; </span><span class="synType">priority</span>=<span class="synConstant">&quot;low&quot;</span><br /><span class="synIdentifier">&nbsp; &nbsp; </span><span class="synType">delivery-method</span>=<span class="synConstant">&quot;unconfirmed&quot;</span><br /><span class="synIdentifier">&nbsp; &nbsp; </span><span class="synType">network-required</span>=<span class="synConstant">&quot;true&quot;</span><br /><span class="synIdentifier">&nbsp; &nbsp; </span><span class="synType">network</span>=<span class="synConstant">&quot;gsm&quot;</span><br /><span class="synIdentifier">&nbsp; &nbsp; </span><span class="synType">bearer-required</span>=<span class="synConstant">&quot;true&quot;</span><br /><span class="synIdentifier">&nbsp; &nbsp; </span><span class="synType">bearer</span>=<span class="synConstant">&quot;sms&quot;</span><span class="synIdentifier">&gt;</span><br />&nbsp; &nbsp; <span class="synIdentifier">&lt;/quality-of-service&gt;</span><br />&nbsp; <span class="synIdentifier">&lt;/push-message&gt;</span><br /><span class="synIdentifier">&lt;/pap&gt;</span><br /></code></div><br />
<br />
So let's test this from the command line:<br />
<div class="codeblock"><code>gateway-1.4.1 # ./test/test_ppg &quot;http://localhost:8080/wappush?username=wap_user&amp;password=wap_pass&quot; ~/si.xml ~/pap.xml<br /></code></div><br />
On my T-Mobile Motorola phone, I now have a message under "Browser Msgs."  I can click the "GO TO" button and it will take me to the URL specified in the 'href' attribute of si.xml.<br />
<a name="php" title="php"></a><h4>Sending WAP Push from PHP</h4><br />
Now let's do the same thing using PHP.  But first let me explain how things are going to change.  XML is pretty chatty, so we'll be using a binary format called WBXML.  Since we'll be communicating directly to Kannel via HTTP with a URL, we'll represent the hexadecimal numbers with a prefix of '%' for URL encoding, rather than '0x'.  Along with the Service Indication (SI) document in WBXML, we'll also have to pass a User Data Header (udh) for WAP Push.  For an explanation of the udh and WBXML, please see the reference information links below, I've also documented them as best I know in the code:<br />
<br />
<div class="codeblock"><code><span class="synSpecial">&lt;?php</span><br /><br /><span class="synPreProc">require_once</span> '<span class="synConstant">SMSBase.php</span>'; <br /><br /><span class="synType">class</span> WAPPush <span class="synType">extends</span> SMSBase<br /><span class="synSpecial">{</span><br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synType">public</span> <span class="synPreProc">function</span> <span class="synStatement">__construct</span><span class="synSpecial">(</span>KannelInfo <span class="synStatement">$</span><span class="synIdentifier">kannel_info</span><span class="synSpecial">)</span><br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synSpecial">{</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synType">parent</span><span class="synStatement">::__construct</span><span class="synSpecial">(</span><span class="synStatement">$</span><span class="synIdentifier">kannel_info</span><span class="synSpecial">)</span>;<br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synSpecial">}</span> <br /><br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synType">public</span> <span class="synPreProc">function</span> sendSMSLink<span class="synSpecial">(</span>LinkSMS <span class="synStatement">$</span><span class="synIdentifier">sms</span><span class="synSpecial">)</span><br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synSpecial">{</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">$</span><span class="synIdentifier">fields</span> <span class="synStatement">=</span> <span class="synType">array</span><span class="synSpecial">(</span>'<span class="synConstant">to</span>' <span class="synStatement">=&gt;</span>; <span class="synIdentifier">urlencode</span><span class="synSpecial">(</span><span class="synStatement">$</span><span class="synIdentifier">sms</span><span class="synType">-&gt;</span>getTo<span class="synSpecial">())</span>,<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; '<span class="synConstant">udh</span>' <span class="synStatement">=&gt;</span> '',<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; '<span class="synConstant">text</span>' <span class="synStatement">=&gt;</span> ''<span class="synSpecial">)</span>; <br /><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synComment">//Nokia User Data Header (UDH) for WAP Push</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">$</span><span class="synIdentifier">fields</span><span class="synSpecial">[</span>'<span class="synConstant">udh</span>'<span class="synSpecial">]</span> <span class="synStatement">.=</span> '<span class="synConstant">%06</span>'; <span class="synComment">//length of UDH - 6 bytes</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">$</span><span class="synIdentifier">fields</span><span class="synSpecial">[</span>'<span class="synConstant">udh</span>'<span class="synSpecial">]</span> <span class="synStatement">.=</span> '<span class="synConstant">%05</span>'; <span class="synComment">//information element (IE) identifier - 0x05 = 16-bit port addressing scheme</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">$</span><span class="synIdentifier">fields</span><span class="synSpecial">[</span>'<span class="synConstant">udh</span>'<span class="synSpecial">]</span> <span class="synStatement">.=</span> '<span class="synConstant">%04</span>'; <span class="synComment">//IE data length - 4 bytes</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">$</span><span class="synIdentifier">fields</span><span class="synSpecial">[</span>'<span class="synConstant">udh</span>'<span class="synSpecial">]</span> <span class="synStatement">.=</span> '<span class="synConstant">%0B%84</span>'; <span class="synComment">//IE data - destination port, 0x0B84 = port 2948 (WAP Push)</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">$</span><span class="synIdentifier">fields</span><span class="synSpecial">[</span>'<span class="synConstant">udh</span>'<span class="synSpecial">]</span> <span class="synStatement">.=</span> '<span class="synConstant">%23%F0</span>'; <span class="synComment">//IE data - origination port, 0x23F0 = port 9200 </span><br /><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synComment">//WBXML version of Service Indication (si)</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synComment">//headers</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">$</span><span class="synIdentifier">fields</span><span class="synSpecial">[</span>'<span class="synConstant">text</span>'<span class="synSpecial">]</span> <span class="synStatement">.=</span> '<span class="synConstant">%1B</span>'; <span class="synComment">//Transaction ID</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">$</span><span class="synIdentifier">fields</span><span class="synSpecial">[</span>'<span class="synConstant">text</span>'<span class="synSpecial">]</span> <span class="synStatement">.=</span> '<span class="synConstant">%06</span>'; <span class="synComment">//PDU Type - Push</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">$</span><span class="synIdentifier">fields</span><span class="synSpecial">[</span>'<span class="synConstant">text</span>'<span class="synSpecial">]</span> <span class="synStatement">.=</span> '<span class="synConstant">%01</span>'; <span class="synComment">//length of headers</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">$</span><span class="synIdentifier">fields</span><span class="synSpecial">[</span>'<span class="synConstant">text</span>'<span class="synSpecial">]</span> <span class="synStatement">.=</span> '<span class="synConstant">%AE</span>'; <span class="synComment">//Content-type: application/vnd.wap.sic </span><br /><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synComment">//xml body</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">$</span><span class="synIdentifier">fields</span><span class="synSpecial">[</span>'<span class="synConstant">text</span>'<span class="synSpecial">]</span> <span class="synStatement">.=</span> '<span class="synConstant">%02</span>'; <span class="synComment">//WBXML Version 1.2</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">$</span><span class="synIdentifier">fields</span><span class="synSpecial">[</span>'<span class="synConstant">text</span>'<span class="synSpecial">]</span> <span class="synStatement">.=</span> '<span class="synConstant">%05</span>'; <span class="synComment">//DTD Version SI 1.0 Public Identifier</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">$</span><span class="synIdentifier">fields</span><span class="synSpecial">[</span>'<span class="synConstant">text</span>'<span class="synSpecial">]</span> <span class="synStatement">.=</span> '<span class="synConstant">%6A</span>'; <span class="synComment">//Charset UTF-8</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">$</span><span class="synIdentifier">fields</span><span class="synSpecial">[</span>'<span class="synConstant">text</span>'<span class="synSpecial">]</span> <span class="synStatement">.=</span> '<span class="synConstant">%00</span>'; <span class="synComment">//String Table Length (0)</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">$</span><span class="synIdentifier">fields</span><span class="synSpecial">[</span>'<span class="synConstant">text</span>'<span class="synSpecial">]</span> <span class="synStatement">.=</span> '<span class="synConstant">%45</span>'; <span class="synComment">//&lt;si&gt;</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">$</span><span class="synIdentifier">fields</span><span class="synSpecial">[</span>'<span class="synConstant">text</span>'<span class="synSpecial">]</span> <span class="synStatement">.=</span> '<span class="synConstant">%C6</span>'; <span class="synComment">//&lt;indication&gt;</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">$</span><span class="synIdentifier">fields</span><span class="synSpecial">[</span>'<span class="synConstant">text</span>'<span class="synSpecial">]</span> <span class="synStatement">.=</span> '<span class="synConstant">%0C</span>'; <span class="synComment">//href=&quot;http://</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">$</span><span class="synIdentifier">fields</span><span class="synSpecial">[</span>'<span class="synConstant">text</span>'<span class="synSpecial">]</span> <span class="synStatement">.=</span> '<span class="synConstant">%03</span>'; <span class="synComment">//start of string value</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">$</span><span class="synIdentifier">fields</span><span class="synSpecial">[</span>'<span class="synConstant">text</span>'<span class="synSpecial">]</span> <span class="synStatement">.=</span> <span class="synStatement">$</span><span class="synIdentifier">this</span><span class="synType">-&gt;</span>urlHexEncode<span class="synSpecial">(</span><span class="synStatement">$</span><span class="synIdentifier">sms</span><span class="synType">-&gt;</span>getURL<span class="synSpecial">())</span>;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">$</span><span class="synIdentifier">fields</span><span class="synSpecial">[</span>'<span class="synConstant">text</span>'<span class="synSpecial">]</span> <span class="synStatement">.=</span> '<span class="synConstant">%00</span>'; <span class="synComment">//end of string value</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">$</span><span class="synIdentifier">fields</span><span class="synSpecial">[</span>'<span class="synConstant">text</span>'<span class="synSpecial">]</span> <span class="synStatement">.=</span> '<span class="synConstant">%01</span>'; <span class="synComment">//si-id attribute</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">$</span><span class="synIdentifier">fields</span><span class="synSpecial">[</span>'<span class="synConstant">text</span>'<span class="synSpecial">]</span> <span class="synStatement">.=</span> '<span class="synConstant">%03</span>'; <span class="synComment">//start of string value</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">$</span><span class="synIdentifier">fields</span><span class="synSpecial">[</span>'<span class="synConstant">text</span>'<span class="synSpecial">]</span> <span class="synStatement">.=</span> <span class="synStatement">$</span><span class="synIdentifier">this</span><span class="synType">-&gt;</span>urlHexEncode<span class="synSpecial">(</span><span class="synStatement">$</span><span class="synIdentifier">sms</span><span class="synType">-&gt;</span>getText<span class="synSpecial">())</span>;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">$</span><span class="synIdentifier">fields</span><span class="synSpecial">[</span>'<span class="synConstant">text</span>'<span class="synSpecial">]</span> <span class="synStatement">.=</span> '<span class="synConstant">%00</span>'; <span class="synComment">//end of string value</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">$</span><span class="synIdentifier">fields</span><span class="synSpecial">[</span>'<span class="synConstant">text</span>'<span class="synSpecial">]</span> <span class="synStatement">.=</span> '<span class="synConstant">%01</span>'; <span class="synComment">//end element (&lt;/si&gt;)</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">$</span><span class="synIdentifier">fields</span><span class="synSpecial">[</span>'<span class="synConstant">text</span>'<span class="synSpecial">]</span> <span class="synStatement">.=</span> '<span class="synConstant">%01</span>'; <span class="synComment">//end element () </span><br /><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">return</span> <span class="synStatement">$</span><span class="synIdentifier">this</span><span class="synType">-&gt;</span>sendSMS<span class="synSpecial">(</span><span class="synStatement">$</span><span class="synIdentifier">fields</span><span class="synSpecial">)</span>;<br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synSpecial">}</span> <br /><br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synType">private</span> <span class="synPreProc">function</span> urlHexEncode<span class="synSpecial">(</span><span class="synStatement">$</span><span class="synIdentifier">text</span><span class="synSpecial">)</span><br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synSpecial">{</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">$</span><span class="synIdentifier">string</span> <span class="synStatement">=</span> '';<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">for</span> <span class="synSpecial">(</span><span class="synStatement">$</span><span class="synIdentifier">i</span><span class="synStatement">=</span><span class="synConstant">0</span>; <span class="synStatement">$</span><span class="synIdentifier">i</span> <span class="synStatement">&lt;</span> <span class="synIdentifier">strlen</span><span class="synSpecial">(</span><span class="synStatement">$</span><span class="synIdentifier">text</span><span class="synSpecial">)</span>; <span class="synStatement">$</span><span class="synIdentifier">i</span><span class="synStatement">++</span><span class="synSpecial">)</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synSpecial">{</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">$</span><span class="synIdentifier">letter</span> <span class="synStatement">=</span> <span class="synStatement">$</span><span class="synIdentifier">text</span><span class="synSpecial">[</span><span class="synStatement">$</span><span class="synIdentifier">i</span><span class="synSpecial">]</span>;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synComment">//get the numeric ascii value of the letter</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synComment">//convert it to hex and add a percent (%)</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">$</span><span class="synIdentifier">string</span> <span class="synStatement">.=</span> <span class="synIdentifier">sprintf</span><span class="synSpecial">(</span>'<span class="synConstant">%%%02X</span>', <span class="synIdentifier">ord</span><span class="synSpecial">(</span><span class="synStatement">$</span><span class="synIdentifier">letter</span><span class="synSpecial">))</span>;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synSpecial">}</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">return</span> <span class="synStatement">$</span><span class="synIdentifier">string</span>;<br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synSpecial">}</span><br /><span class="synSpecial">}</span> <br /><br /><span class="synSpecial">?&gt;</span><br /></code></div><br />
sendSMS() in the parent, SMSBase, simply uses the file() function to send the URL via HTTP GET -- you'll have to make sure allow_url_fopen is set to On in your php.ini or with ini_set().<br />
<br />
Also, now that we're doing all of the encoding ourselves and sending directly to the <strong>smsbox</strong> daemon, we can turn off <strong>wapbox</strong>.  In the startup script, comment out the <strong>wapbox</strong> line.  In kannel.conf you can comment out any wap related entries in the core group (wapbox-port, wdp-interface-name, etc.).  You can also comment out the entire wapbox, ppg, and wap-push-user group blocks.  You'll have to restart kannel for these changes to take effect.<br />
<h4>Resources</h4><br />
<a href="http://dev.sellingsource.com/wp-content/uploads/2007/09/wapsendertar.bz2">Download the entire example.</a><br />
<br />
(udh explanation)<br />
<a href="http://discussion.forum.nokia.com/forum/archive/index.php/t-13518.html">http://discussion.forum.nokia.com/forum/archive/index.php/t-13518.html</a><br />
<br />
(wbxml breakdown)<br />
<a href="http://discussion.forum.nokia.com/forum/archive/index.php/t-16775.html">http://discussion.forum.nokia.com/forum/archive/index.php/t-16775.html</a><br />
<a href="http://www.activexperts.com/activsms/sms/wappushsi/">http://www.activexperts.com/activsms/sms/wappushsi/</a><br />
<br />
(wappush using PHP)<br />
<a href="http://www.mail-archive.com/users@kannel.org/msg07893.html">http://www.mail-archive.com/users@kannel.org/msg07893.html</a><br />
<br />
<h4>Articles In This Series:</h4><br />
<a href="http://dev.sellingsource.com/?p=4">WAP: Part 1 - MultiTech USB GPRS Modem in Linux</a><br />
<a href="http://dev.sellingsource.com/?p=8">WAP: Part 2 - Send SMS from Kannel</a><br />
WAP: Part 3 - WAP Push with Kannel &#038; PHP<br />
<a href="http://dev.sellingsource.com/?p=13">WAP: Part 4 - Send SMS from PHP</a><br />
<a href="http://dev.sellingsource.com/?p=14">WAP: Part 5 - Customizing content with WURFL</a><br />
<a href="http://dev.sellingsource.com/?p=15">WAP: Part 6 - Microbrowser content in WML / XHTML MP</a>]]></content:encoded>
			<wfw:commentRss>http://dev.sellingsource.com/2006/12/07/sending-wap-push-messages-with-kannel-php/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Optimizing Using Xdebug and Kcachegrind</title>
		<link>http://dev.sellingsource.com/2006/12/03/optimizing-using-xdebug-and-kcachegrind/</link>
		<comments>http://dev.sellingsource.com/2006/12/03/optimizing-using-xdebug-and-kcachegrind/#comments</comments>
		<pubDate>Sun, 03 Dec 2006 19:49:55 +0000</pubDate>
		<dc:creator>johnh</dc:creator>
		
		<category><![CDATA[Linux]]></category>

		<category><![CDATA[PHP]]></category>

		<category><![CDATA[Performance]]></category>

		<guid isPermaLink="false">http://dev.sellingsource.com/?p=5</guid>
		<description><![CDATA[Introduction
Recently it came to light that a product of ours was going to be receiving more and more volume.  Our client had plans of putting more users on our system (about ten times as many), and we had already experienced some performance problems before.  It is the type of problem that you would [...]]]></description>
			<content:encoded><![CDATA[<h4>Introduction</h4><br />
Recently it came to light that a product of ours was going to be receiving more and more volume.  Our client had plans of putting more users on our system (about ten times as many), and we had already experienced some performance problems before.  It is the type of problem that you would have a hard time fixing by throwing more servers at it.  The original application wasn’t all that well designed.  We made a lot of mistakes and we learned a lot about product development on this particular application.  It would seem that horizontal scalability (adding more servers) wouldn’t solve our problem. There are far too many bottlenecks in the database, so more application servers don’t really help us.  That leaves the option of vertical scaling (upgrading or replacing servers).  Vertical scaling, however, brings with it another element: Cost.  Not wanting to spend a ton of money on replacing our already very expensive servers, we turned our eyes to the code itself.<br />
<br />
<h4>Installing Xdebug and KCacheGrind</h4><br />
How does one find these problems?  My first thought was some way of profiling code. Xdebug (<a href="http://www.xdebug.org" title="http://www.xdebug.org" target="_blank">http://xdebug.org/</a>) provides a pretty good profiler, and exports results to cachegrind files that can be analyzed using KCacheGrind (<a href="http://kcachegrind.sourceforge.net">http://kcachegrind.sourceforge.net/</a>).  This particular combination of open source ventures is very useful.  You simply install the xdebug extension, enabled it, then edit your xdebug settings.   I use mostly default settings, and you can enable the profiler with the following setting:<br />
<br />
<div class="codeblock"><code>xdebug.profiler_enable=<span class="synConstant">&quot;1&quot;</span><br /></code></div><br />
<br />
XDebug has an enormous amount of options, and the default configuration provided with the extension is pretty solid.  There’s a page on their website outlining all the settings and their uses (http://xdebug.org/docs/all_settings).<br />
<br />
<h4>First Run</h4><br />
Once you have installed and XDebug and KCacheGrind, run your application, and then look in /tmp to see if you have a cachegrind output file.  For example:<br />
<br />
<div class="codeblock"><code>root@localhost /tmp # ls -al -r cachegrind.out.*<br />-rw-r--r-- 1 apache apache 105863 Jun 17 12:35 cachegrind.out.510234603<br /></code></div><br />
<br />
If you do not have a file similar to this, be sure the extension is loaded. If you are using a web server such as apache, remember to restart the daemon after installing xdebug.  If you’re using the command line, simply running a php –v should tell you whether or not XDebug is installed and working. For example:<br />
<br />
<div class="codeblock"><code>root@localhost /etc/php/cli-php5/ext-active # php -v<br />PHP 5.2.2-pl1-gentoo (cli) (built: May 25 2007 12:34:43)<br />Copyright (c) 1997-2007 The PHP Group<br />Zend Engine v2.2.0, Copyright (c) 1998-2007 Zend Technologies<br />with Xdebug v2.0.0RC3, Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, by Derick Rethans<br /></code></div><br />
<br />
If you are using a web server for your application, XDebug will show up in the output of a phpinfo() call if it is installed properly. You can also use this to see if the profiler is properly enabled. It should look something like this (There's a lot more options than I show here):<br />
<br />
<div align="center"><img src='http://dev.sellingsource.com/wp-content/uploads/2007/09/xdebug-info.png' alt='XDebug PHP Info' /></div><br />
<br />
<h4>An Example</h4><br />
I have created a simple application which loops 10,000 times, printing stuff to the screen, performing arithmetic, generating random numbers, and file output.  The entire purpose of this little noisy script is to do a whole bunch of stuff, and give us an opportunity to see which parts take the longest, using Xdebug and KCacheGrind.  I wanted to profile an actual application at some point, but I felt as though it would be too cumbersome and it might be difficult to illustrate the idea. Below is my example.<br />
<br />
<b>profile1.php</b><br />
<div class="codeblock"><code><span class="synSpecial">&lt;?php</span><br /><br />&nbsp; &nbsp; <span class="synIdentifier">define</span> <span class="synSpecial">(</span>'<span class="synConstant">NUM_LOOPS</span>', <span class="synConstant">10000</span><span class="synSpecial">)</span>;<br /><br />&nbsp; &nbsp; <span class="synPreProc">function</span> complex_calculation<span class="synSpecial">()</span><br />&nbsp; &nbsp; <span class="synSpecial">{</span><br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">return</span> <span class="synConstant">1.034587763</span> <span class="synStatement">*</span> <span class="synIdentifier">mt_rand</span><span class="synSpecial">()</span> <span class="synStatement">%</span> <span class="synIdentifier">mt_rand</span><span class="synSpecial">()</span>;<br />&nbsp; &nbsp; <span class="synSpecial">}</span><br /><br />&nbsp; &nbsp; <span class="synPreProc">function</span> print_something<span class="synSpecial">()</span><br />&nbsp; &nbsp; <span class="synSpecial">{</span><br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synPreProc">echo</span> &quot;<span class="synConstant">something</span>&quot;;<br />&nbsp; &nbsp; <span class="synSpecial">}</span><br /><br />&nbsp; &nbsp; <span class="synPreProc">function</span> write_something<span class="synSpecial">()</span><br />&nbsp; &nbsp; <span class="synSpecial">{</span><br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synStatement">$</span><span class="synIdentifier">fp</span> <span class="synStatement">=</span> <span class="synIdentifier">fopen</span><span class="synSpecial">(</span>&quot;<span class="synConstant">test.tmp</span>&quot;, &quot;<span class="synConstant">w</span>&quot;<span class="synSpecial">)</span>;<br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synIdentifier">fwrite</span><span class="synSpecial">(</span><span class="synStatement">$</span><span class="synIdentifier">fp</span>, &quot;<span class="synConstant">something_important</span>&quot;<span class="synSpecial">)</span>;<br />&nbsp; &nbsp; &nbsp; &nbsp; print_something<span class="synSpecial">()</span>;<br />&nbsp; &nbsp; &nbsp; &nbsp; <span class="synIdentifier">fclose</span><span class="synSpecial">(</span><span class="synStatement">$</span><span class="synIdentifier">fp</span><span class="synSpecial">)</span>;<br />&nbsp; &nbsp; <span class="synSpecial">}</span><br /><br />&nbsp; &nbsp; <span class="synStatement">for</span> <span class="synSpecial">(</span><span class="synStatement">$</span><span class="synIdentifier">i</span> <span class="synStatement">=</span> <span class="synConstant">0</span>; <span class="synStatement">$</span><span class="synIdentifier">i</span> <span class="synStatement">&lt;</span> NUM_LOOPS; <span class="synStatement">$</span><span class="synIdentifier">i</span><span class="synStatement">++</span><span class="synSpecial">)</span><br />&nbsp; &nbsp; <span class="synSpecial">{</span><br />&nbsp; &nbsp; &nbsp; &nbsp; complex_calculation<span class="synSpecial">()</span>;<br />&nbsp; &nbsp; &nbsp; &nbsp; print_something<span class="synSpecial">()</span>;<br />&nbsp; &nbsp; &nbsp; &nbsp; write_something<span class="synSpecial">()</span>;<br />&nbsp; &nbsp; <span class="synSpecial">}</span><br /><span class="synSpecial">?&gt;</span><br /></code></div><br />
<br />
Once you have loaded the cachegrind output file into KCacheGrind, you should be presented with a few panels.  One is a list view, another is a panel with a bunch of tabs, and another is a tree view which provides a very useful graphical representation of where CPU is being spent.  In the list (and the graph) you should notice an item labeled <b>{main}</b>.  This is the all-inclusive element that shows the total execution of the program you're profiling.  It should show as 100% of your CPU usage. Here is the list view:<br />
<div align="center"><br />
<img src='http://dev.sellingsource.com/wp-content/uploads/2007/09/listview1.png' alt='List View' /><br />
</div><br />
<br />
Here's a breakdown of each column:<br />
<ul><br />
<li><b>Incl.</b>: The total CPU time spent in this function and every function it called inclusively.</li><br />
<li><b>Self</b>: Only CPU time spent in this function, not counting the time spent in functions CALLED by this function.</li><br />
<li><b>Called</b>: Total number of times this function was called.</li><br />
<li><b>Function</b>: Name of this function.</li><br />
<li><b>Location</b>: Script file containing this function.</li><br />
</ul><br />
<br />
Next is the graph/table view.  The nice thing about this feature is its ability to show major choke points in a very noticeable format.  Typically, this graph excludes calls which are very tiny compared to the rest of the application. Very useful.  If you select the <b>{main}</b> box in the graph and you should see something very close to this:<br />
<br />
<div align="center"><br />
<img src='http://dev.sellingsource.com/wp-content/uploads/2007/09/listview2.png' alt='Tree View' /><br />
</div><br />
<br />
Even the most untrained eye can probably guess that <b>write_something()</b> is the slower part of this application. Double click the <b>write_something()</b> box to make it become the new focal point of the graph. Now that you have that selected, you should see something similar to this:<br />
<br />
<div align="center"><br />
<img src='http://dev.sellingsource.com/wp-content/uploads/2007/09/treeview2.png' alt='Tree View 2' /><br />
</div><br />
<br />
With <b>write_something()</b> centered, you can see who has called this method (100% of the time, it is <b>{main}</b>), and how much time is spent in functions called by <b>write_something()</b>.  So, of the time spent in <b>write_something()</b>, most of that time is spent opening the file, and less time is spent in <b>fwrite()</b>.<br />
<br />
<h4>Conclusion</h4><br />
I could go into details about optimizing my example script, but I feel as though the point has been delivered. Xdebug and KCacheGrind work together to become a very powerful tool when attempting to optimize a PHP application. There are many features to KCacheGrind and I encourage everyone to explore them all. Additionally, it has the capability to track memory usage, but I've had personal experiences which suggest that does not work perfectly.  <br />
<br />
Good luck!]]></content:encoded>
			<wfw:commentRss>http://dev.sellingsource.com/2006/12/03/optimizing-using-xdebug-and-kcachegrind/feed/</wfw:commentRss>
		</item>
		<item>
		<title>WAP: Part 2 - Send SMS from Kannel</title>
		<link>http://dev.sellingsource.com/2006/11/13/configuring-kannel-to-send-sms/</link>
		<comments>http://dev.sellingsource.com/2006/11/13/configuring-kannel-to-send-sms/#comments</comments>
		<pubDate>Mon, 13 Nov 2006 16:42:28 +0000</pubDate>
		<dc:creator>justinf</dc:creator>
		
		<category><![CDATA[Kannel]]></category>

		<category><![CDATA[Linux]]></category>

		<category><![CDATA[WAP]]></category>

		<guid isPermaLink="false">http://dev.sellingsource.com/?p=8</guid>
		<description><![CDATA[While there is Kannel documentation, I found it was unclear to me since I wanted to hone in on one thing: sending a URL to my phone.  So in this article I'll cover setting up Kannel to send a standard SMS text message to a mobile phone.
Compilation and Installation
I use Gentoo on my box [...]]]></description>
			<content:encoded><![CDATA[While there is Kannel documentation, I found it was unclear to me since I wanted to hone in on one thing: sending a URL to my phone.  So in this article I'll cover setting up Kannel to send a standard SMS text message to a mobile phone.<br />
<h4>Compilation and Installation</h4><br />
I use Gentoo on my box at work.  Yes, it can be both powerful and cumbersome, but it also had the best amd64 support when the processors were first available.  So I will be covering Kannel installation in Gentoo/AMD64, but other distributions and architectures will probably be similar.  The latest version in portage for the amd64 platform (at time of writing) was Kannel 1.4.1:<br />
<div class="codeblock"><code>~ # emerge -av kannel&nbsp; &nbsp;  <br /><br />These are the packages that would be merged, in order:&nbsp; &nbsp;  <br /><br />Calculating dependencies&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  ... done! <br />[ebuild&nbsp;  R&nbsp;  ] app-mobilephone/kannel-1.4.1&nbsp; USE=&quot;doc mysql pam pcre sqlite sqlite3 ssl -debug -postgres&quot; 0 kB&nbsp; &nbsp;  <br /><br />Total: 1 package (1 reinstall), Size of downloads: 0 kB<br /></code></div><h4>kannel.conf configuration file</h4><br />
Once the software is compiled and installed, we'll make a simple Kannel configuration file.<br />
<br />
<strong>/etc/kannel/kannel.conf</strong><br />
<div class="codeblock"><code><span class="synComment"># CORE BEARERBOX/KANNEL CONFIG</span><br />group <span class="synStatement">=</span> core<br /><span class="synStatement">admin</span>-port <span class="synStatement">=</span> <span class="synConstant">13000</span><br /><span class="synStatement">admin</span>-password <span class="synStatement">=</span> admin_pass<br /><span class="synStatement">status</span>-password <span class="synStatement">=</span> status_pass<br />log-<span class="synStatement">file</span> <span class="synStatement">=</span> <span class="synStatement">&quot;</span><span class="synConstant">/var/log/kannel/kannel.log</span><span class="synStatement">&quot;</span><br /><span class="synComment">#&nbsp;  0 = 'debug', 1 = 'info', 2 = 'warning', 3 = 'error', 4 = 'panic'</span><br />log-level <span class="synStatement">=</span> <span class="synConstant">4</span><br />access-log <span class="synStatement">=</span> <span class="synStatement">&quot;</span><span class="synConstant">/var/log/kannel/core_access.log</span><span class="synStatement">&quot;</span><br /><span class="synComment"># Wapbox related</span><br />wapbox-port <span class="synStatement">=</span> <span class="synConstant">13002</span><br />wdp-interface-name <span class="synStatement">=</span> <span class="synStatement">&quot;</span><span class="synConstant">*</span><span class="synStatement">&quot;</span><br /><span class="synComment"># Smsbox related</span><br /><span class="synComment">#smsbox-port = 13001&nbsp; </span><br /><br /><span class="synComment"># BASE WAPBOX CONFIG</span><br />group <span class="synStatement">=</span> wapbox<br />bearerbox-host <span class="synStatement">=</span> localhost<br /></code></div><br />
A few notes on the configuration file... The configuration blocks always start with a "group" directive.  Also, there should not be any blank lines within a group, but there must be a blank line before the next group.  A comment is a non-blank line.  Kannel is pretty picky about it's configuration file setup, so it probably won't start if you got it wrong.  You can see what all of these configuration directives do by reading the <a HREF="http://kannel.org/download/1.4.1/userguide-1.4.1/userguide.html">Kannel user guide</a>.  You can also look at a good <a HREF="http://www.ibm.com/developerworks/library/wi-kannelwap.html">Kannel WAP article from IBM</a>.<br />
<br />
Basically, in this configuration Kannel's core daemon will run on port 13000.  All of the administration is done via http requests through this port.  You'll need to use the specified admin and status passwords for certain operations.  Also, I added a wapbox-port and wdp-interface directives.  We're not actually going to start the <strong>wapbox</strong> executable yet, but we need to have one additional group for Kannel to start... so this is just the minimum we need, and these are the two directives required for <strong>wapbox</strong>.  Then we need the wapbox group, and it's required bearerbox-host directive.<br />
<br />
There are additional directives for allowing/blocking access to Kannel based on IP etc.  I am behind a firewall and I'm not concerned with  these settings, but you may choose to use them to protect yourself.  Please see the aforementioned guides for this  information.<br />
<h4>Starting Kannel</h4><br />
So now let's start Kannel.  The init.d startup scripts for Gentoo are terribly broken.  Rather than fixing them, I just created a simple script to start up Kannel, specifically the <strong>bearerbox</strong> executable.  We'll revisit this file later to add the other components.<br />
<br />
<strong>start_kannel.sh</strong><br />
<div class="codeblock"><code><span class="synComment">#!/bin/sh&nbsp; &nbsp;  </span><br /><br /><span class="synStatement">rm</span> /var/log/kannel/* <br />bearerbox <span class="synSpecial">--verbosity</span> <span class="synConstant">4</span> <span class="synSpecial">--logfile</span> /var/log/kannel/bearerbox.log /etc/kannel/kannel.conf &amp;<br /></code></div><h4>Kannel Administration</h4><br />
Once it's up and running, you can check the status using your web browser or via the command-line using curl, etc.:<br />
<br />
Check the status (requires status password)<br />
<div class="codeblock"><code>~ # curl http://localhost:13000/status?password=status_pass<br /></code></div><br />
Shutdown Kannel (requires admin password)<br />
<div class="codeblock"><code>~ # curl http://localhost:13000/shutdown?password=admin_pass<br /></code></div><h4>Sending SMS Messages</h4><br />
Now that <strong>bearerbox</strong> is confirmed to be working (and we shut it back down), let's add <strong>smsbox</strong> to the mix:<br />
<br />
<strong>/etc/kannel/kannel.conf</strong><br />
<div class="codeblock"><code><span class="synComment"># CORE BEARERBOX/KANNEL CONFIG </span><br />group = core <br />admin-port = 13000 <br />admin-password = admin_pass <br />status-password = status_pass <br />log-file = <span class="synConstant">&quot;/var/log/kannel/kannel.log&quot;</span> <br /><span class="synComment">#&nbsp;  0 = 'debug', 1 = 'info', 2 = 'warning', 3 = 'error', 4 = 'panic' </span><br />log-level = 4 <br />access-log = <span class="synConstant">&quot;/var/log/kannel/core_access.log&quot;</span> <br /><span class="synComment"># Wapbox related </span><br />wapbox-port = 13002 <br />wdp-interface-name = <span class="synConstant">&quot;*&quot;</span> <br /><span class="synComment"># Smsbox related </span><br />smsbox-port = 13001&nbsp; &nbsp;  <br /><br /><span class="synComment"># BASE WAPBOX CONFIG </span><br />group = wapbox <br />bearerbox-host = localhost&nbsp; &nbsp;  <br /><br /><span class="synComment"># GSM DEVICE FILE INFO </span><br />group = smsc <br />smsc = at <br />smsc-id = gsm_modem <br />modemtype = wavecom <br />device = /dev/ttyUSB0 <br />keepalive = 30 <br />max-error-count = 5 <br />sim-buffering = true&nbsp; &nbsp;  <br /><br /><span class="synComment"># MODEM CONFIGURATION </span><br />group = modems <br />id = wavecom <br />name = Wavecom <br />detect-string = <span class="synConstant">&quot;WAVECOM&quot;</span> <br />speed = 115200 <br />reset-string = <span class="synConstant">&quot;ATZ&quot;</span> <br />init-string = <span class="synConstant">&quot;AT+CNMI=1,2,0,1,0;+CMEE=1&quot;</span> <br /><span class="synComment"># trying this to see if it resolves errors when the </span><br /><span class="synComment"># modem erroneously returns ERROR to the AT+CPIN? command </span><br />no-pin = true&nbsp; &nbsp;  <br /><br /><span class="synComment"># SMSBOX SETUP </span><br />group = smsbox <br />bearerbox-host = localhost <br />sendsms-port = 13013 <br />global-sender = 8005551212 <br />log-file = <span class="synConstant">&quot;/var/log/kannel/smsbox.log&quot;</span> <br />log-level = 4 <br />access-log = <span class="synConstant">&quot;/var/log/kannel/smsbox_access.log&quot;</span>&nbsp; &nbsp;  <br /><br /><span class="synComment"># SEND-SMS USERS </span><br />group = sendsms-user <br />username = sms_user <br />password = sms_pass <br />forced-smsc = gsm_modem&nbsp; &nbsp;  <br /><br /><span class="synComment"># SMS SERVICES </span><br /><span class="synComment"># there should be default always </span><br />group = sms-service <br />keyword = default <br />text = <span class="synConstant">&quot;No service specified&quot;</span> <br />max-messages = 0 <br />catch-all = true<br /></code></div><br />
The gsm_modem smsc-id and modems group are configurations that Kannel uses to communicate with my <a HREF="http://dev.sellingsource.com/?p=4">Mutitech USB GPRS modem that I covered in a previous article</a>.  The smsbox group specifies that it's running on localhost port 13013 and the "from" phone number we want to show up on all messages is in the global-sender directive.  The sendsms-user group defines what username and password we'll need to supply when sending SMS messages.  Lastly the sms-service group is used for SMS messages received by Kannel.  In this case we're just going to ignore them.  Let's add <strong>smsbox</strong> to the startup file:<br />
<br />
<strong>start_kannel.sh</strong><br />
<div class="codeblock"><code><span class="synComment">#!/bin/sh&nbsp; &nbsp;  </span><br /><br /><span class="synStatement">rm</span> /var/log/kannel/* <br />bearerbox <span class="synSpecial">--verbosity</span> <span class="synConstant">4</span> <span class="synSpecial">--logfile</span> /var/log/kannel/bearerbox.log /etc/kannel/kannel.conf &amp;<br /><span class="synStatement">sleep</span> <span class="synConstant">10</span> <br />smsbox <span class="synSpecial">--verbosity</span> <span class="synConstant">4</span> <span class="synSpecial">--logfile</span> /var/log/kannel/smsbox.log /etc/kannel/kannel.conf &amp;<br /></code></div><br />
The sleep is in there to give <strong>bearerbox</strong> sufficient time to start and open it's communication ports before the others start and try to connect.<br />
<br />
To test the SMS service, we'll connect directly to the sendsms CGI using CURL.  The username and password parameters should be the same as user/pass in the sendsms-user group.  The number should be a standard US 10-digit mobile phone number, and the text should be URL encoded.  I added double quotes to the call to avoid the shell from interpreting the ampersands as background commands.<br />
<div class="codeblock"><code>~ # curl &quot;http://localhost:13013/cgi-bin/sendsms?username=sms_user&amp;password=sms_pass&amp;to=7025551212&amp;text=Hello+world&quot; <br />0: Accepted for delivery<br /></code></div><br />
You should shortly have an SMS message on your mobile.  If not, I suggest grepping the /var/log/kannel directory for your area code to see what issues you may have.  Things I've run into include bad usernames / passwords and a deactivated SIM card that yielded a "CMS ERROR: 512" from the modem.<br />
<br />
<h4>Articles In This Series:</h4><br />
<a href="http://dev.sellingsource.com/?p=4">WAP: Part 1 - MultiTech USB GPRS Modem in Linux</a><br />
WAP: Part 2 - Send SMS from Kannel<br />
<a href="http://dev.sellingsource.com/?p=10">WAP: Part 3 - WAP Push with Kannel &#038; PHP</a><br />
<a href="http://dev.sellingsource.com/?p=13">WAP: Part 4 - Send SMS from PHP</a><br />
<a href="http://dev.sellingsource.com/?p=14">WAP: Part 5 - Customizing content with WURFL</a><br />
<a href="http://dev.sellingsource.com/?p=15">WAP: Part 6 - Microbrowser content in WML / XHTML MP</a>]]></content:encoded>
			<wfw:commentRss>http://dev.sellingsource.com/2006/11/13/configuring-kannel-to-send-sms/feed/</wfw:commentRss>
		</item>
	</channel>
</rss>
