You Are Here Home > Server Performance

Server Performance

PHP Date/Time Handling Made Easy; a beginner’s guide to PHP time and date handling

When I started with PHP, I was a bit confused about this subject so this will hopefully help a beginner a lot.

UNIX Timestamp

UNIX Timestamp (or Unix time or POSIX time) is the number of seconds since the midnight of January 1, 1970 UTC.

You can get the current timestamp with PHP’s time() function:

<?php
	echo time();
?>

This will show you the number of seconds since January 1, 1970 UTC.

Assume that you are creating a blogging application using PHP and you want to save the time/date of the posts
with them, in your database, you can create a table like this:

CREATE TABLE IF NOT EXISTS `post` (
  `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
  `user_id` int(10) UNSIGNED NOT NULL DEFAULT '0',
  `title` varchar(250) NOT NULL DEFAULT '',
  `body` text NULL DEFAULT '',
  `ip_address` varchar(30) NOT NULL DEFAULT '',
  `date` int(11) DEFAULT NULL,
  `last_update` int(11) NOT NULL DEFAULT '0',
  PRIMARY KEY  (`id`),
  KEY `date` (`date`),
  KEY `last_update` (`last_update`)
);

Now, a query to insert a blog post will look something like this:

<?php
 
$query = '
	INSERT INTO post
		(
			user_id,
			title,
			body,
			ip_address,
			date,
			last_update
		)
	VALUES
		(
			' .$user_id .',
			' .mysql_real_escape_string($_POST['title']) .',
			' .mysql_real_escape_string($_POST['body']) .',
			' .mysql_real_escape_string($_SERVER['REMOTE_ADDR']) .',
			' .time() ',
			' .time() '
		)
';
?>

(I left our details about filtering $_POST array out of this, you might want to filter the $_POST array a bit)

This way the query to get all the posts, sorted by date would look like:

SELECT *
FROM post
ORDER BY date DESC

A query to get all the posts from last 24 hours would look like:

<?php
$start_date = time() - (24 * 60 * 60);
$query = "
   SELECT *
   FROM post
   WHERE date >= $start_date
   ORDER BY date DESC
";
$result = mysql_query($query);
/* ... */
?>

A Performance Tip

If you don’t pay attention, you will end up with 100s of calls to time() throughout your application and we
know that function calls have overhead so what do you do?

We can call time only ONCE and save the results in a constant which will be global also, just like the time()
function:

<?php
	define('TIME_NOW', time());
?>

Converting UNIX Time To Readable Time

How do we show what time it is? That is in a format like: Mon, 15 Aug 2005 15:12:46

There is another useful function in PHP for this purpose and that is the date() function.

First you must set a default system timezone, it’s very simple, way on top of your scripts, (in your main include
fine perhaps) call this:

<?php
	date_default_timezone_set('EST');
?>

Don’t worry if you don’t understand what’s happening, this might help clear out a bit of the confusion:
http://www.php.net/manual/en/function.date-default-timezone-set.php

Again, read on and just add the line above on top of your script…

Now back to business, here is a simple call to the date() function:

<?php
	echo date('D/M/Y', TIME_NOW); /* TIME_NOW was explained earlier in this same post */
?>

This will show you something like:

Sun/Jan/2010

You can see that the first argument is a format in which you want the date to be, shown and the second argument is the timestamp of the date, if you don’t provide the second argument, the current timestamp will be used.

Here is another example that shows the time also:

<?php
	echo date('D/M/Y h:i:s A', TIME_NOW); /* TIME_NOW was explained earlier in this same post */
?>

Output:

Sun/Jan/2010 03:12:46 PM

These are some more examples: (taken from here)

<?php
// set the default timezone to use. Available since PHP 5.1
date_default_timezone_set('UTC');
 
 
// Prints something like: Monday
echo date("l");
 
// Prints something like: Monday 8th of August 2005 03:12:46 PM
echo date('l jS \of F Y h:i:s A');
?>

I suggest that you read this page:

http://php.net/manual/en/function.date.php

Tip For Using The date() Function

You shouldn’t have lines like:

<?php
	echo date('D/M/Y h:i:s A', TIME_NOW); /* TIME_NOW was explained earlier in this same post */
?>

All over your code, why?

Because if you decide to change the way you show date, then you have to go around and edit all the lines containing:

<?php
	echo date('D/M/Y h:i:s A', TIME_NOW); /* TIME_NOW was explained earlier in this same post */
?>

To fix this, you could have a constant containing your date format string like:

<?php
	define('DATE_FORMAT', 'D/M/Y h:i:s A');
?>

Then in your code, you do this:

<?php
	echo date(DATE_FORMAT, TIME_NOW);
?>

Now if you want to change the format of the date throughout your PHP application, you can just edit the line with:

<?php
	define('DATE_FORMAT', 'D/M/Y h:i:s A');
?>

And it will magically change all of them!

Better yet, I would have a function like:

<?php
 
	function display_date($timestamp = NULL) {
		echo date('D/M/Y h:i:s A', $timestamp);
	}
 
?>

Or even better yet, you could have the function return the string as a value, so you have even greater control:

<?php
 
	function get_date_string($timestamp = NULL) {
		return date('D/M/Y h:i:s A', $timestamp);
	}
 
?>

Then call it like:

<?php
	echo get_date_string(TIME_NOW);
?>

The Pain Of Finding Out The Timestamp From A Formatted Date String

I made the pain part up, fortunately there is a function that does this very easily, it is strtotime()

<?php
	echo strtotime('9/25/2010 02:28:30 PM');
?>

And bam! magically, you will get the timestamp, it doesn’t end there, you can do things like this:

<?php
	echo strtotime('today'), "\n";
	echo strtotime('today + 1 day'), "\n";
	echo strtotime("now"), "\n";
	echo strtotime("10 September 2000"), "\n";
	echo strtotime("+1 day"), "\n";
	echo strtotime("+1 week"), "\n";
	echo strtotime("+1 week 2 days 4 hours 2 seconds"), "\n";
	echo strtotime("next Thursday"), "\n";
	echo strtotime("last Monday"), "\n";
?>

Read more about strtotime() here:

http://php.net/manual/en/function.strtotime.php

How To Display Dates Like ‘x days ago’?

I got this function form one of the comments on PHP documentation, it’s very nice and does just this:

<?php
	function date_range($timestamp) {
		if( $timestamp < 1 ) return '';
		$difference = time() - $timestamp;
		$periods = array("second", "minute", "hour", "day", "week", "month", "year", "decade");
		$lengths = array("60",     "60",     "24",   "7",   "4.35", "12",    "10");
		for($j = 0; $difference >= $lengths[$j]; $j++)
		$difference /= $lengths[$j];
		$difference = round($difference);
		if($difference != 1) $periods[$j].= "s";
		$text = "$difference $periods[$j] ago";
		return $text;
	}
?>

And call it like:

<?php
	echo date_range(strtotime('today - 1 day'));
?>

Back To The Blog Post Example

I will show you a quick example of displaying those blog posts we talked about in the beginning of this article with a nice formatted time:

<?php
$start_date = time() - (24 * 60 * 60);
$query = "
   SELECT *
   FROM post
   WHERE date >= $start_date
   ORDER BY date DESC
";
$result = mysql_query($query);
while ($post = mysql_fetch_assoc($result)) {
	echo "<strong>{$post['title']}</strong><br />";
	echo "{$post['body']}<br />";
	echo "Published: " .date_range($post['date']) ."<br /><br />";
}
?>

This is very simplistic but demonstrates the concept.

I hope this helps. If you liked it, help spread the word, it’s always appreciated.

Good Luck :)

PHP Date/Time Handling Made Easy; a beginner’s guide to PHP time and date handling
Comments (0)   Filed under: PHP, Server Performance, Web Development   Posted by: Codehead on January 24, 2010

How PHPCache saved us from buying another server

I developed a large website for a client and in the past month we were getting a lot of traffic.

It was in a way that the server had problems handling the traffic and my client wanted to get another server to load balance the traffic between the two.

Pages on this site are generated from 10 to 25 MySQL queries and these queries are optimized but consider this, if there are 1,000 request for a page with 25 queries in a very small period of time, that would be 25,000 queries. 25,000 queries + processing them could lead to huge server loads.

So we used PHPCache to cache the results of those queries for just 1 minute, not an hour or a day, just one minute and it made a huge difference.

The difference was that we cached all 25 queries plus the time it took to process them using PHPCache and now to handle 1,000 requests we were querying the database only 1,000 times.

I think this site can easily handle 10 times more traffic now.

How PHPCache saved us from buying another server
Comments (0)   Filed under: MySQL, PHP, Server Performance, Web Development   Posted by: Codehead on November 25, 2008

Finding and fixing bottlenecks-slow parts in your PHP code

Sometimes you can see that your script is running slow but if you don’t have a lot of experience you don’t know how to find out what’s the problem and where to start looking for it.

You then naturally start looking at your loops and things like that, but from my experience the bottleneck is almost always somewhere you are not expecting.
It’s often in your database queries or calling external resources. The ones that look so innocent :)

To find out where the issue is, you can use these two functions:

	function benchmark() {
		static $start = NULL;
		if( is_null($start) ) {
			$start = get_microtime();
		} else {
			$benchmark = get_microtime() - $start;
			$start = get_microtime();
			return $benchmark;
		}
	}
 
	function get_microtime() {
		list($usec, $sec) = explode(" ", microtime());
		return ((float)$usec + (float)$sec);
	}

Place these 2 functions on top of your code and place these in your code:

benchmark(); /* The first call will initialize the function */
 
/* Some code */
 
echo benchmark() .'<br />';
 
/* Some more code */
 
echo benchmark() .'<br />';
 
/* Yet more code */
 
echo benchmark() .'<br />';

This will show you numbers like 0.02341… etc.
People usually don’t say how long part of a script should run or how long is too long but I’ll tell you that if you get numbers like 0.1, 0.2, 0.4 or 1.4 then you have a problem and your application might not scale well.
If this is the case then you should use PHPCache and cache the results of those slow parts, even for 1 minute at a time, this will bring those numbers down to 0.02 or 0.01…

The other thing you should do first is to check out your queries, use PHPMyAdmin, try “EXPLAIN your query” and see if MySQL is using your indexes properly. (If you indexed your tables well to begin with)
Query optimization is a big topic, I will write about that more later but sometimes query optimization won’t help you because your query is too nasty and you can’t do it any other way. (With your level of experience)

I hope this helps someone :)

Finding and fixing bottlenecks-slow parts in your PHP code
Comments (0)   Filed under: PHP, Server Performance, Web Development   Posted by: Codehead on September 17, 2008

PHPCache; a new version of PHPCache is available

A new version of PHPCache is available.

This one has 5 new methods:

PHPCache::set_expire($key)
Which will set the expiration of the cache record for $key in the past, I think this method has some advantages over deleting the key all together.

PHPCache::remove($key)
Will completely remove the row.

PHPCache::clean_up()
This method will be called when ever you construct/configure a new PHPCache object with PHPCache::configure($database) method and does two things:

1 – Will delete all the old keys on the table, you can control how often this happens with 2 constants:
PHPCACHE_GC_PROBABILITY & PHPCACHE_GC_DIVISOR
If you set PHPCACHE_GC_PROBABILITY to 10 and PHPCACHE_GC_DIVISOR to 100, then when ever you configure the PHPCache object with PHPCache::configure($database); there will be 10% chance that the garbage collector will delete the old rows.
The default value is 1%.

2 – It will optimize the table PHPCache is using, you can also control how often this happens through 2 other constants:
PHPCACHE_TO_PROBABILITY & PHPCACHE_TO_DIVISOR
It works similar to #1 and default value is 10%.

PHPCache::gc()
Will delete the old rows anytime you call this method, it doesn’t care about PHPCACHE_GC_PROBABILITY & PHPCACHE_GC_DIVISOR
One place to use this would be a cron tab.

PHPCache::optimize_table()
Will optimize PHPCache’s table and doesn’t care about
PHPCACHE_TO_PROBABILITY & PHPCACHE_TO_DIVISOR

This new version has some more minor improvements over the old one too.

PHPCache; a new version of PHPCache is available
Comments (0)   Filed under: PHP, Projects, Server Performance, Web Development   Posted by: Codehead on September 16, 2008

PHPCache, a simple, powerful object caching solution for PHP applications…

[ D O W N L O A D ]

If you have a dynamic website, written in PHP and your site is slow then this solution might help you.
Some times you have to have some nasty query then process the result afterwards which makes the whole thing even nastier and slow.

With PHPCache, you will be able to cache the result of that piece of code for as long as you want.
Suppose that your nasty script gets 100 hits per second, and you cache your script using PHPCache for just 1 minute at a time, the result is, in that one minute your server will run that piece of code only once.

PHPCache will only query the database for the result that was stored in the database 100 times in that one minute.
This will be a very quick process, since it’s only a primary key lookup (piece a cake) for MySQL and SQLite. These databases can handle 1000s of simple queries like these per second! But your server might only be able to process your code 5 times per second…
In fact I tested this and SQLite could retrieve the cache 2,300 per second, MySQL around 2,500 times!

PHPCache supports MySQL, MySQLi and SQLite extensions at this time but you are welcome to write and submit extensions for other database servers.

The other great thing about PHPCache is support for SQLite; SQLite is a very nice, quick little database that you can setup easily and you won’t need to have MySQL.

Here is an example usage of PHPCache:

require_once 'phpcache.class.php';
 
	$database = array(
		'type'  => 'mysql',
		'name'  => 'YOUR DATABASE NAME',
		'table' => 'PHPCache',
		'user'  => 'YOUR DATABASE USERNAME',
		'pass'  => 'YOUR DATABASE USERNAME\'S PASSWORD',
		'host'  => 'localhost' /* Or maybe IP address of your database server */
	);
 
	PHPCache::configure($database);
	$cache = PHPCache::instance();
 
	if( ($results = $cache->get('result_of_some_nasty_code')) !== false ) {
		$tpl->assign($results);
		/* Or maybe return $results or whatever depending on where you use this */
	} else {
		/***********************
		 * Your slow code here
		 ***********************/
 
		$cache->store('result_of_some_nasty_code', $results_of_your_slow_code, PHPCACHE_1_HOUR * 5); /* Cache for 5 hours */
	}

It’s very simple!

You can use it in any kind of application, commercial and non-commercial, the only thing I ask is that if you like it, help me spread the word.
You can write a blog post about it, tell your friends about it or whatever, I will really appreciate that :)

What you can store
You can store variables, arrays and objects BUT not resources (like a file or a database handle), PHPCache will serialize your array or object for you but remember to read the information on this page regarding object unserialization:
http://us3.php.net/unserialize

Date constants
PHPCACHE_1_SECOND
PHPCACHE_1_MINUTE
PHPCACHE_1_HOUR
PHPCACHE_1_DAY
PHPCACHE_1_WEEK
PHPCACHE_1_MONTH
PHPCACHE_1_YEAR

To store something for 5 days:

$cache->store('user_' .$user_id, $results_of_your_slow_code, PHPCACHE_1_DAY * 5);

How fast is it?
It can handle 2,300 queries per second on SQLite and 2,500 on MySQL. That’s very fast…

What about user specific data?
If your website has members and you want to cache some data specific to a user you can do something like this:

$cache->store('user_' .$user_id, $results_of_your_slow_code, PHPCACHE_1_MINUTE * 5);

What about the database table?
You don’t need to create the database table for PHPCache, the only thing you need to do is to populate this array:

$database = array(
		'type'  => 'mysql',
		'name'  => 'YOUR DATABASE NAME',
		'table' => 'PHPCache',
		'user'  => 'YOUR DATABASE USERNAME',
		'pass'  => 'YOUR DATABASE USERNAME\'S PASSWORD',
		'host'  => 'localhost' /* Or maybe IP address of your database server */
	);

Or for SQLite:

$database = array(
		'type'  => 'sqlite',
		'name'  => 'PATH TO A DATABASE FILE',
		'table' => 'PHPCache'
	);

“The filename (which is the name in our $database array) of the SQLite database. If the file does not exist, SQLite will attempt to create it. PHP must have write permissions to the file if data is inserted, the database schema is modified or to create the database if it does not exist.”

You can read more about SQLite here:
http://us3.php.net/manual/en/book.sqlite.php

After you setup the $database array you can go ahead and configure PHPCache like this:

PHPCache::configure($database);

Then you can ask PHPCache to make the table for you:

$cache = PHPCache::instance();
$cache->create_table();

Remeber to call $cache->create_table(); only once the first time you use PHPCache!

Also remember, when using SQLite, PHP must have write permissions to the directory you want to make the database file in, for example if you have:

$database = array(
		'type'  => 'sqlite',
		'name'  => $_SERVER['DOCUMENT_ROOT'] .'/cache/phpcache_database_file',
		'table' => 'PHPCache'
	);

You must create the directory “cache” and change it’s permissions so PHP can write to it.

How to write a driver for it?
Here is the interface your driver should implement:

interface PHPCache_Driver_Interface {
 
		public function query($query);
		public function escape($value);
		public function close();
		public function error();
		public function create_table($table_name);
 
	}
 
 
	interface PHPCache_Driver_Results_Interface {
 
		public function fetch_row();
		public function fetch_array();
		public function fetch_assoc();
 
	}

Suppose you want to write a driver for MSSQL, then you will have to write two classes and place them in a file named “phpcache.driver.mssql.class.php” and move it to the folder “PHPCache/drivers”.

Your class names should follow these rules:

             class PHPCache_Driver_mssql implements PHPCache_Driver_Interface {
                  /* ... */
	} // Class
 
 
	class PHPCache_Driver_mssql_Results implements PHPCache_Driver_Results_Interface {
	    /* ... */
	} // Class

Then you can use your driver like this:

$database = array(
		'type'  => 'mssql',
		'name'  => 'YOUR DATABASE NAME',
		'table' => 'PHPCache',
		'user'  => 'YOUR DATABASE USERNAME',
		'pass'  => 'YOUR DATABASE USERNAME\'S PASSWORD',
		'host'  => 'localhost' /* Or maybe IP address of your database server */
	);

Take a look at one of the drivers to see how exactly it looks like.

EDIT 9/15/2008:

A new version of PHPCache is available.

This one has 5 new methods:

PHPCache::set_expire($key)
Which will set the expiration of the cache record for $key in the past, I think this method has some advantages over deleting the key all together.

PHPCache::remove($key)
Will completely remove the row.

PHPCache::clean_up()
This method will be called when ever you construct/configure a new PHPCache object with PHPCache::configure($database) method and does two things:

1 – Will delete all the old keys on the table, you can control how often this happens with 2 constants:
PHPCACHE_GC_PROBABILITY & PHPCACHE_GC_DIVISOR
If you set PHPCACHE_GC_PROBABILITY to 10 and PHPCACHE_GC_DIVISOR to 100, then when ever you configure the PHPCache object with PHPCache::configure($database); there will be 10% chance that the garbage collector will delete the old rows.
The default value is 1%.

2 – It will optimize the table PHPCache is using, you can also control how often this happens through 2 other constants:
PHPCACHE_TO_PROBABILITY & PHPCACHE_TO_DIVISOR
It works similar to #1 and default value is 10%.

PHPCache::gc()
Will delete the old rows anytime you call this method, it doesn’t care about PHPCACHE_GC_PROBABILITY & PHPCACHE_GC_DIVISOR
One place to use this would be a cron tab.

PHPCache::optimize_table()
Will optimize PHPCache’s table and doesn’t care about
PHPCACHE_TO_PROBABILITY & PHPCACHE_TO_DIVISOR

This new version has some more minor improvements over the old one too.

PHPCache, a simple, powerful object caching solution for PHP applications…
Comments (10)   Filed under: PHP, Server Performance, Web Development   Posted by: Codehead on September 7, 2008

highscalability.com and some funny comments they make

1-
One of them which is posted on: (Until now at least 9/4/2008)

http://highscalability.com/digg-architecture

In the “Lessons Learned” section says:
Tune MySQL through your database engine selection. Use InnoDB when you need transactions and MyISAM when you don’t. For example, transactional tables on the master can use MyISAM for read-only slaves.

InnoDB tables are mostly faster than MyISAM. The only thing MyISAM supports is full-text search which is crappy and slow on large datasets anyway.

2-
On the same page:
They moved nearly all work out of the database and into applications, including joins, an operation we normally think of as the job of the database.

a) If you want to join tables from your PHP scripts, that means putting a query in a loop and that means sending a query 10, 15 or 20 times to MySQL and get the results and put the results together some how.
This is slow your application down dramatically…
On the other hand, you can let MySQL handle; MySQL is written in C which is a lot (I mean a lot) faster than PHP; it is also designed to do joins and things like that and knows how to optimize your joins; it is made to be fast!
(This also applies to most database servers)

b) If you want to move sorts to PHP, then you are in so much trouble, say you have 1,000,000 users in a table and you want to get your latest 10 users sorted by username, do you know what you have to do?
You have to load all 1,000,000 users to an array in PHP and then use a usort with a custom function that compares the usernames and the problem with this is that PHP will probably run out of memory in the first place and if not, it will take a long time.

If you follow these 2 “lessons” you will make web applications that suck so bad that you either have to rewrite them or add 1 server per 10 extra users per second…

highscalability.com and some funny comments they make
Comments (0)   Filed under: Annoying Stuff, Server Performance, Web Development   Posted by: Codehead on September 4, 2008