PHP

One Problem With Python

I think one problem Python has is the lack of a great online manual, with great I mean like PHP’s:
http://www.php.net/manual/en/function.ftp-alloc.php

Every single function is documented with examples and I think this is one of the main reasons why PHP is so popular.

Archived under PHP, Programming, Python Comments

A PHP Competition

OK, here is the competition:

Write the shortest piece of PHP code to convert:
Lorem_ipsum_dolor_sit amet,_consectetur_adipisicing_elit

Into this:
Lorem_Ipsum_Dolor_Sit amet,_Consectetur_Adipisicing_Elit

There is no prize other than I will write a post about you :)
Leave a comment.

Update:
Chris wrote a perfectly working line of code for the first string I posted, but you will have to write one that will still work if there is a space in one of the words. I fixed the example.

Archived under Fun, PHP, Programming Comments (9)

Fixing libxml, php bug and issues with HTML entities; downgrading libxml

When you parse XML with PHP and libxml 2.7.0, all HTML entities were stripped out and this annoying bug messed up a lot of things and no one seems to care enough to fix this.

This bug is also reported here:
http://bugs.php.net/bug.php?id=45996
http://bugs.typo3.org/view.php?id=9359&nbn=2

From reading these few resources, I knew I had to downgrade to an older version of libxml but since I’m not very good at Linux I had no idea how to.

But I finally figured this out and here is how to do it with WHM/cPanel:

First you will have to install an older version of libxml, I installed libxml 2.6.30.
You will need an SSH client and you will have to login to your server with root, I use Putty:
http://www.chiark.greenend.org.uk/~sgtatham/putty/
Download it, run it, enter the IP address of your server, enter root and enter your password.
Then do:

cd /opt

mkdir libxml

cd libxml

wget http://xmlsoft.org/sources/libxml2-2.6.30.tar.gz

tar xvzf libxml2-2.6.30.tar.gz

cd libxml2-2.6.30

./configure –bindir=/opt/libxml/ –sbindir=/opt/libxml/ –libexecdir=/opt/libxml/ –datadir=/opt/libxml/ –sysconfdir=/opt/libxml/ –sharedstatedir=/opt/libxml/ –libdir=/opt/libxml/ –includedir=/opt/libxml/ –oldincludedir=/opt/libxml/

make && make install

Now you will need to update yum.conf to prevent it from updating libxml back, so edit:
/etc/yum.conf

And find the line that starts with:
exclude=

And add libxml* to the end of it so this line should look something like this:
exclude=apache* bind-chroot courier* dovecot* exim* httpd* mod_ssl* mysql* nsd* php* proftpd* pure-ftpd* spamassassin* squirrelmail* libxml*

Now we will have to let WHM know that we want to compile PHP with this new libxml path so go to:
/var/cpanel/easy/apache/rawopts/

There might be a file there named: “all_php5″ (no quotes) if there is edit it if there is not create it and add these lines to the end of it:
–with-libxml-dir=/opt/libxml
–with-libxml-dir=/opt/libxml/

Now go ahead and build Apache and PHP using:
Main >> Software >> Apache Update

You should be all set.

Please note:
1 - Do this on your own risk.
2 - I’m not very good at Linux so please let me know if there is an easier method.
3 - This worked great on my CentOS.
4 - If you have never used WHM’s Apache Update, go ahead and read about it first.

Archived under Annoying Stuff, PHP, Server, Web Development Comments (4)

xml_set_character_data_handler problems with HTML entities like < >

This is a big issue and broke a lot of our websites unfortunately.
The problem is that the cdata_handler will be called when the parser finds tokens like < and passes nothing to your cdata_handler which it’s suppose to pass things like < or >.

The problem is with libxml 2.7.0 and 2.7.1 and 2.7.2 fixes the issue:
http://xmlsoft.org/news.html

They say 2.7.2 fixes it but it doesn’t really, it’s very disappointing.

Archived under PHP, Web Development Comments

PHP Script for recursively deleting a folder and all of its contents, subfolders and files

<?php
 
	set_time_limit(900);
 
	delete_folder(dirname(__FILE__) .'/');
 
	function delete_folder($folder) {
		$folder_contents = get_folder_contents($folder);
		if ($folder_contents) {
			foreach ($folder_contents as $__content) {
				// echo $__content['item'] .'<br />';
				if (is_dir($__content['item']))
					delete_folder($__content['item']);
				else
					unlink($__content['item']);
			}
		}
		rmdir($folder);
	}
 
	function get_folder_contents($folder) {
		if( !is_dir($folder) ) { 
			return false;
		}
		$return_array = array();
		$count		  = 0;
		if( $dh = opendir($folder) ) {
			while( ($file = readdir($dh)) !== false ) {
				if( $file == '.' || $file == '..' ) continue;													
				$return_array[$count]['item']	= $folder .$file .(is_dir($folder .$file) ? DIRECTORY_SEPARATOR : '');
 
				$count++;				
			}
			closedir($dh);
		}
		return $return_array;
	}
 
