@andrewgerssen Thanks for your info! I will take a look when I have time - on a business trip now.

Follow me

Write your own URL shortener

With Twitter and its 140 characters limit leading all the trends, URL shortening services are in extreme high demand. We have seen TinyURL in the past, now Bit.ly, Is.gd, Tr.im and dozens of others are joining the party to share the cake. Honestly saying, to me they’re all the same (except for ➡.ws for its cool name). With that being said however, it is interesting how they are doing it out there - what mechanism / algorithm / buzzword-here?

I curiously did some “research”es (well, another buzzword), and it seems in order to create the shorten URLs they are following the same steps:

  1. Insert the original (long) URL into the database
  2. Get the insert ID. If the URL already exists, take its row ID. Let’s say we got 123456.
  3. Convert the ID 123456 into something even shorter, let’s say “am4k”
  4. Make use of Apache’s mod_rewrite so that any request to http://host.com/am4k will reach http://host.com/redir_script.php?code=am4k instead.
  5. In redir_script.php the value “am4k” is converted back into base10’s 123456 and the corresponding URL is queried back from database
  6. If a URL is found, redirect the request to it.

It is simple enough… except for step 3 and 4. Which conversation is needed, and how is the .htaccess written?

So I did some other buzzword-here, and it turned out base36 encoding is taking place. According to Wikipedia, “the choice of 36 is convenient in that the digits can be represented using the Arabic numerals 0-9 and the Latin letters A-Z”. There is a handy conversation table too:

Decimal 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
Base 36 0 1 2 3 4 5 6 7 8 9 A B C D E F G H
Decimal 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
Base 36 I J K L M N O P Q R S T U V W X Y Z

Even better, PHP takes only one line of code to convert between decimal and base36, as shown on the same Wiki page:

1
2
3
4
$base_36 = "ZAQFG"; //Sample Base 36 Number
$decimal = "7654321"; //Sample Decimal Number
echo base_convert($base_36,36,10); //Outputs $base_36 converted to decimal
echo base_convert($decimal,10,36); //Outputs $decimal converted to base 36

In our example, 123456 will be converted into its tidy equivalent base36 2n9c (not am4k, my very bad).

As for the mod_rewrite thing, as I am not a .htaccess master, I copied this thing that has been working perfectly so far from CodeIgniter forum:

1
2
3
4
5
6
7
8
9
10
RewriteEngine On
RewriteBase /
 
#Checks to see if the user is attempting to access a valid file,
#such as an image or css document, if this isn't true it sends the
#request to redir.php.
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ redir.php?code=$1 [L]
 

With this, all of the hardest parts are done, leave the remains being simple MySQL database, queries and HTML form handling. To save you from getting boring, I’ll omit it.

Instead, let’s see a demo here.

The source code of the demo are can be downloaded from the same server.

Referrer Detector 4.2.0.1 (and the IE pain)

Referrer Detector 4.2.0.1 (and the IE pain)

On May 12 I managed to release the latest major version of Referrer Detector. As it was a complete rewritten, bugs are not a doubt expected. Since then, there has been 5 newer versions:

  • 4.0.1 - A hot fix to for allow_call_time_pass_reference problem. As for version 5, PHP passes function parameters by reference by default, thus eliminate the need of the prefix &. This shouldn’t be anything big, if it didn’t generate a warning with any attempt to use & and totally break my JavaScript’s eval().
  • 4.0.2 - Some other hot fixes.
  • 4.1.0 - “Related posts” feature implemented, and a tiny “Powered by Referrer Detector” line added into the welcome div. If you mind, both options can be turned off via Options panel - one-click. Also, the CSS was nearly completely changed.
  • 4.1.0.1 - I accidentally (and stupidly) uploaded some 4.0.2 code in place of 4.1.0, and EVERYTHING was broken. This version is actually a quick roll-back, so the features were exactly the same with 4.0.2 - oops.
  • 4.1.1 - This IS 4.1.0 :D

