Debugging PHP with FirePHP on Zend Framework

Posted on Thursday, October 1st, 2009 under , , , ,

firephpYou know the saying: if debugging means taking the bugs out, then programming means putting them in. Yes. We all have bugs in our code. And since not all of them can be marketed as “undocumented features”, from time to time we have to debug our applications.

The best debugger for PHP I’ve used so far is Zend’s. Zend Platform together with Zend Studio constitutes a very good development environment and a great debugging environment. Due to the fact that Zend Studio is a little pricey, I don’t use it any more, instead I’m using a highly customised vim. This makes a great development environment, but unfortunately isn’t not that great when debugging. I know you can use vim with Xdebug, but it’s quite a chore, and I don’t like it. Since old school debugging with var_dump() or print_r() is out of the question, I was looking for another way to debug my applications. And I’ve found just the thing: FirePHP. It’s a Firefox extension, just like FireBug – that can receive debug information from the server.

Since I do most of my bugging programming on Zend Framework, I also need debugging for this platform. I use the OOP based bootstraping method, where you extend your Bootstrap class from Zend_Application_Bootstrap_Bootstrap. And in the .htaccess file of the /public/ directory, I have an envelope with the current state of application (usually on of development/staging/production):

SetEnv APPLICATION_ENV development

Normally, I need the debug information only when the application is in the “development” state, so I’m using this method in the Bootstrap class.

class Bootstrap extends Zend_Application_Bootstrap_Bootstrap {
    // Bootstrap other components
 
    /**
     * inits FirePHP for debugging
     *
     * @return void
     */
    protected function _initFirebugDebugger() {
        if(APPLICATION_ENV == 'development') {
            // don't debug while not in "development"
            $logger = new Zend_Log();
            $writer = new Zend_Log_Writer_Firebug();
            $logger->addWriter($writer);
 
            Zend_Registry::set('logger',$logger);
        }
    }
}

I also like to have some syntactic sugar when developing, so I’ve define this function in the Bootstrap.php file. Yes, I know that this might be perceived as a blasphemy by some of the OOP purists out there, but I really don’t care. If you don’t want non-OOP “stains” on your code, simply create a YourApplication_Utility_Firebug class or whatever with a static debug() method and paste the code in it.

/**
 * syntactic sugar for logging errors
 * and debug messages to FireBug
 *
 * @param string $message
 * @param int $label
 * @return void
 */
function fb($message, $label = null) {
    if($label != null) {
    	$message = array($label, $message);
    }
 
    if(Zend_Registry::isRegistered('logger')) {
    	Zend_Registry::get('logger')->log($message);
    }
}

And now, any time you need to debug something, simply type:

fb($variable);
fb($_POST); // and so on

And all these variables will be sent to Firefox’s FirePHP toolbar and you can inspect them from there. For even better results, you can also send debug information from your ErrorController to FirePHP (comes in handy when using Ajax).

PS: I’ll have a look into FireLogger for PHP. It also look pretty interesting, although it’s only in Beta.

Caching problems with mod_expires

Posted on Monday, September 21st, 2009 under , ,

apacheSometimes, when you’re dealing with large images, flash movies or large javascript files, it’s generally a good idea to force them in the client’s cache.

A very simple way to achieve this is by using Apache’s mod_expires. For instance, if you add the following example, taken from the manual, to your .htaccess file – assuming of course that mod_expires is properly installed and configured – it will tell the browser to cache all the files for a month.

ExpiresDefault "access plus 4 weeks"

So, every time the client returns in the following month to the site, the browser won’t download all the static content again, but load it locally from the cache, thus minimising the loading time. Of course, there are some issues that usually appear after updates. Particularly after updates of the cached files :)

For instance, you add a new Javascript functionality to the site or make some changes in the css or swf files and the user doesn’t hit at CTRL+F5 to fully refresh the page and clear its cache, then he will see the old version of the site. Of course, one can take the short road to LamerVille and post a message on the site, asking the user to refresh the page. But that’s a little too lame to be taken into consideration, especially when dealing with respectable sites.

But there’s another way, much more elegant. First of all, place all the static, cache-able files in a separate folder. The browser will cache all the files based on their URL. If you want the browser to reload all the static data on every new request, you need to change the URLs on every new request.

Let’s say, the site resides at www.example.com and that all the static information will be served from www.example.com/static/. Now, a good idea is to make the links look like this:

http://www.example.com/static/(release-number)/css/style.css
http://www.example.com/static/(release-number)/js/cool-ajax-app.js

