@ operator is slow

21 June, 2009 (09:44)

The @ “operator” in PHP is used to silence any warnings or errors that would otherwise be shown (in the browser or the log). It’s really useful, because sometimes you know you can safely ignore a warning or error, when checking if a GET variable is set for instance. Until today I though that, if used properly and with caution, the @ operator can be freely used. Then I read this article. I really had no idea that PHP is doing so much work behind the scenes to make @ work.
When PHP comes to a statement, that contains the @ operator, it changes error reporting to none and then back, which translates to a trip to the php.ini file.
So after I stopped scratching my head and thinking “why the bloody hell would one do that like so?”, I opened my PHP editor and wrote this simple test to see just how much of a difference this makes. It’s the most common scenario where you check if a GET variable has any content.
First the version with @:

for ( $i = 0; $i < 1000000; $i++ ) {
	if ( @$_GET['var'] != '' )
		echo 'foo';
}

And the version without @:

for ( $i = 0; $i < 1000000; $i++ ) {
	if ( IsSet ( $_GET['var'] ) && $_GET['var'] != '' )
		echo 'foo';
}

I timed the execution of both snippets and here are the results:

  @ version IsSet version
1 1.52496409416 0.196986913681
2 1.48627185822 0.204479932785
3 1.52267694473 0.206820964813
4 1.51263594627 0.207319021225
5 1.49150109291 0.199639081955
6 1.48829102516 0.174983978271
7 1.54369091988 0.206038951874
8 1.52254199982 0.204971075058
9 1.50641703606 0.190815925598
10 1.51343107224 0.203064918518
sum: 15.11242198945 1.995120763778
avg: 1.511242198945 0.1995120763778

The IsSet version is about 7.5 times faster, really amazing. I don’t use @ as often as I used to, but I will now try to reduce it to zero. You should do the same.

Aliiike recommendation engine

16 June, 2009 (19:21)

We updated igre123.com today and one of the main new features is the recommended games you see on the right of the game you are playing:

recommended games

You may not see this if you go see for yourself. Either you are viewing a game that hasn’t got enough data collected to show the recommendations or you are one of the “lucky” 20% of users who don’t see the recommendations (we are comparing how well this new feature influences bounce rate, time on page, …).

We are using the Aliiike recommender system which is a breeze to use and gives fantastic results. We simply couldn’t offer better recommendations based on search because games rarely have title or description that would overlap (we have yet to test this on mojvideo.com where this isn’t such a big problem). And if you look at the above picture, showing a bejeweled like game, you can see that recommended games are really related (most of the games are of the same type or are puzzle games).

When you install Aliiike you are simply putting a simple JavaScript tracking code (kinda like google’s analytics) into your product page (product being anything you want, aliiike doesn’t care what it is tracking) which logs how your users move from one product to another (it does that by logging the URL of the product). And then you wait a week or two for the data to collect (you get better and faster results on high traffic web pages as there is more clicks to analyze).

After Aliiike has enough data you can start showing recommendations. There are various ways how you can do that, but all is explained on this page, so I won’t go into any details.

We grab a fresh file with analyzed data every day and store the recommendations into the database, but you could opt for a simpler approach with AJAX for instance.

Anonymous paradise

11 June, 2009 (15:57)

Google’s gmail is great; I can’t imagine working with email without it. Unfortunately, as with everything, there are some issues with it.

Did you know that the following email addresses all “translate” to the same account: not.a.real.email@gmail.com,notarealemail@gmail.com, not.arealemail@gmail.com, n.o.t.a.r.e.a.l.e.m.a.i.il@gmailcom, … ?

This is great, because who could remember where the dots are when somebody tells you his email? But this also means that a user can register on your site using one email multiple times (how many times depends on the length of his email), because he can just randomly rearrange the dots and voila a valid unused email.

So this is really anonymous paradise as he can register countless times (if you ban him for instance) without going trough the hassle of setting up a new email account. I don’t know if other mainstream email providers also have this “feature”.

So the obvious solution would be to remove all the dots when a user registers/signs in using a gmail email, but that could cause some problems later on. What if Google suddenly drops this “feature”? You would wind up with a whole bunch of problems.

