Common Lisp

So I've just downloaded the book Practical Common Lisp from Apress. Over the past few months I have been thinking of learning a new programming language. My first choice was C++, then I decided on Java because I took an introductory course to it last semester. Java and C++ share a lot of syntax commonalities with PHP and Javascript/Actionscript so learning them just didn't feel interesting. My other idea was to learn Python, for no real reason beside the fact that it seemed cool. For some reason I never got around to that...

» read the rest of this entry.

Sending emails with PHP’s sockets and SMTP

As a continuation on releasing more of OneLobby's code, here is a useful set of classes that I made for sending emails. Normally one would use PHP's mail function, but everytime you call that function it opens and closes a socket. If you want to send out large amounts of email, this process can be very inefficient. That's where these classes come in handy...

	<?php

	/*
	OneLobby SendMail class and related supporting classes
	Copyright (C) 2007 Peter Goodman

	This program is free software; you can redistribute it and/or
	modify it under the terms of the GNU General Public License
	as published by the Free Software Foundation; either version 2
	of the License, or (at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
	*/

	//--------------------------------------------
	// A class to deal with creating and sending mail.
	// Works with the normal mail method and also SMTP.
	//--------------------------------------------

	class SendMail
	{	
		function &getFinder($type = 'PHP')
		{
			$class = $type .'_MailMessage';
			$ret = NULL;

			if(class_exists($class))
			{
				$ret = &new $class();
			}

			return $ret;
		}
	}

	class MailMessage 
	{
		var $_headers = array();

		var $_message = "";
		var $_subject = "";

		var $_as_html = FALSE;

		var $_bcc = array();
		var $_to;
		var $_from;

		//--------------------------------------------
		// Constructor, set some headers.
		//--------------------------------------------

		function MailMessage()
		{
			$this->_headers[] = "X-Priority: 3";
			$this->_headers[] = "X-Mailer: OneLobby Mailer";
			$this->_headers[] = "Content-Transfer-Encoding: 8bit";
			$this->_headers[] = "Date: ". date("r", time());
			$this->_headers[] = "Content-Transfer-Encoding: quoted-printable";
		}

		//--------------------------------------------
		// Set this message type to be plain text.
		//--------------------------------------------

		function asPlainText()
		{
			$this->_headers[] = "Content-Type: text/plain; charset=UTF-8";
		}

		//--------------------------------------------
		// Set this message type to be HTML
		//--------------------------------------------

		function asHTML()
		{
			$this->_headers[] = "MIME-Version: 1.0";
			$this->_headers[] = "Content-Type: text/html; charset=UTF-8";
			$this->_as_html = TRUE;
		}

		//--------------------------------------------
		// Set who this message is from.
		//--------------------------------------------

		function setFrom($email, $name = FALSE)
		{
			if(!$name)
			{
				$name = "OneLobby Mailer";
			}

			$email = $this->_cleanString($email);
			$name = $this->_cleanString($name);

			$this->_from = $email;

			$this->_headers[] = "Return-Path: <{$email}>";
			$this->_headers[] = "From: \"{$name}\" <{$email}>";
			$this->_headers[] = "Message-Id: <". md5(uniqid(rand())) .".". preg_replace("~[^a-z0-9]~i", "", $name) ."@". $this->_smpt_server .">";
		}

		//--------------------------------------------
		// Set who this message is to. This can either be
		// an array of people or a single email address.
		//--------------------------------------------

		function setTo($email, $name = FALSE)
		{	
			$email = $this->_cleanString($email);

			if($name)
			{
				$name = $this->_cleanString($name);
				$to = "To: \"{$name}\" <{$email}>";
			}
			else
			{
				$to = "To: {$email}";
			}

			$this->_to = $email;
			$this->_headers[] = $to;
		}

		//--------------------------------------------
		// Set the Bcc's (Blind Carbon Copy) for this email
		//--------------------------------------------

		function setBCC($emails)
		{
			$this->_bcc = $emails;
		}

		//--------------------------------------------
		// Set the subject of the mail.
		//--------------------------------------------

		function setSubject($subject)
		{
			$subject = $this->_cleanString($subject);

			$this->_subject = $subject;

			$this->_headers[] = "Subject: {$subject}";
		}

		//--------------------------------------------
		// Set the message of the mail.
		//--------------------------------------------

		function setMessage($message)
		{	
			$this->_message = $message;
		}

		//--------------------------------------------
		// Build the headers.
		//--------------------------------------------

		function &buildHeaders()
		{
			$ret = "";

			foreach($this->_headers as $header)
			{
				$ret .= $header ."\n";
			}

			return $ret;
		}

		//--------------------------------------------
		// Build the email.
		//--------------------------------------------

		function &buildMessage()
		{
			$length = !$this->_as_html ? 68 : 62;
			$break = !$this->_as_html ? "\n" : "<br />\n";

			$message = $this->_cleanMessage($this->_message);
			$message = $this->_wordWrap($message, $length, $break);

			//--------------------------------------------
			// If we're sending from windows, this is some
			// sort of known bug..
			//--------------------------------------------

			if(isset($_SERVER['SERVER_NAME']))
			{
				if(preg_match("~Win32~i", $_SERVER['SERVER_NAME']))
				{
					$message = str_replace("\n.", "\n..", $message);
				}
			}

			return $message ."\n";
		}

		//--------------------------------------------
		// Clean a string.
		//--------------------------------------------

		function _cleanString($str)
		{
			$str = preg_replace("~[ \r\n\t]~", " ", $str);
			$str = preg_replace("~,,~", ",", $str);
			$str = preg_replace("~\#\[\]'\"\(\):;/\$!£%\^&\*\{\}~", "", $str);
			return $str;
		}

		//--------------------------------------------
		// Clean a message.
		//--------------------------------------------

		function _cleanMessage($msg)
		{
			$msg = preg_replace("~(\r\n|\r|\n)~", "\n", $msg);
			$msg = preg_replace("~,,~", ",", $msg);

			if(!$this->_as_html)
			{
				$msg = strip_tags($msg);
				$msg = html_entity_decode($msg, ENT_QUOTES);
			}

			$msg = trim($msg);

			return $msg;
		}

		//--------------------------------------------
		// Word wrap function, care of the PHP Manual comments,
		// thank's Paolo Stefan.
		//--------------------------------------------

		function _wordWrap($text, $size, $separator)
		{
			$new_text = '';
			$text_1 = explode('>',$text);
			$sizeof = sizeof($text_1);
			$remain = $size;

			for ($i = 0; $i < $sizeof; ++$i) 
			{
				$text_2 = explode('<',$text_1[$i]);

				if (!empty($text_2[0])) 
				{
					$perl = '/([^\\n\\r .]{'. $remain .',})/i';
					$possibly_splitted= preg_replace( $perl, '$1'.$separator, $text_2[0] );

					$splitted = explode($separator,$possibly_splitted);
					$remain -= strlen_utf($splitted[0]);
					if($remain<=0) 
					{
						$remain = $size;
					}

					$new_text .= $possibly_splitted;
				}

				if (!empty($text_2[1])) 
				{
					$new_text .= '<' . $text_2[1] . '>';
				}
			}
			return $new_text;
		}

		function sendMessage()
		{
			assert(FALSE);
		}
	}

	class PHP_MailMessage extends MailMessage
	{
		function sendMessage()
		{
			$headers = &$this->buildHeaders();
			$message = &$this->buildMessage();
			$from = &$this->_from;
			$to = &$this->_to;
			$subject = &$this->_subject;

			//--------------------------------------------
			// Deal with bcc's
			//--------------------------------------------
			$bcc = "";
			foreach($this->_bcc as $email)
			{
				if(preg_match("~[^ ]+\@[^ ]+~", $email))
				{
					$bcc .= " <$email>";
					$sep = ",";
				}
			}

			if($bcc != "")
			{
				$this->_headers[] = "Bcc: ". $bcc;
			}

			//--------------------------------------------
			// If we're using PHP's built in mail function.
			//--------------------------------------------
			if (!@mail( $to, $subject, $message, $headers))
			{
				trigger_error("Could not send the mail with mail().");
			}
		}
	}

	class SMTP_MailMessage extends MailMessage
	{
		function sendMessage()
		{
			$headers = &$this->buildHeaders();
			$message = &$this->buildMessage();
			$from = &$this->_from;
			$to = &$this->_to;
			$subject = &$this->_subject;

			//--------------------------------------------
			// If we're sending with SMTP..
			//--------------------------------------------

			//--------------------------------------------
			// Set who this mail is from.
			//--------------------------------------------

			if($this->socketCommand("MAIL FROM: <". $from .">") != 250)
			{
				trigger_error("Could not set who this mail is from.", E_USER_ERROR);
			}

			//--------------------------------------------
			// Get the array of who this message is to.
			//--------------------------------------------

			$bcc = $this->_message->getBcc();
			$bcc[] = $to;

			//--------------------------------------------
			// Loop over who this message is to and set them as
			// a receiver of the message.
			//--------------------------------------------

			foreach($this->_bcc as $email)
			{
				if(preg_match("~[^ ]+\@[^ ]+~", $email))
				{
					if($this->socketCommand("RCPT TO: <". $email .">") != 250)
					{
						trigger_error("Could not send email to: $email", E_USER_ERROR);
						return;
					}
				}
			}

			//--------------------------------------------
			// Let's start to put the data of the message in.
			//--------------------------------------------

			if($this->socketCommand("DATA") != 354)
			{
				trigger_error("Could not set data.", E_USER_ERROR);
			}

			//--------------------------------------------
			// Add the message data in.
			//--------------------------------------------

			$data = $headers ."\n\n". $message;

			//--------------------------------------------
			// First replace all \n's with CR/LF then replace
			// \n.\r\n with \n. \r\n because the next socket
			// command after this is <CRLF>.<CRLF>

			//--------------------------------------------

			$data = preg_replace("~(?<!\r)\n~is", "\r\n", $data);
			$data = str_replace("\n.\r\n", "\n. \r\n", $data );

			fputs($this->_smtp_fp, $data);

			//--------------------------------------------
			// We've put all the message input in. We're done.
			//--------------------------------------------

			if($this->socketCommand("\r\n.") != 250)
			{
				trigger_error("Could not finish data input.", E_USER_ERROR);
			}

			//--------------------------------------------
			// Close the socket.
			//--------------------------------------------

			$this->smtpClose();
		}

		//--------------------------------------------
		// Connect to a SMTP server
		//--------------------------------------------

		function smtpConnect($host = "localhost", $port = 25, $user = FALSE, $pass = FALSE)
		{
			$this->_smtp_fp = fsockopen($host, $port, $error_no, $error_str, 30);

			if(!$this->_smtp_fp)
			{
				break;
			}

			$this->_smtp = TRUE;

			//--------------------------------------------
			// If we have a user and pass, try to log in to
			// the SMTP server.
			//--------------------------------------------

			if($user && $pass)
			{
				//--------------------------------------------
				// Try to identify us as the sender.
				//--------------------------------------------

				if($this->socketCommand("EHLO ". $host) != 250)
				{
					trigger_error("Could not identify as the sender.");
				}

				if($this->socketCommand("AUTH LOGIN") == 334)
				{
					//--------------------------------------------
					// Make sure the username is good.
					//--------------------------------------------

					if($this->socketCommand(base64_encode($user)) != 334)
					{
						trigger_error("Invalid SMTP username.");
					}

					//--------------------------------------------
					// Make sure the password is good.
					//--------------------------------------------

					if($this->socketCommand(base64_encode($pass)) != 334)
					{
						trigger_error("Invalid SMTP password.");
					}
				}
			}
			else
			{
				//--------------------------------------------
				// Try to identify us as the sender.
				//--------------------------------------------

				if($this->socketCommand("HELO ". $host) != 250)
				{
					trigger_error("Could not identify as the sender.");
				}
			}
		}

		//--------------------------------------------
		// Disconnect from the SMTP server.
		//--------------------------------------------

		function smtpDisconnect()
		{
			if($this->_smtp)
			{
				$this->socketCommand("QUIT");

				fclose($this->_smtp_fp);
			}
		}

		//--------------------------------------------
		// Send a command to the socket and return the
		// SMTP code.
		//--------------------------------------------

		function socketCommand($command)
		{
			fputs($this->_smtp_fp, $command ."\r\n");

			$this->socketGetReturnInfo();

			return $this->_smtp_code;
		}

		//--------------------------------------------
		// Parse the info of the last command, get the code
		// and the message.
		//--------------------------------------------

		function socketGetReturnInfo()
		{
			$this->_smtp_code = FALSE;
			$this->_smtp_msg = "";

			while($line = fgets($this->_smtp_fp, 515))
			{
				$this->_smtp_msg .= $line;

				if($line{4} == " ")
				{
					break;
				}
			}

			$this->_smtp_code = substr_utf($this->_smtp_msg, 0, 3);
		}
	}

	?>
	