Where release-number is a number that increments with every new release. This way, the URLs will be different after each release thus forcing the browsers to fetch the new files. You don’t need to go through lots of files and increment the release number by hand, you can just use the following python script:

#!/usr/bin/python
"""
Read more about what this script actually does on 
http://blog.motane.lu/2009/09/21/caching-problems-with-mod_expires/
 
Usage:
	python increment_release.py start_directory static_prefix
 
Author:
	Tudor Barbu http://blog.motane.lu
"""
import sys, os, re
 
REGEX = ''
CACHED_DIR = ''
 
def main():
    global REGEX, CACHED_DIR 
 
    if sys.argv is not None:
        length = len( sys.argv )
        if length < 3:
            print 'Read the comments in the source code'
            exit()
    start_folder = sys.argv[1]
    CACHED_DIR = sys.argv[2]
 
    REGEX = re.compile( '=(\'|")' + re.escape( CACHED_DIR ) + '\/((\d+)\/|)([^\'|"]+)(\'|")' )
 
    parse_files( start_folder )
 
def parse_files( dir ):
    basedir = dir
    subdirectories = []
    for item in os.listdir( dir ):
        if os.path.isfile( os.path.join( basedir, item ) ):
            perform_replace( os.path.join( basedir, item ) )
        else:
            subdirectories.append( os.path.join( basedir, item ) )
    for subdir in subdirectories:
        parse_files( subdir )
 
def perform_replace( file ):
    global REGEX
    f = open( file, 'r' )
    contents = f.read()
    f.close()
    if REGEX.search( contents ):
        f = open( file, 'w' )
        f.write( REGEX.sub( handle_match, contents ) ) 
        f.close()
 
def handle_match( matches ):
    global CACHED_DIR
    if matches.group(3) is not None:
        revision_number = int( matches.group(3) ) + 1
    else:
        revision_number = 1
    return '=%s%s/%s/%s%s' % ( matches.group(1), CACHED_DIR, revision_number, matches.group(4), matches.group(5) )
 
if __name__ == '__main__':
    main()

…and, of course, there’s no need to create lots of directories either. A simple .htaccess rewrite rule will do. Just redirect all the URLs like /static/(number)/css/style.css to point to /static/css/style.css, by adding these 2 lines in the /static/.htaccess file:

RewriteEngine On
RewriteRule ^\/static\/(\d+)\/(.*)$ $2 [NC,L]

This should solve all your caching related problems. If you want to look savvy, you can use the version number of the head revision from subversion of whatever versioning system you might be using instead of a simple incremental number.

Yes, I know that the script is a little bit buggy but it works for me. If you have an improved version, post a comment below. Credits will be given.

The “August” error

Posted on Thursday, September 17th, 2009 under , , ,

I’ve just came back from Wurbe, where I’ve enjoyed a late evening snack (consisting of beer, Pepsi and pizza) and chated with other fellow developers on a large range of subjects, raging from current trends in development to Klingon grammar.

Bodgan Lucaciu told us a funny story about a strange bug. It’s like this: in Javascript, when you parse a number from a string – let’s say a month’s index like 07 – with parseInt you must be very careful, because, for parseInt, the leading 0 is an indicator that the number is written in octal instead of decimal.

alert(parseInt('07')); // for July - will echo 7
alert(parseInt('08')); // for August - will echo 0 as there is no 08 in octal

So if your application mysteriously stops working on the first of August, this might be your problem. Although this “feature” is marked as deprecated, it’s still present in many modern browsers, so one can never be too careful. Also keep in mind that by default, numbers starting with 0x are considered to be hexadecimals.

Python – first impression

Posted on Tuesday, May 12th, 2009 under , ,

This is a post I’ve been trying to write for about 2 weeks now. As some of you might know, I’ve spent the previous weeks studying python and writing small scripts and I’ve decided to write a blog entry about it. As a matter of fact, I’ve also looked over the Pylons framework, but I’ll write about it in a another post. So here it is, my opinion about python alone:

What I like about python

Well, I loooooooooove the indentation. I really do. Python made it impossible for lamers to write ugly “one liners”. Everything must be indented and in its place or it won’t even compile (compiling aka no syntax errors as python is an interpreted language). After years of dealing with ugly sources with no braces, no indentation and so on, this feature is like a gift from heavens for me. I really hope it will catch on and be implemented in other languages.

I also like the for in iteration over…well…everything. This code:

for item in collection:
    do_stuff(item)