I think that a better solution is to store the dot less email into some table when you ban a user. And then at registration you check the email, the user is wishing to register with, against this table (stripping dots off course). This way annoying anonymous users get to use his email only once.

php konferenca 2009

6 June, 2009 (18:15)

This year’s Slovenian PHP conference just finished. This was the second installment of the only PHP event here in Slovenia. It’s a shame I wasn’t there last year so I can’t compare. Overall I was really impressed with everything, all but two talks ware magnificent. Guys from videolectures.net have recorded the whole thing so you will be able to see the conference if you weren’t able to make it.

PHP konferenca 2009

Below are my opinions on the lectures:

Delavnica: OpenID, OAuth in Najdi.si Prijava (Workshop: OpenID, OAuth and najdi.si login):
This workshop showed me that OpenID isn’t that hard to implement (few API calls and you are done). The user experience bugs me (Facebook Connect wins here) and I don’t se mass adoption anytime soon, especially because, apparently, many OpenID enabled web pages are making a white list of OpenID providers that they accept logins from. Najdi.si made their own OpenID provider but they are not really helping with educating users what OpenID with their own custom name.

Delavnica: Varnost in PHP (Workshop: Security in PHP):
Really great workshop, Gašper Kozak walked us trough all the major security issues we, developers, should take care of. Most of the stuff he sowed was known to me and I’ve got them covered in my code, but there were still some things I just stared with my mouth opened. I will address those issues first thing on Monday. Gašper was also kind enough to point some security flaws in my code (he still has to give me details).

Predavanje: PHP brez brskalnika (Lecture: PHP without the browser):
This lecture was about PHP CLI and it showed me some new tricks to use. It also showed me how to do multi-threading properly (something I’m struggling with for quite some time now). Great lecture!

Delavnica: Izdelava Facebook aplikacij in uporaba Facebook Connecta (Workshop: creating Facebook apps with Facebook Connect):
Here we learned how to build Facebook applications and I learned that this really isn’t all that difficult. You build the application just like you are used to, the difference is only that you ask the Facebook API, instead of db for example, for users data. Great!

Predavanje: 10 koščkov kode, ki so mi olajšali življenje (Lecture: 10 code snippets that made my life easier):
Unfortunately I overslept (this lecture was the first of the second day) so I missed half of this lecture. But judging from what I saw it was pretty much useless. Marko Štamcar was showing us some code that would be acceptable for a rookie programmer or would have it’s place 10 years ago.

Predavanje: Keširanje dinamičnih vsebin (Lecture: caching of dynamic content):
One of my favorite lectures, Miha Hribar of 3fs (who was the main sponsor btw) talked about memcache. It was really interesting as we plan on implementing it in the near future and I learned quite allot about how to do this. Very handy!

Predavanje: PHP+Flash=RIA (Lecture: PHP+FLASH=RIA):
Anže Žnidaršič (organizer of the conference) was this lectures speaker. Although I’m not planning on using this anytime soon the talk was interesting as it showed us that there are alternatives to writing PHP applications the “regular” way. Basically the development is very much like ASP.NET if you use flash.

Predavanje: Real-time web (Comet) (Lecture: real time web with Comet):
We are planning on doing a something that will require us to use Comet so this lecture was really helpful. I learned all the missing pieces so I can now dive in and implement the feature (can’t say what it is just yet). There are allot of problems with using Comet (which is just a bunch of technologies wrapped in a common name, just like AJAX) on the client side, but fortunately there are libraries that deal with those problems. The best part is that it works in all mainstream browsers including IE6!

Predavanje: Spletne aplikacije na namizju (Lecture: web applications on the desktop):
Anže already scratched the surface in his lecture but Swizec gave us a in-depth look at Adobe AIR and how to use it. It looks like a nice platform. I only wish he would compare it to Silverlight to give more perspective on the technology.

Predavanje: CodeIgniter PHP Framework (Lecture: CodeIgniter PHP framework):
I hate to say this, but this was the worst lecture of the conference. Tomaž Muraus talked about CodeIgniter but instead of showing us how to do a real web page in it, he basically walked us trough the manual which I can do by myself.

