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

<channel>
	<title>Richard Lord &#187; PHP</title>
	<atom:link href="http://www.richardlord.net/blog/tag/php/feed" rel="self" type="application/rss+xml" />
	<link>http://www.richardlord.net</link>
	<description>Actionscript/Flex, PHP and Java developer</description>
	<lastBuildDate>Mon, 23 Jan 2012 17:07:46 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>If you want to create AVM2 swfs from PHP</title>
		<link>http://www.richardlord.net/blog/if-you-want-to-create-avm2-swfs-from-php</link>
		<comments>http://www.richardlord.net/blog/if-you-want-to-create-avm2-swfs-from-php#comments</comments>
		<pubDate>Thu, 10 Jan 2008 10:21:49 +0000</pubDate>
		<dc:creator>Richard</dc:creator>
				<category><![CDATA[All]]></category>
		<category><![CDATA[AVM2]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.bigroom.co.uk/blog/if-you-want-to-create-avm2-swfs-from-php/</guid>
		<description><![CDATA[<p>If you want to create AVM2 (Actionscript 3) swfs from PHP then this file may be useful. It creates the number formats used in AVM2 swfs. I created these functions for the SWX project and am releasing the code under the MIT licence so it can be used in other projects too...</p>]]></description>
			<content:encoded><![CDATA[<p>If you want to create AVM2 (Actionscript 3) swfs from PHP then this file may be useful. It creates the number formats used in AVM2 swfs, <a href="http://www.adobe.com/devnet/actionscript/articles/avm2overview.pdf">as described here</a>. I created these functions for the <a href="http://swxformat.org/">SWX project</a> and am releasing the code under the MIT licence so it can be used in other projects too.</p>

<p><a href="/files/AVM2_Numbers.zip" title="Download source code">
<img src="/images/icons/phpfile.gif" width="31" height="31" alt="Download source code" class="icon" />
<b>Download the PHP source code.</b></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.richardlord.net/blog/if-you-want-to-create-avm2-swfs-from-php/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>PHP Password Security</title>
		<link>http://www.richardlord.net/blog/php-password-security</link>
		<comments>http://www.richardlord.net/blog/php-password-security#comments</comments>
		<pubDate>Wed, 10 Oct 2007 15:45:34 +0000</pubDate>
		<dc:creator>Richard</dc:creator>
				<category><![CDATA[All]]></category>
		<category><![CDATA[Best practice]]></category>
		<category><![CDATA[Free code]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Security]]></category>

		<guid isPermaLink="false">http://www.bigroom.co.uk/blog/php-password-security/</guid>
		<description><![CDATA[<p>If you build websites that require users to register it's your responsibility to keep their passwords safe. And if you're storing the passwords in plain text then you're not doing your job properly. What happens if your database is stolen? It's not just your site that is compromised. Since most users use the same password on multiple sites, all those sites have also been compromised...</p>]]></description>
			<content:encoded><![CDATA[<p>If you build websites that require users to register it&#8217;s your responsibility to keep their passwords safe. And if you&#8217;re storing the passwords in plain text then you&#8217;re not doing your job properly. It may be that, <a href="http://reddit.com/info/usqe/comments/cuugl">like Reddit</a>, you think that storing passwords in plain text leads to a better user experience. I happen to agree with you. But then, like Reddit, what happens if your database is stolen? It&#8217;s not just your site that is compromised. Since most users use the same password on multiple sites, all those sites have also been compromised.</p>

<p>No data is entirely secure, and if anyone else has access to your webserver (the company managing the server for you?) or your database (the company storing the backups?) then you don&#8217;t have total control over the security anyway. So there&#8217;s always a chance your database could be stolen. So, the simple rule is to hash your passwords.</p>

<h3>Hashing</h3>

<p>A hash is a string derived from the original password via a one-way algorithm. In other words, it&#8217;s easy to create the hash from the original, but harder (when used for security, ideally impossible) to create the original from the hash. You store the hash in the database, and when the user signs-in you hash the password they sign-in with and compare it to the hash in the database. Something like this</p>

<pre class="code">if( $user->passwordhash == sha1( $_POST['password'] ) )</pre>

<p>That way, you never store the user&#8217;s password.</p>

<p>There are a number of hashing algorithms in PHP, of which md5 and sha1 are the most commonly used. Unfortunately, neither is as secure as they were once thought to be. It would be better to use a more secure hash, and if you have the Hash engine in your PHP installation (included by default since PHP 5.1.2) then you have access to many more algorithms. So a better example would be</p>

<pre class="code">if( $user->passwordhash == hash( 'whirlpool', $_POST['password'] ) )</pre>

<h3>Rainbow tables</h3>

<p>But there&#8217;s another problem. Once your database is stolen, the thief has plenty of time to crack the passwords using a simple <a href="http://www.codinghorror.com/blog/archives/000949.html">Rainbow Table attack</a>. This involves creating a large selection of hashes based on likely passwords (e.g. every word in the dictionary) and then comparing the hashes with the hashes in your database. Within an hour or so, half the passwords in your database will probably have been cracked.</p>

<p>To prevent this you should salt each password by adding a random string to it (called a salt or nonce). The time consuming part of a rainbow table attack is building the dictionary of hashes. Adding a random salt to the password means the thief has to build a whole new dictionary of hashes for each salt, making a rainbow table attack too time consuming to be viable. Each password should have a different salt, and the salt doesn&#8217;t even need to be secret.</p>

<h3>The Code bit</h3>

<p>So, for secure passwords you need code that looks something like this</p>

<pre class="code">// get a new salt - 8 hexadecimal characters long
// current PHP installations should not exceed 8 characters
// on dechex( mt_rand() )
// but we future proof it anyway with substr()
function getPasswordSalt()
{
    return substr( str_pad( dechex( mt_rand() ), 8, '0',
                                           STR_PAD_LEFT ), -8 );
}

// calculate the hash from a salt and a password
function getPasswordHash( $salt, $password )
{
    return $salt . ( hash( 'whirlpool', $salt . $password ) );
}

// compare a password to a hash
function comparePassword( $password, $hash )
{
    $salt = substr( $hash, 0, 8 );
    return $hash == getPasswordHash( $salt, $password );
}

// get a new hash for a password
$hash = getPasswordHash( getPasswordSalt(), $password );</pre>

<p>You don&#8217;t have to attach the salt to the hash, you can instead store them separately within the database, but I like keeping them together in a single string. Equally, the salt needn&#8217;t be in hexadecimal, but I like the symmetry with the hexadecimal hash.</p>

<p>Finally, <a href="http://www.matasano.com/log/958/enough-with-the-rainbow-tables-what-you-need-to-know-about-secure-password-schemes/">as Thomas Ptacek points out</a>, you don&#8217;t want the fastest hash algorithm in the world for this &#8211; a fast algorithm is more useful to an attacker than it is to you.</p>]]></content:encoded>
			<wfw:commentRss>http://www.richardlord.net/blog/php-password-security/feed</wfw:commentRss>
		<slash:comments>29</slash:comments>
		</item>
		<item>
		<title>New Wishlist site</title>
		<link>http://www.richardlord.net/blog/new-wishlist-site</link>
		<comments>http://www.richardlord.net/blog/new-wishlist-site#comments</comments>
		<pubDate>Thu, 22 Feb 2007 11:19:04 +0000</pubDate>
		<dc:creator>Richard</dc:creator>
				<category><![CDATA[All]]></category>
		<category><![CDATA[One Wish List]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Zend Framework]]></category>

		<guid isPermaLink="false">http://www.bigroom.co.uk/blog/new-wishlist-site/</guid>
		<description><![CDATA[<p>I've been posting a lot about the <a href="http://framework.zend.com/">Zend Framework</a> recently. That's because I've been using it in building a new version of my wishlist site. The new site is called One Wishlist and is at <a href="http://onewishlist.net/">onewishlist.net</a>...</p>]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been posting a lot about the <a href="http://framework.zend.com/">Zend Framework</a> recently. That&#8217;s because I&#8217;ve been using it in building a new version of my wish list site. The site is called One Wishlist and is at <a href="http://onewishlist.net/">onewishlist.net</a>. It uses version 0.7 of the Zend Framework. I&#8217;ll try moving it to version 0.8 soon.</p>

<p>I&#8217;ve made a few changes to the site since the previous version, including substantial design changes, but mostly during the move to the Zend Framework I have added hooks for new features that are planned but not yet implemented. Many of these are the result of feedback from the previous site, so thanks to everyone who made suggestions and comments, the features are on their way.</p>

<p>Meanwhile, expect more Flash posts in the next couple of weeks as I have a new flash game to develop for a client.</p>]]></content:encoded>
			<wfw:commentRss>http://www.richardlord.net/blog/new-wishlist-site/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Managing 404 errors in the Zend Framework</title>
		<link>http://www.richardlord.net/blog/managing-404-errors-in-the-zend-framework</link>
		<comments>http://www.richardlord.net/blog/managing-404-errors-in-the-zend-framework#comments</comments>
		<pubDate>Fri, 16 Feb 2007 16:27:40 +0000</pubDate>
		<dc:creator>Richard</dc:creator>
				<category><![CDATA[All]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Zend Framework]]></category>

		<guid isPermaLink="false">http://www.bigroom.co.uk/blog/managing-404-errors-in-the-zend-framework/</guid>
		<description><![CDATA[<p>In the Zend Framework there's no obvious way to deal with all page not found errors in one place, including instances where the controller doesn't exist and where the action doesn't exist. In this post I show the code for a Zend Framework plug-in to handle all 404 errors in one place only, automatically displaying the 404 error page if the Controller or Action aren't defined...</p>]]></description>
			<content:encoded><![CDATA[<p>This applies to version 0.7 of the <a href="http://framework.zend.com/">Zend Framework</a>. Changes for later versions of the framework are at the end of the article.</p>

<p>Early versions of the Zend Framework had a noRoute action that was called when the correct action couldn&#8217;t be found. This was a way to deal with some page not found errors. At some point it was dropped &#8211; I don&#8217;t know when or why because I only started using the Zend Framework recently. It&#8217;s still possible to handle non-existent actions using the __call() method of the controller class. But there&#8217;s no obvious way to deal with all page not found errors in one place, including instances where the controller doesn&#8217;t exist.</p>

<p>The Zend Framework is based around <a href="http://framework.zend.com/manual/en/zend.controller.html">controllers and actions</a>, using URL&#8217;s of the form http://www.example.com/controller/action. If no action is specified the index action is used, and if no controller is specified the index controller is used. You can modify the mapping of URLs to controllers and actions by setting up different <a href="http://framework.zend.com/manual/en/zend.controller.providedsubclasses.html#zend.controller.providedsubclasses.rewriterouter">rewrite routers</a> in the front controller.</p>

<p>A 404 error should occur when the controller or action specified in the URL aren&#8217;t defined. But instead of a 404 error, the Zend Framework throws an exception because the controller class or the action method can&#8217;t be found. There&#8217;s nothing worng with this &#8211; it leaves it for each developer to decide what to do. So what should we do?</p>

<p>To generate an appropriate 404 error with a custom page we need either to intercept the request before the error occurs or to catch the exception after the error occurs, and in either case to redirect to an appropriate controller and action.</p>

<p>I created a <a href="http://framework.zend.com/manual/en/zend.controller.plugins.html">controller plug-in</a> to do just that. In the pre-despatch method it checks the controller class can be loaded and that it contains the required action. If either is not the case it redirects the request to the index action of the noroute controller. Then one just creates an appropriate noroute controller to display the page not found error.</p>

<p>Here&#8217;s the plug-in code.</p>

<pre class="code">require_once 'Zend/Controller/Plugin/Abstract.php';

class Bigroom_Controller_Plugin_Noroute
                           extends Zend_Controller_Plugin_Abstract
{
    public function preDispatch(
                       Zend_Controller_Request_Abstract $request )
    {
        $dispatcher = Zend_Controller_Front::getInstance()
                                                ->getDispatcher();
        
        $controllerName = $request->getControllerName();
        if (empty($controllerName)) {
            $controllerName = $dispatcher->getDefaultController();
        }
        $className = $dispatcher
                          ->formatControllerName($controllerName);
        if ($className)
        {
            try
            {
                // if this fails, an exception will be thrown and
                // caught below, indicating that the class can't
                // be loaded.
                Zend::loadClass($className,
                           $dispatcher->getControllerDirectory());
                $actionName = $request->getActionName();
                if (empty($actionName)) {
                    $actionName = $dispatcher->getDefaultAction();
                }
                $methodName = $dispatcher
                                  ->formatActionName($actionName);
                
                $class = new ReflectionClass( $className );
                if( $class->hasMethod( $methodName ) )
                {
                    // all is well - exit now
                    return;
                }
            }
            catch (Zend_Exception $e)
            {
                // Couldn't load the class. No need to act yet,
                // just catch the exception and fall out of the
                // if
            }
        }
    
        // we only arrive here if can't find controller or action
        $request->setControllerName( 'noroute' );
        $request->setActionName( 'index' );
        $request->setDispatched( false );
    }
}</pre>

<p>Simply <a href="http://framework.zend.com/manual/en/zend.controller.plugins.html#zend.controller.plugins.using">register this plug-in</a> with the front controller and set-up the NorouteController class to display the error page. And remember to send a 404 error header from the noroute controller.</p>

<p>The plug-in doesn&#8217;t deal with modules &#8211; mainly because I don&#8217;t use modules and couldn&#8217;t decide whether the NorouteController class should be global or per-module. It shouldn&#8217;t be too hard to add module handling to the code.</p>

<h3>Zend Framework 0.9</h3>

<p>For version 0.9 of the framework you need to change <code>Zend::loadClass</code> to <code>Zend_Loader::loadClass</code>. With this change the plug-in works again as intended.</p>]]></content:encoded>
			<wfw:commentRss>http://www.richardlord.net/blog/managing-404-errors-in-the-zend-framework/feed</wfw:commentRss>
		<slash:comments>15</slash:comments>
		</item>
		<item>
		<title>Zend_View helpers in include path</title>
		<link>http://www.richardlord.net/blog/zend_view-helpers-in-include-path</link>
		<comments>http://www.richardlord.net/blog/zend_view-helpers-in-include-path#comments</comments>
		<pubDate>Thu, 08 Feb 2007 11:52:42 +0000</pubDate>
		<dc:creator>Richard</dc:creator>
				<category><![CDATA[All]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Zend Framework]]></category>

		<guid isPermaLink="false">http://www.bigroom.co.uk/blog/zend_view-helpers-in-include-path/</guid>
		<description><![CDATA[<p>I'm using the Zend Framework at the moment and came across a problem with creating custom helpers for the Zend_View class. All is fine if you place your helpers either within the zend framework's own helpers folder (not a good idea) or within a directory in your site structure. The problem arises if you place the helpers in a folder in the PHP include path and don't know the full path to the folder.</p>]]></description>
			<content:encoded><![CDATA[<p>N.B. This article applies to version 0.7 of the Zend Framework. The first solution suggested below is now incorporated in version 0.8 of the framework.</p>

<h3>The Problem</h3>

<p>I&#8217;m using the <a href="http://framework.zend.com/">Zend Framework</a> at the moment and came across a problem with creating <a href="http://framework.zend.com/manual/en/zend.view.helpers.html">custom helpers</a> for the Zend_View class. All is fine if you place your helpers either within the zend framework&#8217;s own helpers folder (not a good idea) or within a directory in your site structure. The problem arises if you place the helpers in a folder in the PHP include path and don&#8217;t know the full path to the folder.</p>

<p>Why would that happen? Well, here&#8217;s my set-up &#8211; on each server I have a folder that is added to the include path. This folder has the same structure on all my servers &#8211; development, testing and production &#8211; but may be in a different location on some of them. That doesn&#8217;t matter because I can add the correct folder to PHP&#8217;s include path in the php.ini configuration file on each server.</p>

<p>In the include folder I place a number of common files, including the Zend framework itself and my custom files for use with the framework. To keep things simple I duplicate the structure of the Zend Framework library files within my own custom files, as recommended in the Zend Framework documentation. My own files are placed within a fiolder called Bigroom, just as the Zend files are placed within a folder called Zend.</p>

<p>So, my Zend_View helpers are in the folder at Bigroom/View/Helper within the include path. The helpers are all named accordingly too, e.g. Bigroom_View_Helper_SelectCountry for a select box listing all countries. So far so good and in keeping with the recommendations in the framework documentation.</p>

<p>However, to add my helpers to the set of helpers in the Zend Framework, I have to know the full path to the helpers, not the path relative to the PHP include path, and not just the class name. This is not a bug, it&#8217;s how the helpers part of the framework is designed. It&#8217;s just a bit odd when compared to the rest of the framework. The code to add the helper directory to the helpers might look like this on my production and test servers -</p>

<pre class="code">$view = new Zend_View();
$view->addHelperPath( '/home/web/phpincludes/Bigroom/View/Helper',
                      'Bigroom_View_Helper' );</pre>

<p>But on my development system, which is windows based, it would look like this -</p>

<pre class="code">$view = new Zend_View();
$view->addHelperPath( 'C:\php\includes\Bigroom\View\Helper',
                      'Bigroom_View_Helper' );</pre>

<p>This seems to break with the normal behaviour of the Zend Framework, in which classes are automatically found from within the include path based on their class name. It also makes it difficult to create portable code since one must ensure that the include path is exactly the same on all systems using the code.</p>

<p>I have two solutions to this. The first involves altering the code in the Zend Framework, while the second, my preferred option, does not.</p>

<h3>Solution 1</h3>

<p>In the first solution, we make two small modifications to the Zend_View_Abstract class.</p>

<p>First, in the _loadClass method replace the line</p>

<pre class="code">} elseif (is_readable($dir . $file)) {</pre>

<p>with</p>

<pre class="code">} elseif (Zend::_isReadable($dir . $file)) {</pre>

<p>If you do all your work on the same platform, this will suffice. But for cross platform use we also need to check that the directory separators are the same. So the second change is in method _addPath where you need to add the statement</p>

<pre class="code">$dir = str_replace( array('/', '\\'), DIRECTORY_SEPARATOR, $dir );</pre>

<p>after</p>

<pre class="code">$dir = rtrim($dir, '\\/' . DIRECTORY_SEPARATOR) 
                . DIRECTORY_SEPARATOR;</pre>

<p>Now you can add helper paths using a path relative to the include path and with either / or \ as the directory separator. So portable code to add my helpers becomes</p>

<pre class="code">$view = new Zend_View();
$view->addHelperPath( 'Bigroom/View/Helper',
                      'Bigroom_View_Helper' );</pre>

<p>There are, however, two drawbacks to this approach. First it involves modifying the Zend framework itself. That&#8217;s not a good idea since you have to remember to redo the modifications when upgrading to a new version of the framework. And secondly, Zend::isReadable is significantly slower than is_readable, and here it&#8217;s being used every time you use a helper. The speed hit probably won&#8217;t be significant but it would be nice to avoid it.</p>

<h3>Solution 2</h3>

<p>My second solution to the problem is to extent the Zend_View class with my own Bigroom_View class that implements a new function for adding helper paths based on the class prefix only and looks for the files within the include path. This is in keeping with the normal operation of the Zend Framework where a class name is all that&#8217;s needed to find that class within the include paths.</p>

<p>Here&#8217;s the code</p>

<pre class="code">require_once 'Zend/View.php';

class Bigroom_View extends Zend_View
{
    public function addHelperPrefix( $classPrefix )
    {
        $path = DIRECTORY_SEPARATOR
              . str_replace('_', DIRECTORY_SEPARATOR, $classPrefix);
        $dirs = explode( PATH_SEPARATOR, get_include_path() );
        foreach( $dirs as $dir )
        {
            $fullpath = $dir . $path;
            if( is_readable( $fullpath ) )
            {
                $this->addHelperPath( $fullpath, $classPrefix );
            }
        }
    }
}</pre>

<p>Now I use Bigroom_View instead of Zend_View and add helpers as follows.</p>

<pre class="code">$view = new Bigroom_View();
$view->addHelperPrefix( 'Bigroom_View_Helper' );</pre>

<p>Which seems a lot neater to me.</p>

]]></content:encoded>
			<wfw:commentRss>http://www.richardlord.net/blog/zend_view-helpers-in-include-path/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Why I like the Zend Framework</title>
		<link>http://www.richardlord.net/blog/why-i-like-the-zend-framework</link>
		<comments>http://www.richardlord.net/blog/why-i-like-the-zend-framework#comments</comments>
		<pubDate>Tue, 06 Feb 2007 12:23:26 +0000</pubDate>
		<dc:creator>Richard</dc:creator>
				<category><![CDATA[All]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Zend Framework]]></category>

		<guid isPermaLink="false">http://www.bigroom.co.uk/blog/why-i-like-the-zend-framework/</guid>
		<description><![CDATA[<p>I've been researching the <a href="http://framework.zend.com/">Zend Framework</a> for PHP in relation to a project I'm working on and I have to say I'm now a fan of it. There's lots to like about it, and some to dislike about it too...</p>]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been researching the <a href="http://framework.zend.com/">Zend Framework</a> for PHP in relation to a project I&#8217;m working on and I have to say I&#8217;m now a fan of it. There&#8217;s lots to like about it, and some to dislike about it too. But to me the best aspect of it is the flexibility it offers. Unlike some frameworks, you don&#8217;t have to use the complete package. Instead you can pick and choose which bits to use and plug it together with your own classes to get a complete product that meets your particular needs.</p>

<p>For myself, I&#8217;m using the controller and view aspects of the framework with a few minor additions of my own. Alongside this I&#8217;m using the model set-up that I&#8217;ve evolved over a number of projects, with the addition of a few components from the Zend_Framework. Slotting the framework into my current workflow has proven remarkably easy.</p>

<p>If I was to make one complaint it would be about the documentation. It has some gaps in it at the moment but it&#8217;s early days yet. Much of the detail I&#8217;ve discovered has been by inspecting the source code, but the code itself is clearly structured and well commented so it&#8217;s relatively easy to rummage through and find what you&#8217;re looking for.</p>

<p>If you&#8217;re looking for a PHP framework it&#8217;s worth checking out more than one since they all have different advantages and disadvantages. Here&#8217;s a short list to consider.</p>

<ul>
<li><a href="http://framework.zend.com/">Zend Framework</a></li>
<li><a href="http://cakephp.org/">CakePHP</a></li>
<li><a href="http://www.symfony-project.com/">Symphony</a></li>
<li><a href="http://solarphp.com/">Solar</a></li>
</ul>]]></content:encoded>
			<wfw:commentRss>http://www.richardlord.net/blog/why-i-like-the-zend-framework/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>PHP mail() function and GMail</title>
		<link>http://www.richardlord.net/blog/php-mail-and-gmail</link>
		<comments>http://www.richardlord.net/blog/php-mail-and-gmail#comments</comments>
		<pubDate>Fri, 01 Dec 2006 17:26:12 +0000</pubDate>
		<dc:creator>Richard</dc:creator>
				<category><![CDATA[All]]></category>
		<category><![CDATA[GMail]]></category>
		<category><![CDATA[Mail]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.bigroom.co.uk/blog/php-mail-and-gmail/</guid>
		<description><![CDATA[<p>or Another reason to avoid PHP's mail() function...</p>]]></description>
			<content:encoded><![CDATA[<p>or <strong>Another reason to avoid PHP&#8217;s mail() function</strong></p>

<p>Since launching <a href="http://www.giefan.com/">Giefan.com</a> on Monday we&#8217;ve fixed a few bugs that only came to light as a result of the way other people work. One such was an email problem with messages sent to GMail (thanks to Alan for catching this). I&#8217;ve never had a GMail account so it wasn&#8217;t one of the email applications we tested the messages with.</p>

<p>Email messages were arriving at GMail with messages garbled into a string of apparently random characters and with the sender listed as unknown. I was using <a href="http://php.net/manual/en/function.mb-send-mail.php">mb_send_mail()</a> to send UTF-8 email messages from PHP. I always intended to implement a different email solution at some point but evaluating the various possibilities and making a choice didn&#8217;t seem as important for the launch period as many of the other features so I chose to start with mb_send_mail() and switch to another solution later.</p>

<p>mb_send_mail() was sending messages as UTF-8 and base64 encoded, and it seems that GMail failed to correctly understand this from the email headers. As a result, GMail simply displayed the base64 encoded data. The quick fix just to get it working was to switch to PHP&#8217;s <a href="http://php.net/manual/en/ref.mail.php">mail()</a> function. This would suffice for a few hours while we sought a better solution.</p>

<p>The other problem was GMail displaying the sender as unknown, despite having the sender data in the From: header. I tried various different formats for the From: header (quotes around the name, extra spaces etc.) but none seemed to work for GMail. Instead, it always displayed the From: header line in the body of the message (there were no blank lines in the header so that&#8217;s not the problem, and the messages worked with a number of other email applications we tested them with).</p>

<p>I still haven&#8217;t discovered what the problem was but have three possibilities.</p>
<ol>
<li>Does GMail dislike the unconventional (but not technically wrong) ordering of the headers that mail() and mb_send_mail() produce?</li>
<li>Does GMail distrust messages in which the X-Mailer header lists &#8220;PHP mailer&#8221; as the system used and consequently displays the sender as unknown and places the from data in the message?</li>
<li>Is mail() doing something wrong in its headers, and most email applications are simply ignoring the mistake and figuring out what&#8217;s intended?</li>
</ol>
<p>If anyone knows the actual cause please add a comment below.</p>

<p>Anyway, the obvious solution was to avoid PHP&#8217;s mail functions altogether so I hurriedly added Chris Corbyn&#8217;s <a href="http://www.swiftmailer.org/">Swift Mailer</a> script and altered my code to use it, and all was well. I haven&#8217;t thoroughly tested Swift Mailer yet but it seems to be working fine &#8211; the messages are in UTF-8 and GMail is happy with them.</p>

<p>Swift Mailer is just one of <a href="http://phpmailer.sourceforge.net/">many</a> <a href="http://pear.php.net/package/Mail">alternatives</a> <a href="http://framework.zend.com/manual/en/zend.mail.html">to the</a> mail() function but I like it for it&#8217;s simplicity of use. Hopefully, when I test it out more thoroughly later this month I&#8217;ll still be very happy with it.</p>]]></content:encoded>
			<wfw:commentRss>http://www.richardlord.net/blog/php-mail-and-gmail/feed</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>PHP 5.2 &#8211; Nesting level too deep &#8211; recursive dependency?</title>
		<link>http://www.richardlord.net/blog/php-nesting-level-too-deep-recursive-dependency</link>
		<comments>http://www.richardlord.net/blog/php-nesting-level-too-deep-recursive-dependency#comments</comments>
		<pubDate>Mon, 13 Nov 2006 11:06:21 +0000</pubDate>
		<dc:creator>Richard</dc:creator>
				<category><![CDATA[All]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.bigroom.co.uk/blog/php-nesting-level-too-deep-recursive-dependency/</guid>
		<description><![CDATA[<p>I installed PHP 5.2 on my testing server today and a couple of bits of code that previously worked fine in version 5.1.6 threw fatal errors in the new version. The error message was "Nesting level too deep - recursive dependency?" and it took a little time to track down the root of the problem. Here's what happened...</p>]]></description>
			<content:encoded><![CDATA[<p>I installed PHP 5.2 on one of my testing servers today and a couple of bits of code that previously worked fine in version 5.1.6 threw fatal errors in the new version. The error message was &#8220;Nesting level too deep &#8211; recursive dependency?&#8221; and it took a little time to track down the root of the problem. Here&#8217;s what I&#8217;d done wrong.</p>

<p>In PHP there are <a href="http://php.net/manual/en/language.operators.comparison.php">two comparison operators</a>, <code>==</code> and <code>===</code>. It&#8217;s generally known that the first is not strict about type but the second is. So, for example</p>

<pre class="code">echo ( false == 0 ); // true
echo ( false === 0 ); // false
    - 0 is an integer and false is a boolean</pre>

<p>My problem arose from using non-strict typing with objects.</p>

<pre class="code">$a = new MyObj();
$b = new MyObj();
if( $a == $b )
...</pre>

<p>I hadn&#8217;t considered <a href="http://php.net/manual/en/language.oop5.object-comparison.php">what I was doing with this code</a>. When comparing two objects using the non-strict comparison operator (==) PHP compares all the properties of the objects and if they match the objects are deemed to be equal. If they don&#8217;t match they are not equal. In effect, we have a recursive comparison of all the properties of each object, and all their properties, etc. until we reach basic data types like strings and integers.</p>

<p>If, however, we use strict comparison (===), PHP will check whether the two objects are exactly the same object, not just objects with the same properties.</p>

<pre class="code">class MyObj
{
    public $p;
}

$a = new MyObj();
$b = new MyObj();
$c = new MyObj();
$a->p = 1;
$b->p = 1;
$c->p = 2;
echo ( $a == $c ); // false
echo ( $a == $b ); // true
echo ( $a === $b ); // false</pre>

<p>The problem arises if you have circular references in your objects properties. So, for example</p>

<pre class="code">class MyObj
{
    public $p;
}
class OtherObj
{
    public $q;
}

$a = new MyObj();
$b = new OtherObj();
$a->p = $b;
$b->q = $a; // the circular reference: $a->p->q === $a

$c = new MyObj();
$d = new OtherObj();
$c->p = $d;
$d->q = $c;// another circular reference: $c->p->q === $c

echo ( $a == $c ); // Fatal error:
    Nesting level too deep - recursive dependency?</pre>

<p>In order to compare $a to $c, PHP must compare their properties. So the logic in PHP goes something like this: <code>$a == $c if $a->p == $c->p if $a->p->q == $c->p->q if $a->p->q->p == $c->p->q->p</code> etc. indefinitely.</p>

<p>PHP 5.1 seemed to smooth over the problem somehow (probably after a certain level of recursion it simply returned false) &#8211; and usually it worked out fine. PHP 5.2 correctly produces the fatal error above.</p>

<p>Once you know the problem, the solution is easy &#8211; use strict comparison.</p>

<pre class="code">echo ( $a === $c ); // false (and no error)</pre>

<p>The strict comparison will simply check whether the two objects are at the same location in memory and so doesn&#8217;t even look at the values of the properties.</p>

<p>N.B. The same problem can arise when using the negated comparison operators (use <code>!==</code> instead of <code>!=</code>) and when using <code><a href="http://php.net/manual/en/function.in-array.php">in_array</a></code> (use <code>in_array</code>&#8216;s third parameter to indicate strict comparison).</p>]]></content:encoded>
			<wfw:commentRss>http://www.richardlord.net/blog/php-nesting-level-too-deep-recursive-dependency/feed</wfw:commentRss>
		<slash:comments>18</slash:comments>
		</item>
		<item>
		<title>Dates in PHP and MySQL</title>
		<link>http://www.richardlord.net/blog/dates-in-php-and-mysql</link>
		<comments>http://www.richardlord.net/blog/dates-in-php-and-mysql#comments</comments>
		<pubDate>Fri, 03 Nov 2006 10:18:09 +0000</pubDate>
		<dc:creator>Richard</dc:creator>
				<category><![CDATA[All]]></category>
		<category><![CDATA[Dates]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.bigroom.co.uk/blog/dates-in-php-and-mysql/</guid>
		<description><![CDATA[<p>I see a lot of people on forums and on my training courses asking about the best way (or any way) to manage dates stored in a MySQL database and used in PHP. Three options follow, but first the problem...</p>]]></description>
			<content:encoded><![CDATA[<p>I see a lot of people on forums and on my <a href="/about/training/">training courses</a> asking about the best way (or any way) to manage dates stored in a MySQL database and used in PHP. Three options follow, but first the problem.</p>

<p>PHP uses unix timestamps for all its date functionality. It has methods to convert these timestamps into pretty much any text format you could want but internally it uses the timestamp format. A timestamp is simply an integer. Specifically, it&#8217;s the number of seconds that have elapsed since midnight on January 1st 1970 (greenwich mean time).</p>

<p>MySQL has <a href="http://dev.mysql.com/doc/refman/4.1/en/date-and-time-types.html">three date types</a> for use in columns. These are DATETIME, DATE, and TIMESTAMP. DATETIME columns store date and time as a string in the form YYYY-MM-DD HH:MM:SS (e.g. 2006-12-25 13:43:15). DATE columns use just the date part of this format &#8211; YYYY-MM-DD (e.g. 2006-12-25). TIMESTAMP columns, despite their name, are nothing like the unix timestamps used in PHP. A TIMESTAMP  column is simply a DATETIME column that automatically updates to the current time every time the contents of that record are altered. (That&#8217;s a simplification but broadly true and the details are not important here). In particular, since version 4.1 of MySQL the TIMESTAMP format is exactly the same as the DATETIME format.</p>

<p>So the problem is how to work with these two very different date formats &#8211; the PHP timestamp integer and the MySQL DATETIME string. There are three common solutions&#8230;</p>

<ol>
	<li><p>One common solution is to store the dates in DATETIME fields and use PHPs <code><a href="http://php.net/manual/en/function.date.php">date()</a></code> and <code><a href="http://php.net/manual/en/function.strtotime.php">strtotime()</a></code> functions to convert between PHP timestamps and MySQL DATETIMEs. The methods would be used as follows -</p>
<pre class="code">$mysqldate = date( 'Y-m-d H:i:s', $phpdate );
$phpdate = strtotime( $mysqldate );</pre></li>

	<li><p>Our second option is to let MySQL do the work. MySQL has functions we can use to convert the data at the point where we access the database. <code><a href="http://dev.mysql.com/doc/refman/4.1/en/date-and-time-functions.html#id3239270">UNIX_TIMESTAMP</a></code> will convert from DATETIME to PHP timestamp and <code><a href="http://dev.mysql.com/doc/refman/4.1/en/date-and-time-functions.html#id3236302">FROM_UNIXTIME</a></code> will convert from PHP timestamp to DATETIME. The methods are used within the SQL query. So we insert and update dates using queries like this -</p>
<pre class="code">$query = "UPDATE table SET
    datetimefield = FROM_UNIXTIME($phpdate)
    WHERE...";
$query = "SELECT UNIX_TIMESTAMP(datetimefield)
    FROM table WHERE...";</pre></li>

	<li><p>Our last option is simply to use the PHP timestamp format everywhere. Since a PHP timestamp is a signed integer, use an integer field in MySQL to store the timestamp in. This way there&#8217;s no conversion and we can just move PHP timestamps into and out of the database without any issues at all.</p>
<p>Be aware, however, that by using an integer field to store your dates you lose a lot of functionality within MySQL because MySQL doesn&#8217;t know that your dates are dates. You can still sort records on your date fields since php timestamps increase regularly over time, but if you want to use any of MySQL&#8217;s date and time functions on the data then you&#8217;ll need to use FROM_UNIXTIME to get a MySQL DATETIME for the function to work on.</p>
<p>However, if you&#8217;re just using the database to store the date information and any manipulation of it will take place in PHP then there&#8217;s no problems.</p></li>
</ol>

<p>So finally we come to the choice of which to use. For me, if you don&#8217;t need to manipulate the dates within MySQL then there&#8217;s no contest and the last option is the best. It&#8217;s simple to use and is the most efficient in terms of storage space in the data table and speed of execution when reading and writing the data.</p>

<p>However, some queries will be more complicated because your date is not in a date field (e.g. select all users who&#8217;s birthday is today) and you may lose out in the long run. If this is the case it may be better to use either option 1 or 2. Which of these you use depends on whether you&#8217;d rather place the work on MySQL or PHP. I tend to use option 2 but there&#8217;s no right or wrong answer &#8211; take your pick.</p>

<p>So to summarise, for those who&#8217;ve skipped straight to the last paragraph, most of the time I use option 3 but occasionally I use option 2 because I need MySQL to know the field contains a date.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.richardlord.net/blog/dates-in-php-and-mysql/feed</wfw:commentRss>
		<slash:comments>63</slash:comments>
		</item>
		<item>
		<title>Search PHP &amp; MySQL documentation from Firefox 2 search box</title>
		<link>http://www.richardlord.net/blog/search-php-mysql-docs-from-firefox2</link>
		<comments>http://www.richardlord.net/blog/search-php-mysql-docs-from-firefox2#comments</comments>
		<pubDate>Thu, 26 Oct 2006 23:34:54 +0000</pubDate>
		<dc:creator>Richard</dc:creator>
				<category><![CDATA[All]]></category>
		<category><![CDATA[Browser search]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.bigroom.co.uk/blog/search-php-mysql-docs-from-firefox2/</guid>
		<description><![CDATA[<p>Firefox 2.0 is now available and it transpires that the search provider functionality uses the same OpenSearch specification as IE7. That means the custom search providers I created for IE7 also work with Firefox2, so here they are again...</p>]]></description>
			<content:encoded><![CDATA[<p>Firefox 2 is <a href="http://www.mozilla.com/">now available</a> and it transpires that the search provider functionality uses the same <a href="http://www.opensearch.org/Specifications/OpenSearch/1.1">OpenSearch specification</a> as IE7.</p> 

<p>That means the custom search providers I created for IE7 also work with Firefox2, so here they are again. They provide searching of the on-line documentation for PHP and MySQL. If you&#8217;re using Firefox2 (or IE7) just click the appropriate links to add the search functionality you want.</p>

<p><b>PHP.net website searches</b></p>
<ul>
<li><a href="#" onclick="window.external.AddSearchProvider('http://www.bigroom.co.uk/search/phpfuncsearch.xml');">PHP Online Function List search</a></li>
<li><a href="#" onclick="window.external.AddSearchProvider('http://www.bigroom.co.uk/search/phpdocsearch.xml');">PHP Online Documentation search</a></li>
<li><a href="#" onclick="window.external.AddSearchProvider('http://www.bigroom.co.uk/search/phpsitesearch.xml');">PHP.net full website search</a></li>
</ul>

<p><b>MySQL.org website searches</b></p>
<ul>
<li><a href="#" onclick="window.external.AddSearchProvider('http://www.bigroom.co.uk/search/mysql4docsearch.xml');">MySQL versions up to 4.1 Documentation search</a></li>
<li><a href="#" onclick="window.external.AddSearchProvider('http://www.bigroom.co.uk/search/mysql5docsearch.xml');">MySQL version 5.0 Documentation search</a></li>
<li><a href="#" onclick="window.external.AddSearchProvider('http://www.bigroom.co.uk/search/mysql51docsearch.xml');">MySQL version 5.1 Documentation search</a></li>
<li><a href="#" onclick="window.external.AddSearchProvider('http://www.bigroom.co.uk/search/mysqlsitesearch.xml');">MySQL.com full website search</a></li>
</ul>]]></content:encoded>
			<wfw:commentRss>http://www.richardlord.net/blog/search-php-mysql-docs-from-firefox2/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

