Overloading in PHP must use public methods

July 25th, 2008

The magically overloading methods in PHP, such as __get, and __set must be public according to The PHP Manual.

Aleksis recently pointed that out to me by making his new methods public, which gave me the initiative to look it up at the manual.

I thought this script to convert them might end up being useful to others, too:

for i in `find -iname "*.php"
               |xargs egrep -i "(private|protected) function __(get|set)"
               |awk -F: '{print $1}'`
do 
sed 's/\(private\|protected\) function __\(get\|set\)/public function __\2/' $i >$i.processed;
mv $i.processed $i
done

Frontend optimizations

June 15th, 2008

In Excalibur Phoenix one aspect we are giving major attention to is frontend.

In contrast to Excalibur Reloaded (the previous version) we try not only to provide a user-friendly interface but we also want it to be as fast as possible for the client. The latter is mostly a need that came up as more and more users started using Zino. Furthermore, through the process of optimization we learn new techniques we weren’t keen with, that extend by far our knowledge especially on the way the browsers render a page and the lower level mechanisms that play a major part when there is a greater need for speed (the term is stolen from Google Blog :P ). So I want to write a few lines for some optimizations we started implementing in the new version.

1) Lessen HTTP requests

One of the most important aspects is to lessen the HTTP requests that are needed for a page to show properly. Till now, our pages had icons, images, many stylesheets and scripts. Each of those needed a separate HTTP request in order to download since all these files were separated. For example, we used to have the stylesheet for the user profile on a different file from the one for the frontpage. What we do now, is combine all the scripts in one file, all the stylsheets in another and so we use just two separate files for all our styling and javascript. Another thing we did is known with the term “spriting”. We combined all of our background images into one bigger image file. Everytime we need to show an icon, we use this image we created as a source and through the background-position we specify exactly which icon we want to be visible. Those are the most common and effective ways we are currently using in Phoenix

2) Cache content

Another way of reducing HTTP requests and the weight of downloading for the client is to use caching. More specifically caching with far-future headers set. To make things a bit clearer if the browser has cached some of the needed components he has to check whether those are valid according to the Last-Modified header in the response. If the component hasn’t been modified there is no need to download it, so the size of the download decreases. Though a request has been made, that could have been avoided if we used an Expires header. When we set an expires header, we are actually telling the browser to use the components in its cache till a specified date. Until this expiry date the browser uses its cached content without the need to ask for modification of the content. This is more useful with static data such as javascript, stylesheets and icons.

3) Minification

In projects where great amount of javascript is in use, minifying the code makes a lot sense. With the term minification we mean the elimination of spaces, line breaks and comments from the original code. In other words all unnecessary stuff is removed in order to lessen the size of the data the client will download. This technique can also be used for stylesheets but is not so effective. Stylesheets optimization is a bit more complex, as you can get the most of it if you find duplicate rules for elements and remove them. Some developers go a step further with obfuscation but I believe it’s not worth. In obfuscation variable and function names are changed automatically to shorter ones, in order to reduce even more the size. Another reason for using obfuscation is to make the code unreadable to others. Implementing this technique is not as simple as minification and using it should be examined carefully as bugs are likely to appear because of core function name substitution.

4) Gzipping content

One last technique worth mentioning is to use gzip compression. The use of this technique is pretty obvious. Compression reduces download sizes leading to faster downstreaming times for the client. Gzipping is supported by almost all modern browsers so it doesn’t need further browser compatibility thoughts. This technique is more effective when combined with the others described. Minification combined with gzip compression decreases significantly the size of the content. To use it though the web server should be configured properly.

Last but not least few simple things to look after are: avoiding duplicate script inclusion, loading stylesheets at the beginning of the document, scripts at the bottom and sometimes clever content preloading that will be needed later on, while the user is interacting with other parts of the page.

jQuery Style Rules

June 12th, 2008

In Excalibur Phoenix a really powerful JavaScript library is used, jQuery. It allows developers to create JavaScript code fast, using only a few lines, and also offers a great variety of features that make coding life easier. jQuery code, though, doesn’t have many similarities with regular JavaScript DOM code. This post contains a few suggestions about how Kamibu developers should write jQuery code. Before you start reading this post, please take a quick look on this
article
, since those style rules should be also applied whenever possible.

1) jQuery allows developers to execute more than one jQuery class methods using a technique called method chaining. Method Chaining should be used to the maximum by Kamibu developers.

Do not use this:

$( "div.newcomment" ).clone( true );
$( "div.newcomment" ).css( "opacity", 0 ).removeClass( "newcomment" );

Use this instead:
$( "div.newcomment" ).clone( true ).css( "opacity", 0 ).removeClass( "newcomment" );