Like I said I’m very pleased with the conference and I’m looking forward to the next one. Maybe I’ll even man up and prepare a lecture/workshop of my own.
I’ve also meat a lot of my fellow php-si.com users and it’s always nice to put a face to a nickname. Really great getting to know you all!

IE6 is dead … over the weekend

4 June, 2009 (21:28)

Every time I’m writing new HTML&CSS I check google analytics to see what browsers our users are using. I do this so I can determine what browsers must be supported and if Internet Explorer 6 is, by any chance, dead yet. This is, annoyingly, still not the case (I shall be very drunk when that day comes). IE6 still has, on one of our web pages, 47.30% share between different IE versions (IE7 trails it closely with 47,06%). Overall IE holds a 48.54% share, Firefox is second with 47,09% and Chrome is third with 1,90%.
So no surprises here, except maybe for Chrome which beats Opera and Safari. The power of Google brand is amazing.

What I did find interesting is how IE6&7 share changes during the week. On weekends IE7 has a bigger share then IE6, whereas during the week IE6 leads. And here lies the main problem why IE6 is still hanging around. You see, most of IE6 users come from various government agencies and departments (ministries, schools, town halls, …) and big companies. They usually don’t upgrade because they use custom web applications that refuse to work on anything else other than IE6. The other main reason is that system administrators (in companies mostly) can’t justify the upgrade to the bosses or are just plain ignorant and don’t bother. So that is why IE7 gains, although slightly, over IE6 during the weekend, because users who surf the internet during work with IE6 go home and use something more modern.

This disturbs me greatly, because I don’t know how this will change anytime soon and we, webmasters, will have to support IE6 (if we don’t want to loose customers that is) for a long time.
Off course there are other reasons for this mess we are in. Most users are regular Joe’s who haven’t got a clue about computers and they usually don’t even know they are using a browser, they just “surf the web”, so we can’t expect them to upgrade anytime soon. How could they? They don’t even know that there is something wrong with what they are using. And Microsoft is to blame here. They ware simply not aggressive enough when they released IE7, they should have pushed IE7 as a critical update that would install automatically without user intervention (they could exclude companies from this so that sys admins could confirm the install) and they should have launched a broader media campaign, like they are doing now with IE8.

Stop IE6

Facebook like rounded images

31 May, 2009 (09:30)

We are currently renewing Igre123 with a wider design to accommodate the new standard web resolution. Somewhere along the way, we decided that it would be nifty if user’s avatars would be rounded like on Facebook:

I thought the task would be difficult at first, but after I tossed some CSS around, I found out that this is not the case.
In a nutshell: you have a regular rectangular image and then you make another (overlay) image that you put on-top of the first image. The overlay image is mostly transparent and only has white corners that make the curved border (those hide the corners of the first image).
I’ve made this demo page where you can see how one can accomplish this (I used ugly images just for the sake of demonstration). You’ll notice that there are two examples. The first one uses one overlay image which has corners both on top and on the bottom. Use this if you know the dimensions of the image being rounded (as the overlay must match it’s dimensions).
The second example uses two overlay images, one for the top and one for the bottom. I use this one, as our user’s avatars have a variable height (but fixed width). The only problem here was IE6, that’s why there is a height property on the container span. Without that IE6 puts the bottom overlay at the bottom of the page and not at the bottom of the image.

The Invisible Man

20 May, 2009 (20:59)

If you have a web page such as YouTube or Mojvideo, where the sole reason for a pages success is user generated content and the quantity (and quality off course) of it, it’s easy to forget about the users who don’t contribute to the content of the page. We (at Popcom) spent most of the time developing and improving features for registered users, which isn’t bad per se, but unregistered users (who account for the majority of visitors) usually don’t gain anything from that. Mostly because you have to be signed in to see the new feature. The problem is that usually there is no easy or unobtrusive way to advertise that feature to unregistered users.

So, the goal of any page maintainer should be to evenly spread his time between developing features for registered and unregistered users. The real trick is, off course, making some feature for unregistered users which will convert them into registered users.

The rage

13 May, 2009 (23:11)