So today I would like to announce the release of Referrer Detector 4.2.0.1 (code name: IE-PAIN). For this version we have another option on how to display the welcome box - in light box style. This is not a joke: I saw the light box in action in my dream, and started to implement it right when I woke up, basing on SimpleModal. Mendeleev’s style, haha. Actually I’m not sure if this welcome style fits normal needs, but for advertisements it seems to. At least it has some cool effects.

If you wonder about its cool code name, here you go:

  • First, version 4.1.1 has a serious bug (or is it IE?) which cause the whole admin panel to stop functioning. IE informally and informatively told me that at line 303, column 13, page ?rd.class.php there was a serious “Expected identifier, string or number” error. Actually it was a </tr> closing tag there… but I had some experience with it already: must be an extra comma in a JavaScript array. The problem is, I have like thousands of JavaScript lines within this plugin, and so it took me one hour for a single comma. Thank you, IE, for the extra headache!
  • Then, I spent almost 2 hours to beautify the CSS. Everything was perfect, until I switched to IE. Then, I spent almost 2 hours more to beautify THE CSS on IE. Everything was perfect, until I switched back to Firefox. Then, I reverted back my files, and gave up, and went to sleep. Everything was perfect - damn it.
  • After the CSS is ok on all major browsers, the welcome box disappeared on IE. Just the same eval() code worked on Firefox and all others! I tried execScripts(), I tried jQuery plugins, I tried alert(), I tried document.write() - hopelessly. PHP returned the correct string, Base64 plugin decoded it with no hassle, but IE failed to properly insert it into DOM. Stupid. One more night, and I discovered that in some Ajax circumstances, $(”element”).replaceWith(html) doesn’t work in IE. Stupid. When $(”element”).after(html).remove() does. Stupid.
  • Troubles wouldn’t stop there. The message eventually showed up - kind of. It was there, but not visible. If the mouse was hovering a link - the line appeared. Moused out, and it’s gone. Have you ever imagined that? Do you have any clue why CSS display: inline fixed it? I’ve no idea.

If it wasn’t IE, I would have released this new version 3 days ago. So I say (sorry, parental control recommended): Curse you, IE, go die pig!

Almost forgot it: nevertheless, Referrer Detector 4.2.0.1 is here, that’s what important ;)

Referrer Detector 4.0 is out!

Referrer Detector 4.0 is out!

Finally I’ve made it! Referrer Detector version 4.0 is now out! I decided to mark this as a major version increment because of these reasons:

  1. The code has been COMPLETELY re-written from scratch. As of the previous versions, it was one big file that handled everything from admin to front-end control. Needless to say how inconvenient this approach had become when bug fixes and new features were added… too bad that I have decided to throw all away and build a brand new OOP Referrer Detector. Well, it was a looong and tough way, but I’ve never looked back!
  2. The data are now in (ahem) database. I was thinking (and convincing myself) that a JavaScript file is faster, as it reduces the number of database requests. But with time, it becomes too bloat and too hard for me to track bugs as well as to add improvements. So I told myself: hell with this sacrifice, I better obey the power of MySQL.
  3. The biggest new feature that I’m really excited of is the ability to add localized messages. In the past, your users were welcomed the the same (English) greetings regardless of which country they were from. Now you can specify a localized message for those from Vietnam, another for Brazilians, Portuguese, and so on. The plugin will try to detect users’ country and decide which message to show. Isn’t it cool?
  4. The second new feature is the ability to backup and restore stuffs, including entries, excluded URLs, and options. For restoring, in order to keep the administration panel AJAX’ed, I go with Uploadify, a wonderful jQuery file upload plugin. This plugin uses a bit of Flash, but no worries, it will still works if your browser has no Flash player installed.
  5. For the Stats panel, there were two problems that caused me much of headache. One is Google TLDs which are hundreds in number thus totally ruined the chart. The other is the chart itself: PHP/SWF Charts library is too darn heavy and often broke my SVN commits. So I wrote some code to group those annoying TLDs into one group, and use Google Chart instead.
  6. In the admin panel, I added a “Support this plugin!” tab. Just a bit about myself, like “Follow me on Twitter”. Hope you aren’t pissed of with this change.

