Monday, January 29, 2007

PHP Timer Class

Wrote a PHP Timer class this afternoon that might come in handy here and there for anyone developing PHP scripts. It's really simple actually, but powerful enough to be used just about anywhere you would need to measure time of script block execution.

Usage is simple:

$t1 = new Timer("mytimer");
.. (perform some code) ..
$t1->stop();
$t1->display();

You can also create any amount of timers and Timer::dump() them at the end of the script for a nice overview.

There's no better way on Blogger to post code like this, so it'll have to do for now:


<?
/*
 * Simple Timer Class
 *
 * Author: Mattias Nilsson (mrorigo@gmail.com)
 * Licenced under GPL. No warranties implied or given. 
 * Use at your own risk.
 *
 * Usage:
 * $t = new Timer("myid1");
 * ...
 * $t->stop();
 * ...
 * $t->display();
 * OR
 * Timer::dump();
 *
 */
class Timer
{
  var 
$id false;
  var 
$start false;
  var 
$stop false;
  var 
$time false;

  static 
$_TIMERS;

  
/*
   * @param $id Unique ID for your timer
   * @param $autostart Set to false to avoid timer start
   */
  
function Timer($id$autostart=true)
  {
    
$this->id $id;
    
Timer::addTimer($this);
    if(
$autostart)
      
$this->start();
  }

  
/**
   * Start the timer
   */
  
function start()
  {
    
$this->start Timer::getmicrotime();
  }

  
/**
   * Stop the timer and calculate elapsed time.
   *
   * @return Elapsed time since timer start.
   */
  
function stop()
  {
    
$this->stop Timer::getmicrotime();
    
$this->time $this->stop $this->start;
    return 
$this->time;
  }

  
/* *
   * Displays the timer result. If the timer is still running, it is stopped.
   */
  
function display()
  {
    if(!
$this->time)
      
$this->stop();
    print 
"Timer: ".$this->id.": " sprintf("%.5fs",$this->time) . "\n";
  }


  
/**
   * Adds a timer to the global timers array
   *
   * @param $timer Timer to add
   */
  
static function addTimer($timer)
  {
    
Timer::$_TIMERS[$timer->id] = $timer;
  }

  
/**
   * Dump/display all timers
   */
  
static function dump()
  {
    
reset(Timer::$_TIMERS);
    while(list(
$id$timer) = each(Timer::$_TIMERS))
      
$timer->display();
  }

  
/**
   * @return The current system milliseconds time as a float (seconds.fraction)
   */
  
static function getmicrotime()
  { 
    list(
$usec$sec) = explode(" ",microtime()); 
    return ((float)
$usec + (float)$sec); 
  }

}
?>



I killed Apache

I hereby swear to never consider Apache as a first-hand choice for installing any high-performance website again. It's simply not up for the task anymore.

I'm not going to back the previous statement up with a bunch of numbers and fancy graphs, you'll just have to take my word for it or come to this conclusion yourself after considering the options.

There was a time when Apache was one of the Greatest, and has contributed a great deal to the rapid growth of the Internet, but these days others have started over, considered every flaw and optimized for the latest kernels/IO-systems and hardware, and come up with software that does it's job in extremely efficient ways. mApache may have more features, but most of the time all you need is a fast static webserver with FastCGI-support anyway, right?

So, what's my choice? At the moment, LighTTPd outperforms anything I've ever tried, I'm yet to se it crash, and haven't missed one feature so far. Try it, be amazed and change your mind (if it's not changed already).

Memcached delivery-cache for Openads

I just submitted a patch for the Openads Project to add Memcached delivery-cache. This patch greatly increase deliver-cache performance over using the database, and almost completely eliminates SELECT queries to the database during delivery.

If you're using Openads (or PhpAdsNew 2.0.7 and above) you should be able to easily integrate this patch until it's in the main release(s).

Wednesday, January 24, 2007

File uploads with CakePHP

I wanted to upload a file and attach it to my object, but couldn't find a nice enough solution for it out there, so I created my own method, and I must say I'm quite happy with the results.

In my controller, I just added a method called encodeFile that take 2 parameters, the PHP file upload array, and a target variable reference;

   
function encodeFile($arr, &$dest)
{
switch($arr["error"]) {
case 0: // OK!
$fileData = fread(fopen($arr['tmp_name'], "r"),
$arr['size']);
if(!$fileData)
return "Could not read file from disk";
$dest = base64_encode($fileData);
break;
case UPLOAD_ERR_INI_SIZE:
case UPLOAD_ERR_FORM_SIZE:
return "The file is too big.";
case UPLOAD_ERR_PARTIAL:
case UPLOAD_ERR_NO_FILE:
return "The file was not uploaded.";
case UPLOAD_ERR_NO_TMP_DIR:
case UPLOAD_ERR_CANT_WRITE:
return "A configuration error occured";
default:
return "An unknown error occured.";
}

return true;
}


Then, in my add() method, I can use the function like this:

$ret = $this->encodeFile($this->params["form"]["File"], $this->data["MyModel"]["File"]);
if($ret !== true) {
$this->Session->setFlash('File problems: ' . $ret);
} else {
if($this->MyModel->save($this->data)) {
...

I also added a controller method to view the image:

function image($id)
{
$this->layout = "empty";
$o = $this->MyModel->read(null, $id);
Header("Content-type: image");
echo base64_decode($o["MyModel"]["File"]);
}

So, now I also have a blog

Just felt the urge to create a blog, so here it is!