…works in most cases, even when collection is a file. In which case the loop iterates over the file’s lines. Tuples, dictionaries and lists are cool features.

What I don’t like about python

Of course, there are some things I dislike about this programming language. The first thing is that sometimes is too verbose. Python doesn’t have an post/pre increment operator. You can’t write i++ or ++i, although this code compiles. Further more, it compiles and does nothing, taking the act of debugging to a whole new level of annoyance.

You always have to write i += 1. It also doesn’t have a ternary operator. If you write a = (condition) ? b : c it will give you an compiling error.

Another weak point is its OOP capabilities. Object orientated programming is very strangely implemented in python. A class example in python looks something like this:

class MyClass:
    def __init__(self):
        self.attribute = 'default value'
    def custom_method(self, attribute):
        self.attribute = attribute
    def print_data(self):
        print self.attribute
 
obj = MyClass()
obj.custom_method('wassabi')
obj.print_data()

As you can see, there are no access modifiers (private, protected, public), no instantiation operator (new), the this keyword is replaced by self, and you must write it every single time you define a new method in the class. And python also allows multiple inheritance, which does one thing: annoys people.

Conclusion

Apart from some really annoying “features”, I’m starting to like python. It provides a quick way and pretty clean way to do get things done. And in the end, this is all that matters…Python is cool!

HTTP headers and AJAX requests

Posted on Wednesday, February 11th, 2009 under , , , ,

This post is about a quite common problem that I’ve encountered over and over again but didn’t look into it to find a proper answer to it. The problem is what happens when I request via AJAX a page that makes a HTTP redirect to another and how do I fix it to behave “normally”. It’s quite common problem with pages that require authentication.

Let’s say we have the following PHP script:

if( !is_user_allowed() ) {
    header( 'Location: ' . PATH_TO_LOGIN_PAGE );
    die();
}

Pretty simple and self explanatory. If the user isn’t logged in, he gets sent to the login form. But what happens if the request is made via AJAX? A simple AJAX request made using the prototype.js library looks like this:

new Ajax.Request(
    'server_side.php',
    {
        onSuccess: function( t ) {
            $( 'container' ).update( t.responseText );
        }
    }
);

What happens if the user isn’t logged in? The browser makes two requests to the server, the second one to the page containing the login form.

requests

And the whole login page gets loaded into a small container on current page, ruining the design and confusing the user.

Although I’ve encountered this problem on several occasions, I didn’t give it much thought. I’ve used that very popular design pattern “I know it’s lame, but hey, it works…moving on”. The implementation on case was like this: add a token to the login page’s markup, something like and check to see if this string is in the response text. Like this:

new Ajax.Request(
    'server_side.php',
    {
        onSuccess: function( t ) {
            if( t.responseText.indexOf( '<!--login-->') != -1 ) {
                document.location = 'login.php';
            }
            else {
                $( 'container' ).update( t.responseText );
            }
        }
    }
);

Plain and simple. And lame. I admit it. But hey! It works :) Still, I’ve found a better way of doing things, that relies on HTTP headers. First of all, in the login page, instead of a lame string message, I’ve added some custom headers to the response.

header( 'HTTP/1.0 401 Authorization Required' );
header( 'Login-path: ' . PATH_TO_LOGIN_PAGE );

And then, I’ve altered the the javascript a little. Since a response served with a 401 header won’t trigger the onSuccess callback function, this script uses onComplete.

new Ajax.Request(
    'server_side.php',
    {
        onComplete: function( t ) {
            switch( t.status ) {
                case 200:
                    $( 'container' ).update( t.responseText );
                    break; 
                case 401:
                    document.location = t.getHeader( 'Login-path' );
                    break;
            }
        }
    }
)

It works. And it’s not so lame. Mission accomplished…

Valuable software

Posted on Friday, January 30th, 2009 under ,

I’ve been a programmer for about 5 years now. I’ve worked on a large variety of projects. Small projects, medium projects, large projects. I’ve worked in teams, I’ve worked alone. I was an employee. I was a freelancer. But from these 5 years, I’ve spent about 1 year – an astonishing 20% – or maybe even more working on projects that were never used. They were paid for. I was paid for my work, but the project was simply cast aside. Nobody used it.

And I’m puzzled, some of those projects were quite expensive, not the average “500 euro for a 5 pages with contact form and Google maps widget website” deals you find when working with freelancers. After months of work and thousands of euros paid…nothing. The project was quietly buried. And I’m not a singular case. I’ve talked to my friends that also work as developers and most of them worked more than once on a project that was never used. Is software so worthless than you can easily cast aside projects that costed so much? It seems it is.