The first example is not as fast as the second, since two DOM searches are performed.

2) Sometimes, however, chaining makes the code complex and difficult to read, especially when find() is used a lot of times. Therefore, when end() is used, the developer should change a line exactly after it.

Do not use this:

$( "div.comments" ).find( "span.time" ).text( "πριν λίγο" ).end().find( "div.text" ).empty().append( document.createTextNode( texter ) ).end();

Use this instead:
$( "div.comments" ).find( "span.time" ).text( "πριν λίγο" ).end()
.find( "div.text" ).empty().append( document.createTextNode( texter ) ).end();

3) This new JavaScript library provides a lot of ways to select a DOM node, apart from getElementById and getElementsByTagName. You should always use jQuery selectors, before trying to find another way to select the node you want.

Do not use this:

var node = $( "div.comments" ).get( 0 );
node = node.childNodes[ node.childNodes.length-1 ];

Use this instead:
var node = $( "div.comments:last-child" ).get( 0 );

And do not use this:

var node = $( "div.comments" ).eq( 0 );

Use this instead:
var node = $( "div.comments:first" );

4) Even though selectors could become really long, do not break them into parts, unless you have a good reason to do so.

Do not use this:

$( "#dilution div.comments div.text" ).find( "div div:last-child" );

Use this instead:
$( "#dilution div.comments div.text div div:last-child" );

5) When you want to create a node and append it to an element do not use jQuery’s append method using a string as an argument. Firstly, create the element you want using DOM JavaScript, and then append it to the node you want. This solution should be preffered since it is more object-oriented. Use jQuery’s append( “string” ) only when you would use innerHTML in normal DOM

Do not use this:

$( "div.bottom" ).append( "<a href='http://www.zino.gr'>Click Me</a>" );

Use this instead:
var a = document.createElement( 'a' );
a.href = "http://www.zino.gr";
a.appendChild( document.createTextNode( 'Click Me' ) );
$( "div.bottom" ).append( a );

6) Always try to use jQuery’s characteristics as much as you can, before you try to find another “manual” way. A characteristic example is jQuery’s toggleClass method.

7) Always prefer jQuery’s events except for the following situations.
7.1 When a DOM element that will be appended is going to be bound to an event.
7.2 When an argument from backend is going to be used.
You should use this:

<?php
				$foo = 5;
			?><a onclick="function() { alert( <?php
			echo $foo;
			?> );return false;" >Test</a>

7.3 When an event that was not bounded by jQuery is going to be replaced.
Do not use this:
var a = document.createElement( 'a' );
		a.onclick = function() { 
			alert( 'lolek' ); 
		};
		$(a).click( function() { alert( 'bolek' ); } );

Use this instead:
var a = document.createElement( 'a' );
		a.onclick = function() { 
			alert( 'lolek' ); 
		};
		a.onclick = function() {
			alert( 'bolek' );
		};

Notice: Keep in mind that jQuery supports multiple events. The first example, will just add another function to be executed when a is clicked. So two alerts will pop up (lolek,bolek). Moreover, the unbind method cannot be used since the first event was not bounded using jQuery.

8 ) Use fadeIn, fadeOut, fadeTo, show, hide methods, instead of the more general animate method, whenever possible.

Do not use this:

$( 'chiki' ).animate( { opacity : 0 }, 400 );

Use this instead:
$( 'chiki' ).fadeOut( 400 );

9) Prefer jQuery’s methods instead of the body’s onload event.

Do not use this:

<body onload="alert( 'done' );"></body>

Use this instead:
$(document).ready(function(){
		alert( 'done' );
	} );

Moreover,
Do not use this:

$(function() {
		alert( 'done' );
	} );

Use this instead:
$(document).ready(function(){
		alert( 'done' );
	} );

Notice: Use “jQuery(function($) {” format only when absolutely necessary

10) Always prefer $( ‘something’ ) instead of jQuery( ‘something’ ), unless a compatibility issue emerges.

11) Kamibu Specific:
11.1 Use jQuery’s effects instead of the objects of animation.js
Do not use this:

Animations.Create( document.getElementById( 'fire' ) , 'opacity' , 2000 , 1 , 0.3 );

Use this instead:
$( '#fire' ).css( 'opacity', 1 ).fadeTo( 2000, 0.3 );

11.2 Prefer Coala instead of jQuery.ajax

Which “false” is it?

May 27th, 2008

dionyziz@turing ~ $ cat test.php
<?php
    class false {
    }
 
    $c = New false();
    echo get_class( $c );
?>
 
dionyziz@turing ~ $ php test.php
false
dionyziz@turing ~ $

Change collation on all columns of a database

May 25th, 2008