As usual, the plugin is downloadable at WordPress Codex. Your comments are always welcome here and in the plugin page. Let me know if you’re happy with the new version, or about the bugs you encounter!

Code snippet #2 - Shorten Links Using Bit.ly

Code snippet #2 - Shorten Links Using Bit.ly

Following the first snippet, here is another small one to shorten a link using Bit.ly. I chose Bit.ly over other link shortening services due to a simple reason: Twitter uses it as default (by now).

Code snippet #1 - Shorten Links Using Bit.ly

Purpose

Create a shortened URL using Bit.ly. This is extremely useful for your visitors, as they don’t have to look any further - just grab it to use right away.

Requirements

  • A Bit.ly account (and API key). You can create one for free at their site in seconds. Once logged in, head to Account section and look for a long ugly string starting with “R_”.
  • PHP 5 >= 5.2.0. Your host doesn’t support PHP 5? Claim your money back and find another host.

The Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
function get_shortened_url($url)
{
    $bitly_api_key = 'YOUR KEY HERE';
    $bitly_username = 'YOUR BIT.LY USERNAME HERE';
    $data = file_get_contents("http://api.bit.ly/shorten?version=2.0.1&longUrl=$url&login=$bitly_username&apiKey=$bitly_api_key");
 
    $data = json_decode(utf8_encode($data));
 
    if ($data->errorCode)
    {
        return false;
    } 
 
    return $data->results->$url->shortUrl;
}
 
// now use it
echo get_shortened_url('http://www.example.com/this-is-a-stupid-long-long-long-url.html');
 
// how about WordPress?
// Just place the function above somewhere in your functions.php theme page and then
 
// 1. inside The Loop
echo get_shortened_url(get_permalink());
 
// 2. outside The Loop
echo get_shortened_url(get_permalink($post->ID));
 

Code snippet #1 - Get Latest Tweet

Code snippet #1 - Get Latest Tweet

Ok so I’m following some guy’s recommendation (sorry, I really forgot his name as well as his blog address) to try to post something useful even when I don’t have anything to blog about. How about a series of code snippets? To some they are old but to the others they may help - for example to myself two months later that is.

Code Snippet #1 - Get Latest Tweet

Purpose

  • Get your latest tweet from Twitter to show up instead of an unconvincing “Follow Me” link -or-
  • Display your idol’s latest tweet to wow your readers

Requirements

  • A Twitter account. Don’t have one? Head here or here

The Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php
 
// the function
/**
 * @desc Get latest tweet from a Twitter account
 * @param string The account's username
 * @return string The tweet
 */
function get_latest_tweet($username)
{
    $url = "http://search.twitter.com/search.atom?q=from:$username&rpp=1";
    $content = file_get_contents($url);
    $content = explode('<content type="html">', $content);
    $content = explode('</content>', $content[1]);
    return html_entity_decode($content[0]);
}
 
// now use it
$my_username = 'Phoenixheart';
echo get_latest_tweet($my_username);
?>

Deal with browser incompliance using jQuery

Deal with browser incompliance using jQuery

Without a doubt, being a serious web guy you want your new site to look perfect on web browsers. Yes, mission would be simple - or sound simple - if there wasn’t something called browser wars for such a long time without any glorious winner (yet). The stupid result is, we poor web designers and programmers are still hopelessly struggling to keep our sites look the same on Internet Explorer (DIE PIG, DIE!!!), Firefox, Opera, Safari, just to find out that the oh so cool banner suddenly disappears from that new boy Chrome. FYI (psst) that was when I decided to stick with web that I started to learn cursing and swearing.