?>

Put it *inside* the folder that you want to delete and run it.
Be very careful when using this code, I warned you! Don’t use this if you don’t know any PHP.

Archived under PHP, Server Comments (1)

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 :)

Archived under PHP, Server Performance, Web Development Comments

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.

Archived under PHP, Projects, Server Performance, Web Development Comments

A cool break_words function for PHP

I wrote this a while back, if you wrote a better one please let me know :)

             function break_words($text, $length, $result_length, $append) {
		preg_match_all('#([^ ]{' .$length .',})#', $text, $matches);
		foreach($matches[1] as $word) {
			$word = trim($word);
			$text = str_replace($word, substr($word, 0, $result_length) .$append, $text);
		}
		return $text;
	}

This function will break the long words in string $text, which are more than $length to be maximum $result_length characters and appends what ever you pass in as $append.

Example usage:

$post = break_words($post, 30, 30, '');

I’m not convinced that this is the best solution.

Archived under PHP, Web Development Comments

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.

Archived under PHP, Server Performance, Web Development Comments (4)

SEOmoz Guy, PHP doesn’t suck really

I agree, PHP, is easy to learn, use and abuse and makes many people who don’t know anything about server and web development feel like experts, but that doesn’t mean PHP sucks, those developers suck.

Recently I read on SEOmoz:

There is no mileage in buying vBulletin for $160. It can’t be any good at that price - and is probably written in PHP. You are looking for a cool project to write in Ruby and here’s your chance.