It was recently required for me to change the collation of each and every column of every table in a database from ‘latin1′ to ‘utf8′. Although the table collations were correct, the column collations were incorrect. It’s a cumbersome process to perform manually, and there’s apparently no real automated way to do it without a script. Although collation information is only meta-data, not actual data, I found this problem interesting.

Changing one column collation information is easy enough to do with one MySQL query:

ALTER TABLE `moods` 
CHANGE `mood_label` `mood_label` text CHARACTER SET utf8 COLLATE utf8_unicode_ci;

Changing all the columns is more difficult. Here’s a small script that I came up with to do it recently:

dionyziz@orion:~$ mysqldump -u root --password=1234 \ 
--no-data --no-create-db --compact ccbeta \
|egrep 'CREATE TABLE|latin1' \
|sed 's/CREATE TABLE `\(.*\)` (/;ALTER TABLE `\1`/' \
|sed 's/character set latin1/CHARACTER SET utf8 COLLATE utf8_unicode_ci/' \
|sed 's/  `\(.*\)`/ CHANGE `\1` `\1`/'>columns
dionyziz@orion:~$ php -r 'file_put_contents( "columns", 
    preg_replace( "#^;|ALTER TABLE `.*`(\\s*;|$)#", "", 
    preg_replace( "#,(\\s*);#", ";\\1", 
    file_get_contents( "columns" ) ) ) );'
dionyziz@orion:~$ mysql -u root --password=1234 ccbeta <columns

Let’s go through it step-by-step.

mysqldump -u root --password=1234 --no-data --no-create-db --compact ccbeta

This creates a list of CREATE TABLE statements for all our tables. That’s good because it’ll allow us to determine whether the collation of a column is incorrect. Here’s an example CREATE TABLE statement:

CREATE TABLE `albums` (
  `album_id` int(11) NOT NULL auto_increment,
  `album_userid` int(11) NOT NULL default '0',
  `album_created` datetime NOT NULL default '0000-00-00 00:00:00',
  `album_name` text character set latin1 NOT NULL,
  `album_description` text character set latin1 NOT NULL,
  PRIMARY KEY  (`album_id`),
  KEY `album_userid` (`album_userid` )
) ENGINE=MyISAM AUTO_INCREMENT=55 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

In this example, the `album_name` and `album_description` columns are wrong and need their collations changed.

egrep 'CREATE TABLE|latin1'

This simple line limits our results to only lines that contain “CREATE TABLE” or “latin1″. That’s useful since it’ll only show the table names followed by a list of all incorrectly collated columns, if any. The result would be something like this:

CREATE TABLE `relations` (
CREATE TABLE `searches` (
 `search_query` text character set latin1 NOT NULL,
CREATE TABLE `shoutbox` (
 `shout_text` text character set latin1 NOT NULL,
 `shout_delreason` text character set latin1 NOT NULL,

(with more entries potentially)

Good. Now all we need to do is modify these lines to make them ALTER TABLE lines:

sed 's/CREATE TABLE `\(.*\)` (/;ALTER TABLE `\1`/'

Ah, the magic of regular expressions. This removes the final “(” of every CREATE TABLE line, as we don’t need it and also changes the word “CREATE” into “ALTER”. It also adds a semicolon in front of the ALTER TABLE statement (to terminate the previous statement).

sed 's/character set latin1/CHARACTER SET utf8 COLLATE utf8_unicode_ci/'

Straightforward enough, this replaces the existing character set instruction from latin1 to utf8, and adds the correct collation as well.

sed 's/  `\(.*\)`/ CHANGE `\1` `\1`/'

Finally, this adds the word “CHANGE” in front of every column line and repeats the column name (as we want to tell MySQL which column to change (first repetition) and to which to change it (second repetition)). The result is:

;ALTER TABLE `relations`
;ALTER TABLE `searches`
 CHANGE `search_query` text CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,
;ALTER TABLE `shoutbox`
 CHANGE `shout_text` text CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,
 CHANGE `shout_delreason` text CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,

Pretty close to what we actually want. You’ll notice three problems:

  • There are empty ALTER statements
  • There’s an extra comma at the end of every column (providing all your tables have a primary key, as they should)
  • There’s a redundant semicolon at the beginning

These problems cannot easily be fixed by sed because sed performs a line-to-line processing. A sed expert might have been able to provide us with a better solution, but I’ll prefer to use the PREG feature of PHP. To use PHP, first let’s save our current result into a file:

>columns

Time to run our PHP code on the target file:

php -r 'file_put_contents( "columns", 
    preg_replace( "#^;|ALTER TABLE `.*`(\\s*;|$)#", "", 
    preg_replace( "#,(\\s*);#", ";\\1", 
    file_get_contents( "columns" ) ) ) );'

Let’s analyze it in short.

file_get_contents( "columns" );

This, simply enough, reads the “columns” file into memory. Now we’ll perform two regular expression replacements:

First, we’ll match the following regular expression:

#,(\s*);# 

(notice that the # are separators that wrap the regular expression for clarity — they aren’t part of the actual regular expression)

Anything matching this will be replaced by ;\1. This means that a comma followed by any whitespace (including a new line) followed by a semicolon will be replaced by only a semicolon (and the same whitespace). This simply removes the redundant comma at the end of every ALTER statement.

Second, we’ll match the following:

#^;|ALTER TABLE `.*`(\\s*;|$)# 

Anything matching will be removed. You’ll notice that this regular expression matches basically two things (separated by the first alternation (pipe) character).

The first part is:

#^;# 

It’ll remove the first line if it only contains a single semicolon (which it does in our example).

The second part is:

#ALTER TABLE `.*`(\\s*;|$)# 

This will look for empty ALTER TABLE statements (an ALTER TABLE statement followed only by whitespace and a semicolon or an end-of-file) and remove them.

Finally, we’ll write the result back to the file we read from:

file_put_contents( "columns", ... );

Now if we cat that file we’ll see that it contains all ALTER statements in the form we want them:

ALTER TABLE `searches`
 CHANGE `search_query` `search_query` text CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL;
ALTER TABLE `shoutbox`
 CHANGE `shout_text` `shout_text` text CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,
 CHANGE `shout_delreason` `shout_delreason` text CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL;

Excellent. Finally, let’s execute it:

mysql -u root --password=1234 ccbeta <columns

You can also add ‘time’ in front of it to measure how long it’ll take. We can now validate that the collations were changed successfully by, again, performing our initial dump and grepping for ‘latin1′ to confirm that there are none.

Accessing MySQL using a SSH-Tunnel

May 21st, 2008

Due to security aspects MySQL server often only listen on localhost and accessing them remotely is not possible. With a simple trick you can access them with your favourite tool aswell.

ssh -l login_name -N -L [bind_address:]port:host:hostport remoteServer

login_name is your username on the remote machine
bind_address is the local interface’s address where the tunnel should bind to
port is the local port the tunnel should bind to
host is the remote host to which you want to connect
hostport is the remote port to which you want to connect
remoteServer is the server using which you want to etablish the tunnel
-N should disable starting the login shell

So for creating a tunnel for MySQL the command looks like this:

ssh -l user-remote -N -L 123456:localhost:3306 remoteServer

This create a tunnel to MySQL running on remoteServer. You are able to access MySQL on port 123456 on localhost. For example you can use the following command:

mysql --port=123456 -h 127.0.0.1 --user=mysqlUser --password=mysqlPassword database

How to change your standard editor

April 13th, 2008

Everyone who is using linux knows that if you type editor in a bash shell an editor opens. But where can you change that editor?

Change the editor temporarily

Just execute the following on your shell:

export EDITOR=joe

Change the editor forever

Edit ~/.bash_profile and add the following:

export EDITOR=joe

Zino Phoenix mockups

April 10th, 2008

A sneak preview of the new Zino version!

Userprofile

Frontpage

Increasing method visibility through extension

March 16th, 2008

Although it’s nothing superspecial, I wanted to illustrate how it is possible to modify the visibility of a parent class method when extending it, to convert it from ‘protected’ to ‘public’. Assume we have a base class which exposes a protected function called ‘Test’. We want to extend the class and make that function public in our extension. Here’s how:

<?php
    class Fred {
        protected function Test() {
            ?>Boo!<?php
        }
    }
 
    class Barney extends Fred {
        public function Test() {
            parent::Test();
        }
    }
 
    $barney = New Barney();
    $barney->Test();
?>

Notice that $barney->Test() is a public method call. It’s also possible to disallow this kind of behavior from the parent’s perspective by declaring a method as final. This way it can no longer be overridden (including its visibility):

<?php
    class Fred {
        final protected function Test() {
            ?>Boo!<?php
        }
    }
?>

Fighting against DDoS

March 12th, 2008

The last week we had some downtimes due to a distributed denial-of-service attack. I’m not sure if it was directly related to our Kamibu projects because there is a bug in the current lighttpd version. An attack can cause a bufferoverflow of Lighttpd with a DDoS. So at all someone tried to get our sites down.

Our solution is very easy. We created a little script fetching all connections by using netstat, counting the number of connections per IP and if there are more than x connections from a certain IP it will add the IP to our firewall. Very simple but helpfull. We execute the script periodically to stop a possible DDoS.