Web Development

How to fix transparent PNGs in Internet Explorer

You might know already that there are some issues with transparent GIFs but PNGs don’t have those issues.
The problem with transparent PNGs is that Internet Explorer doesn’t like them so much and gives them a funny background.

So here is the solution that works great:
http://homepage.ntlworld.com/bobosola/index.htm

Archived under Annoying Stuff, JavaScript, Web Browsers, Web Design, Web Development Comments

Calling a JavaScript function from Actionscript 3 (Flash)

It’s very easy:

import flash.external.ExternalInterface;
...
ExternalInterface.call("your_javascript_function()");

You can even get a return value:

var x:int = ExternalInterface.call("get_x()");

Archived under Actionscript, Flash, JavaScript, Web Development Comments

How to move a column’s position in a MySQL table

You can move a column in a MySQL table to another position like this:

ALTER TABLE name_of_the_table MODIFY column_to_move tinyint(1) DEFAULT '0' AFTER column_to_move_after

Note: the part with: “tinyint(1) default ‘0′” is necessary and it should be the exact definition of your column.
For example yours might be:
int(10) unsigned NOT NULL auto_increment
or
int(10) unsigned NULL default ‘0′
or

Archived under MySQL, Web Development Comments

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

There is another way to fix this issue and I didn’t write about it because I couldn’t make it work at first.
Apparently I was missing one line :)

First you will need to find out where libexpat is located on your server, it’s probably here:
/usr/lib

To find out for sure, open this folder (/usr/lib) and look for the file:
libexpat.so

If you can’t find it, log in as root via SSH and enter:
whereis libexpat.so

This should list the folder in which libexpat is located.

After all this you will need to compile PHP to use libexpat instead of libxml, so go to:
/var/cpanel/easy/apache/rawopts/

And create a file and name it “all_php5″ (no quotes), if there is a file with this name edit it and add these lines to the end of it:
–with-expat=builtin
–with-libexpat-dir=/usr/lib

(lines start with two dashes “-” that are not showing up here for some reason)
Remember that depending on where libexpat is located on your server you might need to edit the second line.

Now compile Apache and everything should work fine!

Archived under Annoying Stuff, Programming, Server, Web Development Comments

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

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)

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…

Archived under Annoying Stuff, Server Performance, Web Development Comments

Acid Test and different web browsers

Acid test is a test to identify problems web browsers have when rendering web pages.
There are 3 versions Acid Test 1, 2 and 3.

Acid2 should look like this:

But here is how Acid Test 2 works on my different browsers:

Google Chrome:

Firefox:

Opera:

Safari:

Retarded Internet Explorer 7:

!!!

Now, none of my browsers passed Acid Test 3!!!
It should look like this:

Google Chrome:

Firefox:

Opera:

Safari:

Retarded Internet Explorer 7:

Of all the browsers, all perform almost the same but only Internet Explorer is way off, I don’t know what the developer team who is in charge of Internet Explorer does at Microsoft every day. I’d say all of them deserve to be fired!!!

Of all the other browsers, I think Apple Webkit rendering engine is the best (Google Chrome and Apple Safari) which I think is another reason for Google to use it in their browser Chrome.

Apple Webkit is a state of the art and open source HTML rendering engine developed and released by Apple.

Here are the links to these tests:
Acid2
Acid3

Archived under CSS, HTML, Web Browsers, Web Design, Web Development Comments

My first impressions of Google Chrome

1 - It was extremely easy to install.
2 - It looks like a solid product.
3 - It doesn’t crash like IE 8.
4 - It’s fast.
5 - It’s very smooth.
6 - Has spell checking built in. (Just right click on the words that are underlined…)
7 - It’s very simple and elegant looking.
8 - Has nice new JavaScript engine V8.
9 - Has a nice JavaScript console and debugger.
10 - It doesn’t take 3 seconds (15 million instruction) to open a new tab.
11 - When you right click on a link it says “Copy link address” not “Copy shortcut” ;)

I’m using Google Chrome to write this and it might be the end of IE horror for me :) (and yes I don’t like Firefox…)

I also noticed that Cnet news wrote this funny article:
http://news.cnet.com/8301-17939_109-10030522-2.html

In case the author doesn’t know (which I think they should, before they write for Cnet) that is Google’s general terms of services and applies to all of their products including Gmail:
https://www.google.com/accounts/TOS?loc=US&hl=en