I believe it’s because the clients usually think about huge projects, with thousands of features that will make them the next month’s billionaires, while forgetting that developing projects of that magnitude usually take months or sometimes years to be implemented and by the time it’s ready, might not worth a dime and it would be cheaper to simply throw it away than continue pumping money into it.

Imagine a project that was started 18 months ago and and was initially scheduled to be released in 24 months. Let’s say that this project was meant to be “the next big thing” in real-estate with all the possible features, with anything a real-estate agent’s heart could ever desire. Would be in production today? I seriously doubt that. Nowadays, the only way you can become a real-estate millionaire is to start as a real-estate billionaire. And why would anyone pump money in that? The market moves so quickly, that this year’s niche could be full of competitors next year.

The solution: start small. Build a large project in small incremental steps. Use agile development methodology. Be ready to change the specs at any time. Build the project as modularised as possible. Make sure that you can easily add new stuff and remove worthless stuff. Have a look over MVC, it allows a more agile approach on web projects.

And of course, always ask yourself: what would Captain Picard do?

Common lies in freelancing

Posted on Thursday, January 29th, 2009 under , ,

At one time in our careers, we all worked as freelancers. It’s fun, you get to pick your work, no annoying project managers, no accounts managers, no managers at all. You’re your own boss. Just you and the project. And yeah, almost forgot, the client.

Because most freelancers are cowboy programmers that work from home, sooner or later the project will fall behind schedule. Reasons include proximity to the fridge (also has a devastating effect on the waist), games that are installed on that computer, movies and so on. What do you think most people will choose between eating a huge sandwich and drinking some beer while watching the new episode of Heroes and working? Yeah, my point exactly.

And when you’re behind schedule and the client asks you for a status update, you’ll do what every other moral person would. Lie about it! But try to do it with style and in a way that won’t get you caught. Most common lies are:

  • I’ve worked on the database” since nobody can actually check that
  • I’ve solved some security issues” again, really hard for somebody to actually check that
  • We have a small problem with the server’s configuration, I’m working on it now” somehow implies that is not your fault
  • I haven’t done the layout part yet, but everything else is ready” but I can’t show it to you without the layout now, can I?
  • My (retarded) neighbour flooded me, but don’t worry, your files are safe” should work, as long as he’s not your neighbour…
  • We’re almost there, I’ll set up a demo environment for you by tomorrow noon” like coping some files on a FTP host takes a day and a half
  • I’ve worked on optimization…riiiiiiiiiiiiight

And in the end, a meaningful quote: I did not have sexual relations with that woman – Bill Clinton.

Scrum & agile development

Posted on Monday, January 26th, 2009 under ,

When I started my programming career, I was convinced that waterfall is the way to go. I felt the need to have clear specifications for the project I was working on since the very beginning. The let me see what you’ve done so far e-mails from the customers were a real pain in the ass, because since no partial releases were scheduled, I usually had to pick and choose parts of the project that seemed to work and build an adhoc release. The result was what one might call a Frankenstein of software development that had major bugs, didn’t quite work and the only thing it could do right was to annoy everybody. The client was annoyed because he was feeling that his money are not well spent and I was annoyed because I was stuck with a meddling client who doesn’t stick to the agreed plan. If the release isn’t scheduled for another three months, the he should go and bother somebody else. Maybe a government employee from the IRS. But instead of doing just that, the client was sending bug reports -- fix this, change that -- on the “Franky version”. So the project was slowly branching into two. We had to continue the development of the main branch, as initially agreed, but we also had to do some bug fixing and changes to the adhoc version. Fixing those bugs was taking away valuable development time and the estimated time of delivery was being pushed further and further in the distant future.

Now that he could see parts of the software, the client was changing his mind about some of the specifications and was asking for new features that weren’t originally planed. Features that were incompatible with what we’ve done so far. And…long story short: epic fail!

After spending about 2 years in the waterfall hell, I have found out about Agile development and scrum. It’s a whole different approach that divides a large scale project into smaller parts that are easier to implement, easier to test and easier to change if the customer changes his mind. In the current economical climate, even without meddling customers, a waterfall approach to software development is bound to fail. Imagine how things looked 12 months ago and how they look now. A software project must be able to adapt quickly and meet the market’s requests.

I have found this video on Adobe’s (Romania) blog that explains agile development and scrum in about 10 minutes. Enjoy!