Hope they come in handy!

Not Everything is AJAX

AJAX (Asynchronous Javascript and XML) as been around now long enough that people should be able to recognize when some is and isn't AJAX. In fact, a lot of AJAX isn't even AJAX! A lot of the time it's AJAH (... HTML) and AJAJ (... JSON (Javascript Object Notation)) but that's just me being critical.

So what is AJAX anyway? AJAX is when one uses a great little Javascript object called XMLHttpRequest (this now exists in IE7) to connect to the server behind the scenes to get some sort of information. That's it. Technically speaking, everything following (formatting, sexy effects, etc) just IS NOT AJAX. That stuff fits nicely into the ambiguous Web 2.0 label.

So what's Web 2.0? Oh jeez. Go look Google it, the top four results are enlightening. So to finish off this rant, not everything is AJAX. Most of the time, things are plain and sexy DHTML (Dynamic HTML).

Working with PHP Sockets and cURL

I was recently asked to release OneLobby's source code. It's an unfinished product but I think it would be a good idea. However, before I do that I'm going to showcase some of the useful classes I made for it. Four of these classes happen to be interfaces for dealing with PHP's socket and cURL functions. Take a look...

<?php

/*
OneLobby
Copyright (C) 2007 Peter Goodman, Geoffrey Goodman

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/

//-------------------------------------------------
// The user Agent and version of this OneLobby remote
// XML caller.
//-------------------------------------------------

define ('REMOTE_XML_USERAGENT''OneLobby [RemoteXML v.1.0]');

//-------------------------------------------------
// Out little extension class.. it's not really needed,
// but it's convenient to choose REST or RPC.
//-------------------------------------------------

class RemoteXML extends FAExtension
{
    function 
RemoteXML()
    {
        
// moo :P
    
}
    
    function &
getFinder($type 'REST')
    {
        
$class $type .'_Request';
        
$ret NULL;
        
        if(
class_exists($class))
        {
            
$ret = &new $class();
        }
        
        return 
$ret;
    }
}

//-------------------------------------------------
// Base wrapper class for REST and RPC calls. Deal with
// opening connections using sockets or cURL, sending
// and receiving data, etc.
//-------------------------------------------------

class RemoteXMLRequest
{
    
//-------------------------------------------------
    // Some variables related to RPC and REST requests.
    //-------------------------------------------------
    
    
var $_initial_request FALSE;
    var 
$_initial_put FALSE;
    
    
//-------------------------------------------------
    // Get a cURL or Socket connection.
    //-------------------------------------------------
    
    
function &getConnection()
    {
        
//-------------------------------------------------
        // If the cURL extension isn't loaded, try to load
        // it. The PHP_SHLIB_SUFFIX is for checking if we are
        // on Windows or UNIX.
        //-------------------------------------------------

        
if(!extension_loaded('curl'))
        {
            
$prefix = (PHP_SHLIB_SUFFIX === 'dll') ? 'php_' '';
            @
dl($prefix 'curl.'PHP_SHLIB_SUFFIX);
        }
        
        if(
function_exists('curl_init'))
        {
            
$conn = &new cURL_Connection;
        }
        else
        {
            
$conn = &new Socket_Connection;
        }
        
        return 
$conn;
    }
    
    
//-------------------------------------------------
    // Interface methods...
    //-------------------------------------------------
    
    
function getInfo($url)
    {
        
assert(FALSE);
    }
    
    function 
putInfo($url$xml)
    {
        
assert(FALSE);
    }
}

//-------------------------------------------------
// Deal with REST (representational state transfers)
// requests.
//-------------------------------------------------

class REST_Request extends RemoteXMLRequest
{
    
//-------------------------------------------------
    // Do the initial request of data for this REST session.
    //-------------------------------------------------
    
    
function getInfo($url)
    {    
        
//-------------------------------------------------
        // Get out socket/cURL connection and make the request.
        //-------------------------------------------------
        
        
$conn = &$this->getConnection();
        
$conn->createRequest('GET'$url);
        
$data $conn->getReturnData();
        
$conn->closeRequest();
        
        
$this->_initial_request TRUE;
        
        return 
$data;
    }
    
    
//-------------------------------------------------
    // Put info to the server.
    //-------------------------------------------------
    
    
function putInfo($url$xml)
    {
        
//-------------------------------------------------
        // Make sure we're doing things the REST way.
        //-------------------------------------------------
        
        
if(!$this->_initial_request)
        {
            
trigger_error("[ERROR] This is a REST application, not RPC.");
        }
        
        
//-------------------------------------------------
        // Use a socket connection for this for the sake of
        // simplicity.
        //-------------------------------------------------
        
        
$conn = &new Socket_Connection;
        
        
$conn->createRequest('PUT'$url);
        
$conn->setPutData($xml);
        
$data $conn->getReturnData();
        
$conn->closeRequest();
        
        return 
$data;
    }
}

//-------------------------------------------------
// Deal with RPC (remote procedure call)
// requests.
//-------------------------------------------------

class RPC_Request extends RemoteXMLRequest
{    
    
//-------------------------------------------------
    // Put info to the server.
    //-------------------------------------------------
    
    
function putInfo($url$xml)
    {    
        
//-------------------------------------------------
        // Use a socket connection for this for the sake of
        // simplicity.
        //-------------------------------------------------
        
        
$conn = &new Socket_Connection;
        
        
$conn->createRequest('PUT'$url);
        
$conn->setPutData($xml);
        
$data $conn->getReturnData();
        
$conn->closeRequest();
        
        
$this->_initial_put TRUE;
        
        return 
$data;
    }
    
    
//-------------------------------------------------
    // Get the information after out inital PUT
    //-------------------------------------------------
    
    
function getInfo($url)
    {    
        
//-------------------------------------------------
        // Make sure we're doing things the RPC way.
        //-------------------------------------------------
        
        
if(!$this->_initial_put)
        {
            
trigger_error("[ERROR] This is a REST application, not RPC."E_USER_ERROR);
        }
        
        
//-------------------------------------------------
        // Get out socket/cURL connection and make the request.
        //-------------------------------------------------
        
        
$conn = &$this->getConnection();
        
$conn->createRequest('GET'$url);
        
$data $conn->getReturnData();
        
$conn->closeRequest();
        
        return 
$data;
    }
}

//-------------------------------------------------
// Interface for cURL and socket connections.
//-------------------------------------------------

class RemoteXMLConnection
{
    var 
$_conn;
    var 
$_conn_closed FALSE;
    
    
//-------------------------------------------------
    // Some nice variables
    //-------------------------------------------------
    
    
var $_scheme;
    var 
$_server;
    var 
$_path;
    var 
$_port 80;
    var 
$_timeout 5;
    
    var 
$_put FALSE;
    var 
$_head FALSE;
    
    function 
createRequest($type 'GET'$server ''$path '/'$port 80)
    {
        
assert(FALSE);
    }
    
    function 
closeRequest()
    {
        
assert(FALSE);
    }
    
    function 
getReturnData()
    {
        
assert(FALSE);
    }
    
    function 
setFile($file_name)
    {
        
assert(FALSE);
    }
    
    function 
errorNo()
    {
        
assert(FALSE);
    }
    
    function 
showAnyErrors()
    {
        
assert(FALSE);
    }
    
    function 
setXMLData(&$data)
    {
        if(!
is_a($data'RemoteXMLDocument'))
        {
            
trigger_error("[ERROR] The data must be an instance of the RemoteXMLDocument object.");
        }
    }
    
    function 
_parseUrl($url)
    {
        
//-------------------------------------------------
        // Parse the passed in URL.
        //-------------------------------------------------
        
        
$url parse_url($url);
        
        
$this->_scheme strtoupper($url['scheme']);
        
$this->_server $url['host'];
        
$this->_path = isset($url['path']) ? $url['path'] : '/';
        
$this->_port = isset($url['port']) ? $url['port'] : 80;
        
$this->_timeout = isset($url['fragment']) ? $url['fragment'] : 5;
    }
}

//-------------------------------------------------
// A cURL layer for doing what we need to do :D
//-------------------------------------------------

class cURL_Connection extends RemoteXMLConnection
{
    var 
$_called_exec FALSE;
    
    
//-------------------------------------------------
    // Create a request.
    //-------------------------------------------------
    
    
function createRequest($method 'GET'$url)
    {    
        
//-------------------------------------------------
        // Parse the url to get the connection data.
        //-------------------------------------------------
        
        
$this->_parseUrl($url);
        
        
//-------------------------------------------------
        // Check to see if the cURL extension is even enabled.
        //-------------------------------------------------
        
        
if(function_exists('curl_init'))
        {
            
//-------------------------------------------------
            // Start connecting and do stuff.
            //-------------------------------------------------
            
            
$this->_conn = &curl_init();
            
            
$this->showAnyErrors();
            
            
curl_setopt($this->_connCURLOPT_URL$this->_server $this->_path);
            
curl_setopt($this->_connCURLOPT_HTTP_VERSION1.0);
            
curl_setopt($this->_connCURLOPT_USERAGENTREMOTE_XML_USERAGENT);
            
            
$this->showAnyErrors();
            
            
//-------------------------------------------------
            // Figure out what connection method we are using.
            //-------------------------------------------------
            
            
$return_headers FALSE;
            
            if(
$method == 'GET')
            {
                
$method CURLOPT_HTTPGET;
            }
            else if(
$method == 'POST')
            {
                
$method CURLOPT_POST;
            }
            else if(
$method == 'HEAD')
            {
                
$method 'GET';
                
$return_headers TRUE;
            }
            else
            {
                
$method CURLOPT_PUT;
                
$this->_put TRUE;
            }
            
            
curl_setopt($this->_conn$method1);
            
            
//-------------------------------------------------
            // Should we display the headers?
            //-------------------------------------------------
            
            
curl_setopt($this->_connCURLOPT_HEADER$return_headers);
            
            
//-------------------------------------------------
            // If the request fails (error code > 400), fail silently.
            //-------------------------------------------------
            
            
curl_setopt($this->_connCURLOPT_FAILONERROR1);
            
            
//-------------------------------------------------
            // Follow header(Location: )'s, but only a max of 5
            // of them.
            //-------------------------------------------------
            
            
curl_setopt($this->_connCURLOPT_FOLLOWLOCATION1);
            
curl_setopt($this->_connCURLOPT_MAXREDIRS5);
            
            
//-------------------------------------------------
            // Make sure to close the request.
            //-------------------------------------------------

            
register_shutdown_function(array(&$this'closeRequest'));
        }
        else
        {
            
trigger_error("[ERROR] The cURL extension cannot be found.");
        }
    }
    
    
//-------------------------------------------------
    // Get the return data from the execution.
    //-------------------------------------------------
    
    
function getReturnData()
    {
        
curl_setopt($this->_connCURLOPT_RETURNTRANSFER1);
        
$data curl_exec($this->_conn);
        
        
$this->_called_exec TRUE;
        
        return 
$data;
    }
    
    
//-------------------------------------------------
    // Close the connection
    //-------------------------------------------------
    
    
function closeRequest()
    {
        if(!
$this->_conn_closed)
        {
            if(!
$this->_called_exec)
            {
                
curl_exec($this->_conn);
            }
        
            
curl_close($this->_conn);
        }
    }
    
    
//-------------------------------------------------
    // If we're using HTTP PUT, we need to 'put' a file to
    // their server, so, open up a file pointer to the local
    // file that we want to put and send it to their server.
    //-------------------------------------------------
    
    
function setFile($file_name)
    {
        if(
$this->_put)
        {
            
//-------------------------------------------------
            // Do some nice error checking..
            //-------------------------------------------------
            
            
if(!file_exists($file_name))
            {
                
trigger_error("[ERROR] File [$file_name] does not exist.");
            }
            
            if(!
is_readable($file_name))
            {
                
trigger_error("[ERROR] File [$file_name] cannot be read.");
            }
            
            
//-------------------------------------------------
            // Get and put the file.
            //-------------------------------------------------
            
            
$file_fp fopen($file_name"r");
            
$file_size filesize($file_name);
            
            
curl_setopt($this->_connCURLOPT_INFILE$file_fp);
            
curl_setopt($this->_connCURLOPT_INFILESIZE$file_size);
            
            
$this->showAnyErrors();
        }
    }
    
    
//--------------------------------------------
    // Send XML data through the curl session.
    //--------------------------------------------
    
    
function setPutData($xml)
    {
        if(
$this->_put)
        {
            
// TODO:{[Should I make this create a file only to pass it to cURL only to delete it after?[setPutData[cURL_Connection}
        
}
    }
    
    
//-------------------------------------------------
    // Return the last error code of the curl operation.
    //-------------------------------------------------
    
    
function errorNo()
    {
        return 
curl_errno($this->_conn);
    }
    
    
//-------------------------------------------------
    // If there are any errors, show them.
    //-------------------------------------------------
    
    
function showAnyErrors()
    {
        if(
$this->errorNo() > 0)
        {
            
trigger_error(curl_error($this->_conn), E_USER_ERROR);
        }
    }
}

//-------------------------------------------------
// Do everything that the above cURL stuff does, but
// manually with the socket.
//-------------------------------------------------

class Socket_Connection extends RemoteXMLConnection
{
    
//-------------------------------------------------
    // Open a socket to the url on the specified port.
    //-------------------------------------------------
    
    
function createRequest($method 'GET'$url)
    {
        
//-------------------------------------------------
        // Parse the url to get the connection data.
        //-------------------------------------------------
        
        
$this->_parseUrl();
        
        
//-------------------------------------------------
        // Connect...
        //-------------------------------------------------
        
        
$scheme $this->_scheme == 'HTTPS' 'ssl' $this->_scheme;
        
        
$this->_conn fsockopen($scheme .'://'$this->_server$this->_port$error_number$error_string$this->_timeout);
        
        
//-------------------------------------------------
        // Error check.
        //-------------------------------------------------
        
        
if(!$this->_conn)
        {
            
trigger_error("[ERROR] Could not open the socket."E_USER_ERROR);
        }
        
        
$data stream_get_meta_data($this->_conn);
        
        if(
$data['timed_out'])
        {
            
trigger_error("[ERROR] Socket times out."E_USER_ERROR);
        }
        
        
//-------------------------------------------------
        // Make sure it times out.
        //-------------------------------------------------
        
        
stream_set_timeout($this->_conn$this->_timeout);
        
stream_set_blocking($this->_connFALSE);
        
        
//-------------------------------------------------
        // Figure out what connection method we are using.
        //-------------------------------------------------
        
        
if($method == 'PUT')
        {
            
$this->_put TRUE;
        }
        else if(
$method == 'HEAD')
        {
            
$this->_head TRUE;
        }
        
        
//-------------------------------------------------
        // Set the headers.
        //-------------------------------------------------
        
        
if($this->_scheme == 'HTTPS')
        {
            
$this->_scheme 'HTTP';
        }
        
        if(
$this->_scheme != 'UDP')
        {
            
$this->_socketCommand("{$method} {$this->_path} {$this->_scheme}");
        }
        
        
$this->_socketCommand("Host: {$this->_server}");
        
$this->_socketCommand("User-Agent: "REMOTE_XML_USERAGENT);
        
$this->_socketCommand("X-Requested-With: "REMOTE_XML_USERAGENT);
        
$this->_socketCommand("Connection: Close");
        
$this->_socketCommand("");
        
        
//-------------------------------------------------
        // Make sure to close the request.
        //-------------------------------------------------
        
        
register_shutdown_function(array(&$this'closeRequest'));
    }
    
    
//-------------------------------------------------
    // Close the socket.
    //-------------------------------------------------
    
    
function closeRequest()
    {
        if(!
$this->_conn_closed)
        {
            
fclose($this->_conn);
            
$this->_conn_closed TRUE;
        }
    }
    
    
//-------------------------------------------------
    // Get the data that the socket returned.
    //-------------------------------------------------
    
    
function getReturnData()
    {
        
$data "";
        
        
$first_line TRUE;
        
$getting_headers TRUE;
        
        
//-------------------------------------------------
        // Loop through the data returned.
        //-------------------------------------------------
        
        
while(!feof($this->_conn))
        {
            
$line fgets($this->_conn4096);
            
            
//-------------------------------------------------
            // This is the first line, check for the 200 code 
            // (everything's a-okay)
            //-------------------------------------------------
            
            
if($first_line)
            {
                if(
strlen($line) != 0)
                {
                    
//-------------------------------------------------
                    // Did something go wrong?
                    //-------------------------------------------------
                    
                    
if(strstr($line" 200 ") === FALSE)
                    {
                        
trigger_error("[ERROR] An error occured. HTTP status code was not 200.");
                    }
                
                    
$first_line FALSE;
                    
                    
//-------------------------------------------------
                    // If we only want to get the headers, make them part
                    // of the data.
                    //-------------------------------------------------
                    
                    
if($this->_head)
                    {
                        
$data .= $line;
                    }
                }
            }
            
            
//-------------------------------------------------
            // If we're not getting headers anymore, add this line to the data.
            //-------------------------------------------------
            
            
if(!$getting_headers && !$this->_head)
            {
                
$data .= $line;
            }
            
            
//-------------------------------------------------
            // If we're still getting headers and this line is equal
            // to CR\LF, tell the script to start recording data for
            // the next loop.
            //-------------------------------------------------
            
            
if($getting_headers && $line == "\r\n")
            {
                
$getting_headers FALSE;
                
                
//-------------------------------------------------
                // So, we only want to return the headers.
                //-------------------------------------------------
                
                
if($this->_head)
                {
                    break;
                }
            }
        }
        
        return 
$data;
    }
    
    
//--------------------------------------------
    // Send data through the socket.
    //--------------------------------------------
    
    
function setPutData($xml)
    {
        if(
$this->_put)
        {
            
fputs($this->_conn$xmlstrlen($xml));
        }
    }
    
    
//--------------------------------------------
    // Send a command to the socket.
    //--------------------------------------------
    
    
function _socketCommand($command)
    {
        
$command $command ."\r\n";
        
fputs($this->_conn$commandstrlen($command));
    }
}

?>

Well, you should be able to figure out how to use them, they're pretty straightforward. Have fun with them!

Apple iPhone

Wow. Wowowowowowowowowow. This thing looks beyond cool. Wow. Go check it out for youself at apple.com/iphone.

I think I should write some more on it but it just wouldn't do the videos on the apple website justice. Wow!

Merry Christmas

Later today I will be on my way up to Mt. Tremblant so I won't be online. Just wanted to wish everyone a merry christmas!

Observers and Dispatchers Revisited

So I've had requests to do some more explaining on the observer and dispatcher patterns, and what better way to do that than to make code for an example!

Let's assume that we have a simple database abstraction layer. For the purpose of debugging, we want to be able to display information about each query at the end of the page. To make an effective debugging system we need to keep track of the query used, how many rows it affected, and how much time it took to execute. So, how could we do this? Well, we could store the information in a singleton (registry) but that is more of a hack than anything. So why not dispatch observable events to some observers?

» read the rest of this entry.

Simple CAPTCHA

So I made this CAPTCHA script a little while ago for OneLobby. I have no idea how strong it is, but I took a different approach to obfuscating the image. Normally one would put lot's of lines and shapes and whatnot in the image as extra noise. I didn't feel like doing this this time around so I messed around with the quality of the image instead... (skip to the end if you want to download the .zip)

You can find an example of the CAPTCHA script if you click here.

» read the rest of this entry.

Quick and Dirty Re-Design

Okay, I did a quick and dirty re-design. It's not as humorous as the previous look with my distorted green face, oh well. I don't know exactly why I re-designed the blog but I just did.. maybe I'll start trying to write more often too... we'll see. :D

A quick note, one thing I've done in this design is use the Reset CSS that's part of the Yahoo User Interface. It's pretty kickass.

P.S. If you think it sucks, please say so.

k4BB version 1, circa 2004

A few weeks ago I was approached to sell k4 Bulletin Board (version 2) and although the persons price wasn't what I had in mind, I never thought of offering to sell k4BB v1.

I think the reason why that thought never occured to me is because most people don't know that the k4BB that (if anyone) people know about is actually the second version. The first version of k4BB is actually more modern, with the exception of fancy javascript. It was built with PHP 5 whereas k4BB v2 is PHP 4.

The reason k4BB v1 was PHP 5 was that it was made to compete in the Zend PHP 5 Competition. It tied for 22nd place!

Another reason why people might not care about it is because it only has slightly more features than phpBB 2 and looks a lot like vBulletin 3... haha! Oh well, check k4BB version 1 out here.