Another common usability mistake most make, is the step after a user signs into a web page. Most web pages will redirect a user to the front page or his profile page, which is fine if he is signing in from the front page. But most commonly a user will sign in when he is forced to do so, when he tries to leave a comment for instance:

loginThe text translates as “Sign in, if you want to comment, rate or add the game to your favorites”. Upon clicking the link, a user would then be presented with sign in page. So far so good. The problem arises (on most web pages) when a user successfully signs in. Instead of redirecting him back to the page where he was, when he clicked on the sign in link, he is instead taken to the front page. Now the user must navigate his way back to where he was, loosing his interest in leaving the comment along the way …
I’m stating the obvious now, but the correct way is to redirect the user back to the page, where he can do whatever he was unable while not signed in.

And implementing this is really easy, that is why it’s even more strange that there are so many web pages without this “feature”. All you have to do is append the current URL to the sign in page (signin.php?ReturnTo=current_url for instance) and then do a simple HTTP redirect after the sign in.

The image above is taken from our web page igre123.com, where we don’t annoy our users :)

Generate sitemap(s) with PHP

9 May, 2009 (14:45)

Sitemaps are XML files that help web crawlers (google, yahoo, …) get to know your web page better. The sitemap file contains information about when a web page or sub page was last modified, how often it is updated, etc.
It also includes a “priority” information which tells the crawler how important is one page in comparison with other web pages on the same domain. I won’t go into any details here as you can read all about sitemaps here.

Since I don’t want to edit the sitemap files by hand I’ve written a simple PHP5 class that generates the sitemap(s) on my behalf. On videoarhiv.com, for example, I generate the sitemaps when a crawler that fetches new videos is run.
Now since most of the web pages I work on have many sub pages, my class splits the entries into multiple sitemap files (there is a limit of 50000 entries per sitemap file, and it can’t exceed the 10MB file size) and then generates a sitemap index file that contains the URLs to site maps.
This class was constructed with my demands in mind, so you may have to tweak it to suit your needs. For instance, I only store 40000 (which is hard coded) entries per sitemaps as to respect the 10MB file size limit.
You may have to change this, depending on the type of URLs you have (if you have very short URLs, you can increase this number for instance).

Source code of the class can be found here.

And here is a short example of how to use it:

Include ( '/path/to/SiteMap.class.php' );
// change to SiteMap::WRITE_GZIP to compress the sitemaps
$sm = new SiteMap ( '/path/to/sitemaps/', 'http://www.yourdomain.com/sitemaps/', SiteMap::WRITE_PLAIN ); 

$data= Array ();
$data[] = new SiteMapItem ( 'http://www.yourdomain.com/', Date ( 'c' ), SiteMap::CHANGE_HOURLY, '0.9' );
$data[] = new SiteMapItem ( 'http://www.yourdomain.com/about', Date ( 'c' ), SiteMap::CHANGE_MONTHLY, '1.0' );
// add all your sub pages like above

// this will generate your sitemap(s) and store them on the location you specified in the SiteMap constructor
$sm->Generate ( $data);

Another One Bites the Dust

8 May, 2009 (17:15)

I like talking about usability, so today I’ll talk about another easy way to improve your web page. There are many web pages which use AJAX to post the contents of a form back to the server. The problem is that most of them don’t act as regular forms, where you can hit enter on your keyboard and submit the form.
The problem is that most developers use a type=”button” instead of the type=”submit” button in their AJAX forms, so you have to click on the button to submit the form. The problem with using a type=”submit” button in AJAX forms is that the browser will submit the form the regular way.

And this, off course, can be easily fixed. You already have a JavaScript function that your type=”button” button calls when clicked. All you have to do is change the type=”button” to type=”submit”, return false from the function that does the AJAX request and then you define a “onsubmit” event for your form.

Example:

<script type=”text/javascript”>
function SaveFormData () {
// validate the form and send a AJAX request
return false;
}
</script>
<form method=”post” action=”" onsubmit=”return SaveFormData ();”>
your form elements
<input type=”submit” name=”btnSubmit” value=”Save” />
</form>

And that’s it. Off course you should attach the “onsubmit” event via JavaScript not in-line like in the example.