I am so proud to say that I decided to stop supporting IE 6 to save myself some precious life years and keep my head from getting bald long ago. But still, those guys in Microsoft they have IE 7 and 8 to haunt us. And despite of the so-called W3C standards, each of the remaining major browsers renders the pages differently here and there - margins, paddings, form elements, and so on. To deal with them, we use “hacks”. Perhaps the most well known hack is one below, called “conditional comments”:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<!--[if IE]>
Stuffs for Internet Explorer all versions
<![endif]-->
<!--[if IE 5]>
Stuffs for Internet Explorer 5
<![endif]-->
<!--[if IE 5.0]>
Stuffs for Internet Explorer 5.0
<![endif]-->
<!--[if IE 5.5]>
Stuffs for Internet Explorer 5.5
<![endif]-->
<!--[if IE 6]>
Stuffs for Internet Explorer 6
<![endif]-->
<!--[if IE 7]>
Stuffs for Internet Explorer 7
<![endif]-->
<!--[if IE 8]>
Stuffs for Internet Explorer 8
<![endif]-->
<!--[if gte IE 5]>
Stuffs for Internet Explorer 5 and up
<![endif]-->
<!--[if lt IE 6]>
Stuffs for Internet Explorer lower than 6
<![endif]-->
<!--[if lte IE 5.5]>
Stuffs for Internet Explorer lower or equal to 5.5
<![endif]-->
<!--[if gt IE 6]>
Stuffs for Internet Explorer greater than 6
<![endif]-->

When this technique is great, it has two limitations. First, only IE is taken into account. When most of the time dealing with IE takes the majority, there are still cases when your sites looks different on Firefox, Safari, Opera etc. Second, the HTML code looks very ugly and unprofessional - just like we are humbly telling: sorry this is beyond my control… I must use a hack here… and here… sorry again…

Then today when looking for a better solution, I stumbled upon a much better method that overcomes all of our current problems - well, sort of. The idea behind it is using jQuery to detect the browser and its version, then add the corresponding class names into the <body> tag. For instance, if the visitor uses Internet Explorer 7, then “.browserIE” and “.browserIE7″ are added. Then, in our CSS we specify the styles for this browser:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#aPainInThe4ssElement
{
    /* generic styles for this pain */
}
 
.browserIE7 #aPainInThe4ssElement
{
    /* styles for this element on IE 7 */
}
 
.browserFirefox #aPainInThe4ssElement
{
    /* styles for this element on all Firefox browsers */
}
 
.browserSafari2 #aPainInThe4ssElement
{
    /* styles for this element on Safari 2 */
}

My hat off to Jon for this brilliant idea. Now dealing with different browsers is just a piece of cake!

Now the only thing I regret of is what took me so long to find out this solution.

If I don’t write a post, people may think I’m dead :)

If I don’t write a post, people may think I’m dead :)

Yes, the stupid office work hour has been taken from me all the precious time and inspiration. Even the plan to redesign this site had to be abandoned. But I am still here.

I have too little time for a new technique to share with you, but have never forgot this blog of mine. If you care about it, I’m completely rewriting my most popular plugin Referrer Detector from scratch. After 3 major versions, its limitations are going clearer and clearer each day, most of which cannot be just fixed easily with the current code. So I’m rewriting it into a pure better OOP Referrer Detector, ready for extending and maintaining. Of course there will be some new and improved features too. I won’t promise on the release date though - I don’t want to be a liar again.

I wanted to say I’m much appreciate for all of your compliments, suggestions, bug reports, and encouragement these days. So I am still here, please stay tuned ;)

phpQuery

phpQuery

It’s been quite a while I don’t have any update on this blog (sorry my *ten* RSS subscribers…). If there is any excuse, then it should be the fact that I’ve just left Gameloft to join a start up, and you know it, the work load is just a bit heavier than what I expected. To make my life somewhat more difficult, one day I realized that the current theme of this blog was just too messy and not so flexible, so I decided to redesign it somehow. Well, the new theme is under development now, and all I can promise is it will be much easier for the eye.

Ok cut the chit-chat, today I have this new thing to share.

Here is one line of the oh-so-familiar code:

$("div.old").replaceWith($("div.new").clone()).appendTo(".trash").prepend("Deleted");

If you got no idea what the line means, then let us be honest to each  other: How long have you been under the rock? Man, it’s jQuery! And the code I’ve just shown is a really simple stupid example about manipulation!

Now, once you know what it is and what it does, take a look at this:

pq('div.old')->replaceWith(pq('div.new')->clone())->appendTo('.trash')->prepend('Deleted');

You must have got it right: it’s PHP - OOP PHP 5 to be precise. But what was that with those jQuery stuffs in the middle, you ask?

Well, it’s phpQuery. And it’s what I’m about to introduce here and now.

As the name calls, phpQuery is a jQuery port to PHP. Being based on the most famous Javascript library, phpQuery provides server-side, chainable, CSS3 selector driven DOM API. Many things in jQuery are available/doable in phpQuery - including but not limited to selectors, attributes, traversing, manipulation, utilities, even AJAX and events. And the syntax is just about, if not most of the time exactly the same as that in jQuery - of course if that dollar character doesn’t have a special role in PHP. Example, here is a sample selector code:

pq(".class ul > li[rel='foo']:first:has(a)");

Here is some traversing back and forth:

pq('div > p')->add('div > ul')->filter(':has(a)')->find('p:first')->nextAll()->andSelf();

With some attributes here and there:

pq('a')->attr('href', 'newVal')->removeClass('className')->html('newHtml');

Impressive, no? So what is it for? What are the benefits of using phpQuery?

A bunch!

  • From the simplest, imagine you are “stealing” some content from a website. Imagine you will need to parse the content out from that garbage of (X)HTML, Javascript and CSS tags. Imagine you suck at Regular Expression. How will you reach the goal then? No worries with phpQuery. Just load the (X)HTML content into phpQuery using phpQuery::newDocument(X)HTML(), do some basic selector parsing like pq(”div#holder :text:first:not(’.bad-boy’)”), and then val(), and then that’s it. Well, what do you say?
  • To some server side DOM creator helpers, when you need to fully control the DOM.
  • To a jQuery plugin named jQueryServer that beautifully allows you to “1. Connect to server and make an Ajax request to somewhere (crossdomain allowed), 2. Do some manipulations, you can even trigger a server-side event, and 3. Get processed data back to the browser”. Have you imagined it? Have you? Woa, I’m excited!
  • And last but not least, to something much more advanced, a TemplatE SysteM - they do call it QueryTemplates. This time it really gets big!

No, don’t tell me you’re not impressed!

WordPress plugins I’m using (cont’d)

WordPress plugins I’m using (cont’d)
Be sure you’ve read the first part of this post.

6. Though my knowledge is very very very humble, I sometimes do tutorials (don’t laugh, what a shame :”>), for example, this and this which have been receiving a few of visitors from Google. In these tutorials, I posted some source code - HTML, XML, PHP, Javascript, CSS etc. In order for them to be clearer to read, I highlighted them. How? Did I have to color each and every span? Nope. WP-Syntax is the key. This Geshi supported plugin did everything for me. Install and activate it, then wrap the code block into a <pre></pre> pair with a specified lang attribute, there, it’s done.

7. Do you notice that out of the box, the comment boxes provided by WordPress look very simple (read: ugly)? I do. And I hate it, especially comparing with the much more functional reply boxes in those forums out there. So I looked for a way to add my comment boxes some extra power, and finally stopped at MCEComments, a plugin that integrates TinyMCE into a WordPress comment box, giving it a lot more features. I’m pretty sure there are some other plugins that share the same purpose, but I’m not that picky - since MCEComments perfectly worked for me from the beginning, I’ll stick with it.

8. Just like all other plugin developers, I have a development version of this blog, as described in one of my previous posts. That post mentioned that I used WP-DBManager to create a backup of my live database. Though in another post, I talked about the possible vulnerability this plugin’s users may encounter if by any chance don’t strictly follow the instructions, this plugin is still a must-have. Almost every database-related actions can be performed through it: you can optimize, repair, empty/drop tables, run specific SQL queries, and most important, set up an automatic schedule to back up your database. No matter how big your blog scale is, keeping backup(s) of your database is a must. For this reason, having WP-DBManager healthily activated is vital.

9. For user experiences and interactions, I use 3 plugins in a row: ShareThis, Digg This O’ Mine, and Referrer Detector. The first is so famous that I see it on almost every blog - it allows blog owners and visitors to submit a post which they feel interesting to plenty of social services: Digg, Reddit, StumbleUpon, Delicious etc.

The others are my own plugins, very simple, but fits my needs :).