Archived under Web Browsers, Web Design, Web Development Comments

Google Chrome; another browser for your browser arsenal!

Now you can download a beta version here:

http://www.google.com/chrome/

I make web pages so I have to have all the possible browsers installed so I can check the pages I code in all of them and make sure they look the same.
So far I have Internet Explorer 7, Internet Explorer 6, Firefox, Opera, Safari and now Google Chrome!

It was a really easy and smooth installation and it even automatically imported my favourites from Internet Explorer.

Archived under Web Browsers, Web Design, Web Development Comments

Users without JavaScript and what to do about them

Here is what I do:

<noscript>
	<div style="color:#FF0000">
   	<strong>Sorry!</strong><br /><br />
      Please enable JavaScript on your browser to be able to use advanced features of this site.
      <br /><br /><br />
      <strong>Internet Explorer 6 or 7</strong>
      <ul style="list-style-type: decimal">
      	<li>Click the Tools menu.</li>
         <li>Select Internet Options.</li>
         <li>Click the Security tab.</li>
         <li>Click the Custom Level button.</li>
         <li>Scroll down until you see the 'Scripting' section. Select the 'Enable' radio button for 'Active Scripting.'</li>
         <li>Click the OK button.</li>
         <li>Click the Yes button in the confirmation window.</li>
      </ul><br />
      <strong>Firefox 2 or 3</strong>
      <ul style="list-style-type: decimal">
      	<li>Click the Tools menu.</li>
         <li>Select Options.</li>
         <li>Click the Contents tab.</li>
         <li>Select the 'Enable JavaScript' checkbox.</li>
         <li>Click the OK button.</li>
      </ul><br />
      <strong>Safari 2 or 3</strong>
      <ul style="list-style-type: decimal">
      	<li>Click the Safari menu.</li>
         <li>Select Preferences.</li>
         <li>Click the Security tab.</li>
         <li>Select the 'Enable JavaScript' checkbox.</li>
      </ul>
   </div>
</noscript>

“noscript” tag ensures that users without JavaScript will see this message ;)

Archived under AJAX, JavaScript, Web Development Comments

jEditable and password input type support

I wrote a post earlier about how jEditable (a jQuery) plugin needed password support and the author of the plugin wrote back and said here is how to add this feature:

$.editable.addInputType(’password’, {});

You can read more here:
http://www.appelsiini.net/2007/8/custom-input-types
http://www.appelsiini.net/2008/4/autogrow-textarea-for-jeditable

This plugin is really great and we are doing some exciting things on Bloggapedia with it.
We will launch early this week hopefully because we are working on a recommendation engine.

Happy Coding :)

Archived under AJAX, JavaScript, Projects, Web Development Comments

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

Password Support for Jeditable, a Cool jQuery Plugin

Here is the original plugin:
http://www.appelsiini.net/projects/jeditable

It let’s you implement inline editing capabilities and it’s supported by major browser.
Here are some examples:
http://www.appelsiini.net/projects/jeditable/default.html

An example usage is like this:

$(".edit_area").editable("http://www.example.com/save.php", { 
         type      : 'textarea',
         cancel    : 'Cancel',
         submit    : 'OK',
         indicator : "<img src='img/indicator.gif'>",
         tooltip   : 'Click to edit...'
     });

The problem is, it doesn’t support password input types, but here is how to add this support.

1 - Open the plugin file.
2 - Find this code:

text: { 
	element:function(settings,original) {
		var input=$('<input>');
		if(settings.width!='none') {
			input.width(settings.width);
		}
		if(settings.height!='none') {
			input.height(settings.height);
		}
		input.attr('autocomplete','off');
		$(this).append(input);
		return(input);
	}
},

3 - Add this after that:

password: { element:function(settings,original) {
		var input=$('<input type="password">');
		if(settings.width!='none') {
			input.width(settings.width);
		}
		if(settings.height!='none') {
			input.height(settings.height);
		}
		input.attr('autocomplete','off');
		$(this).append(input);
		return(input);
	}
},

Now you can do:

$(".edit_area").editable("http://www.example.com/save.php", { 
         type      : 'password',
         cancel    : 'Cancel',
         submit    : 'OK',
         indicator : "<img src='img/indicator.gif'>",
         tooltip   : 'Click to edit...'
     });

It’s odd that the developers didn’t add this capability…

Archived under AJAX, JavaScript, Web Development Comments (3)

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

« Previous entries