Just in case the author doesn’t know, here is a list of sites that are powered by PHP:
1 - Facebook (http://www.facebook.com/index.php)
2 - Wikipedia (http://en.wikipedia.org/wiki/Index.php)
3 - Yahoo! bookmarks (You have to login)
4 - Stumbleupon (http://www.stumbleupon.com/index.php but redirects to http://www.stumbleupon.com/)
5 - SEOmoz itself! (http://www.seomoz.org/index.php)
6 - Flickr (http://www.niallkennedy.com/blog/uploads/flickr_php.pdf Flickr even uses Smarty template engine!)
There are more but I think this is enough.

Now vBulletin which is also written in PHP, is a state of the art forum software that is running some of the biggest communities on the web such as:
1 - Digital Point
2 - Site Point
3 - RC Groups
etc. ect.

That’s all.

Archived under Annoying Stuff, PHP, Web Development Comments

Adding Auto Login (Remember Me) Capability to Your Applications

Here are the steps:

1 - You need to add a field to your login form, preferably a checkbox and name it “remember” (or whatever).

2 - We need a way of recognizing users computer, to do this you will need to add an extra field to your user table and name it something like “token”:

ALTER TABLE YOUR_USER_TABLE ADD token VARCHAR(40);
ALTER TABLE YOUR_USER_TABLE ADD INDEX(token);

(We need the index for fast lookup)

You will also need another column to save the user agent:

ALTER TABLE YOUR_USER_TABLE ADD user_sig VARCHAR(40);

This is for security. (I will explain this in a little bit)

3 - We will also have to save a cookie on users computer; after you logged the user in successfully you will need something like this in your login script:

if (LOGIN_VALID()) {
   /* Log user in here first */
   if (isset($_POST['remember'])) {
       $token = md5(str_shuffle('ABCDEFGHIJKLMNOPQRSTUVWXYZ'));
       $user_sig = md5('SOME SECRET SEED' .$_SERVER['HTTP_USER_AGENT']);
       mysql_query("UPDATE YOUR_USER_TABLE SET token = '$token', user_sig = '$user_sig' WHERE USER_ID_FIELD = USERS_ID");
       $cookie_name = 'A SHORT NAME FOR THE COOKIE';
       $cookie_value = $token;
       $cookie_expire = time() + 60 * 60 * 24 * 30 * 12 * 10; /* Approx 10 years */
       $cookie_path	= '/';
       $cookie_domain = $_SERVER['SERVER_NAME']; /* If this didn't work, put your domain name here */
       setcookie($cookie_name, $cookie_value, $cookie_expire, $cookie_path, $cookie_domain);
   }
}

What this does is that it generates a token to be saved on user’s computer as a cookie, and also for security reasons, it generates a request signature out of user’s browser user agent and saves them both in your database.
It also sets a cookie on user’s computer with the token only.

4 - Now you will need to place something like this in your main include file:

if (!isset($_SESSION['valid_user']) && isset($_COOKIE['A SHORT NAME FOR THE COOKIE']) && trim($_COOKIE['A SHORT NAME FOR THE COOKIE']) != '') {
    $token = mysql_real_escape_string($_COOKIE['A SHORT NAME FOR THE COOKIE']);
    $user_result   = mysql_query("SELECT * FROM YOUR_USER_TABLE WHERE token <> '' AND token = '$token'");
 
    if ($user_result && mysql_num_rows(user_result) > 0) {
        $user = mysql_fetch_assoc($user_result);
        if ($user['user_sig'] == md5('SOME SECRET SEED' .$_SERVER['HTTP_USER_AGENT'])) {
             /* Go ahead and log the user in again */
             $_SESSION['valid_user'] = $user;
             session_regenerate_id(); /* Always good idea */
        }
    }
}

This script will check and see if the user is already logged in and if he/she is already logged in then it won’t go through all the trouble to log the user in again.
It also checks for existence of the cookie you saved on users computer before.

If all the conditions are true then the script will checks the token and user’s signature and if everything matches, it will log the user in.

5 - There is also one last step: Clean up. In your *logout* script, place:

       $cookie_name = 'A SHORT NAME FOR THE COOKIE';
       $cookie_value = '';
       $cookie_expire = time() - 60 * 60 * 24 * 30 * 12 * 10; /* Approx 10 years ago */
       $cookie_path	= '/';
       $cookie_domain = $_SERVER['SERVER_NAME']; /* If this didn't work, put your domain name here */
       setcookie($cookie_name, $cookie_value, $cookie_expire, $cookie_path, $cookie_domain);

This will delete the cookie from user’s computer when the user logs out.
If you don’t do this, your application will keep logging the user in even after he/she logs out.

The same concept will work in other languages.
Also this script only relies on the user agent to double check everything, you might want to take extra security measures…

I hope this helps someone :)

Archived under PHP, Web Development Comments

How to fix: Warning: Invalid argument supplied for foreach()

This warning happens only if you try to use foreach on a non array like:

$myvar = 10;
foreach ($myvar as $value) {}

If you run this, you will get:

Warning: Invalid argument supplied for foreach() in YOUR_FILE on line FOREACH_LINE

To fix this just cast $myvar to array like this:

$myvar = 10;
foreach ((array) $myvar as $value) {}

Archived under PHP, Web Development Comments

You can in fact use foreach to change array elements in PHP

Recently I read somewhere that you can’t do this and you have to use this awful syntax:

foreach ($array as &$value) {}

This is only valid in PHP5 and can have very bad consequences for example run this piece of code:

<pre><?php
$array = array(1, 2, 3, 4, 5);
foreach ($array as &$value) {
	echo "$value \n";
}
echo "\n\n";
foreach ($array as $value) {
	echo "$value \n";
}
?>

Here first foreach loop is foreach by reference but the second one is a normal foreach loop.
Run it and see what happens.

The way to change the elements using foreach is very simple actually, the only thing you need is a $key along with the $value!

/* Filter the input */
foreach ($_POST as $key => $value) {
   $_POST[ $key ] = trim(strip_tags($value));
}

Archived under PHP, Web Development Comments

A PHP form obfuscator; secure and spam free PHP forms

[ D O W N L O A D ]

Example usage:

<?php
 
	require_once 'class_obfuscator.php';
 
	$form_fields = array('username', 'password', 'email');
	$obfuscator  = new Form_Obfuscator($form_fields);
	$obfuscator -> set_secret_key('My Secret Key - ET8439FSKJ - EDIT THIS');
 
	if( empty($_POST) ) {
		$fields   = $obfuscator	-> obfuscate();
		$enc_form = $obfuscator	-> encode_form();
		?>
<form action="" method="post">
	Name:<br /><input type="text" name="<?php echo $fields['username']; ?>" /><br /><br />
   Password:<br /><input type="password" name="<?php echo $fields['password']; ?>" /><br /><br />
   Email:<br /><input type="email" name="<?php echo $fields['email']; ?>" /><br /><br />
   <input type="submit" />
   <input type="hidden" name="__A" value="<?php echo $enc_form; ?>" />
</form>
      <?php
	} else {
		foreach($_POST as $key => $value) $_POST[ $key ] = trim(strip_tags($value)); /* Filter input */
		$form = $obfuscator -> decode_form($_POST['__A'], $_POST);
 
		foreach($form as $key => $value) $form[ $key ] = htmlentities($value, ENT_QUOTES, 'utf-8'); /* Escape output */
		echo "Username: {$form['username']}<br />
				Password: {$form['password']}<br />
				Email: {$form['email']}";
	}
 
?>

This is a class I developed a while back while working on a project of mine and we already know that it’s very effective.

In order to understand what it does you need to first understand how a browser sends a POST request.
When a user submits a form, browser sends something like this to the server:

POST /somepage.php HTTP/1.1
Host: example.com
Content-Type: application/x-www-form-urlencoded
Content-Length: THE LENGTH

username=blah&password=blah&email=some_email

There are 2 problems with this:

1 - Someone along the way can view the password and email address by looking at the packets that are going to the server. (take a look at Wireshark software)

2 - You can send automatic queries to servers, for example automated spam through contact forms works like this. (some spam software can also read Captcha images so you need more protection)

The class I developed will change this POST request to something like this:

POST /somepage.php HTTP/1.1
Host: example.com
Content-Type: application/x-www-form-urlencoded
Content-Length: THE LENGTH

JDF8W9JHF=blah&OEROWF83=blah&VLKDSFOE=some_email

Note that the field names are changed to random strings, and they also change every time the form is shown, so:

1 - Even if a user in the middle can see the packets, he/she won’t know that OEROWF83 stands for “password”.

2 - A spam software won’t have a way of guessing the field names because they are random every time. There is also a secret encryption key which you only know what it is.

Questions and comments are welcome :)

Archived under PHP, Security, Web Development Comments (3)

Better PHP Applications

Developing better applications requires practice and study but there are little things you can do while you develop your applications that will help.

One of the things I think is very important and all great PHP developers do this is developing your application with error_reporting(E_ALL);

You have to simply place these lines on top of your PHP source files: (or put it on top of your common include file, hopefully you have one)

ini_set('display_errors', 1); /* Output all errors as oppose to logging them */
error_reporting(E_ALL);     /* Show all errors */

What this does is that it will ask PHP to show you all the errors (almost, later on this) such as warnings and notices. (It is most likely that PHP is already set to show you parser and fatal errors.)

Warnings are very important to address, they are run time errors but the compiler doesn’t halt the execution of the script.
Notices are most likely logical errors (in my experience). If you develop with error_reporting set to E_ALL you will see that PHP was telling you where the problems that took you 5 hours to find were all along.

Here is how to produce a notice and how it can help you with some problems.

Suppose you have this self submitting form:

<?php
error_reporting(0);
 
if (isset ($_POST['name'])) :
 
?>
 <form action="" method="post">
 Enter your name: 
 <input type="text" name="name" /><br />
 <input type="submit" />
 </form>
<?php
 
else: /* This is the alternate PHP syntax */
 
    echo 'Hello and welcome ' .htmlentities($_POST['name1'], ENT_QUOTES);
 
endif; /* This syntax will make your templates more readable */
?>

This won’t work, you might have spotted the issue but if you didn’t, you will see that this doesn’t work.
What it does is it turns error reporting off completely on line 2 and this is where the problem is (well, not the problem itself) because if you change line 2 to:

echo 'Hello and welcome ' .htmlentities(@$_POST['name'], ENT_QUOTES);

@ will tell the compiler that you know already what’s going on and the compiler won’t show the notice.

After you are done developing your application and ready to launch it, you will replace error_reporting(E_ALL); with error_reporting(0); to turn this off so the PHP compiler won’t show anything at all.

Better yet I suggest to do something like this:

ini_set("display_errors", 0); 
ini_set("log_errors",     1); 
ini_set("error_log",      "path/to/php.log"); 
error_reporting(E_ALL);

This will set the PHP to log errors rather than displaying them to the user and I suggest that you visit that error log every once in a while.

This way if your application crash or your users report strange things you will be able to check your log and possibly find some notices ;)

Also one of the reason you don’t want users to see PHP errors is that PHP will show the error and a path to the file that the error was occurred and some information about the error.
This could help malicious users identify your application’s file and folder structure and give them some clues on how they can exploit your application.

Happy Coding :)

Archived under PHP, Web Development Comments

Should we stop supporting users without JavaScript?

I say YES!

I’m doing it from now on, just like Facebook and many others, I will show them a message:
Sorry, you won’t be able to use this site until you enable JavaScript on your browser.

I think it’s time for AJAX everywhere and web applications should start being modern and interactive…

Archived under AJAX, JavaScript, PHP, Web Development Comments (5)

Accessing single character inside PHP strings

In PHP5 you don’t do it like

$char = $string{2};

Do it like:

$char = $string[2];

The curly braces syntax is deprecated!

Archived under PHP, Web Development Comments

Generating an array of months

Here is a nice way of doing this:

for( $i = 0; $i < 12; $i++ ) {
    $retval[ $i ] =
       date('M', strtotime('Jan +' .$i .' month'));
}

The real power of this is when you put it in a function like this:

function get_months($format) {
   $retval = array();
   for( $i = 0; $i < 12; $i++ ) {
      $retval[ $i ] =
         date($format, strtotime('Jan +' .$i .' month'));
    }
   return $retval;
}

And calling it like this:

$list_of_months_short_text = get_months('M');
$list_of_months_full_text  = get_months('F');

Archived under PHP, Web Development Comments