11. It is also a good idea (that I borrow from others) to have an “Other Posts” section on a post page - this reminds visitors to explore other (interesting) contents. I used to use Random Posts plugin to randomly display other posts, until I one day realized that it doesn’t work so well with WP-Super Cache. So I decided to write and use my own AJAX Random Posts. It’s a humble plugin (just like all other ones from mine), but again, it fits my needs, so still I’m using it.

12. Finally, for all these plugins, believe it or not, I didn’t have to download any them from WordPress codex repository, ever. Everything was automatically done by an extremely useful plugin called WP Easy Uploader. I downloaded, uploaded, activated (and configured) this one the very first. From then on, every time I need to upload a plugin, I just need to head to Tools:Upload Files, paste the download link into the URL text field, specify that it’s a plugin, and click the cute “Upload” button at the bottom. The plugin archive file will be grabbed from WordPress codex server and extracted just in place.

Yes, I know that with the 2.7 version of WordPress coming out, we have a neaty plugin installer built-in. But WP Easy Uploader still remains one of my most favorite plugin. The first reason is that it works for almost everything, not just plugins alone. With it, I rarely have to fire up FileZilla anymore. And you can tell, this seriously satisfies my laziness. Hehe. Hehe. Hehe.

So how about you? Do you have any recommendations or cool stuffs to share? How about trying my MCEComments-powered comment box right now?

Hot update: My latest plugin is the great MobilePress which renders my blog to work well on mobile handsets. Thank you very much, Thaya!

WordPress plugins I’m using

WordPress plugins I’m using

Just in case you don’t know - I’m pretty sure you do though - a WordPress-powered website is very limited in any terms without plugins. Or you can tell, a WordPress site that doesn’t use any plugin is just useless. Plugins bring your site uncountable and invaluable enhancements.

Well, enough of babbling. What I wanted to say is, today I’m going to write down here list of plugins I’m currently using on this site. For what, you ask? To show off, of course. Or - I prefer this - to share something that may be useful sometimes.

So in no particular order, here they come.

1. I use WordPress.com Stats to have a in-details view on my blog. Five or ten times a day, I click “Blog Stats” link in the admin panel to get an idea on the traffic, incoming/ongoing links, search terms etc. All these data are essential if I want to build up a high quality site.

2. To save a lot of clicks and keep the admin menu bar tidy, Ozh’ Admin Drop Down Menu is my plugin of choice. Agree, the new menu system in WordPress 2.7 is a good improvement, but it’s still nowhere near Ozh’s version. Write a new post, customize the theme, add a new plugin, change some settings… almost all the commands are now just one-click away from me. Huge productivity, I’d say.

3. When it comes to SEO, All in One SEO Pack definitely suits my needs. I didn’t need to do anything, just installed it and all the keywords, titles, descriptions were there beautifully. Sure, there are plenty more than just than for SEO (like the incoming links) but that should be basically enough for a good start. So if you’re coming from Google, this plugin deserves some credits.

4. And some other credits should go to Google XML Sitemaps. This plugin automatically generates a XML-Sitemap compliant site map for me every time I add/edit/remove my posts and pages, so that MSN, Yahoo, Ask, and Google bots can easily browse (and index) my site. I don’t even want to imagine just how long and boring it would be if I had to manually modify my site map after there was a change in the architecture, so this plugin is a must-have.

5. I’m not a good writer. Especially when English is not my mother language. And my articles are boring. So I guess that’s why I’m not receiving many comments from my readers. From those darn spammers however, well, there’s a bunch of spams almost every day. But you don’t see any of them, right? It’s totally thanks to the Askimet spam fighter. I installed it from the beginning of this blog, and since then there is 0 missed, around ten false positives on over 500 spamming comments got caught. Impressive, huh?

(to be continued)