The PHP Hierarchy of Needs

We had a lecture about Unit Testing in our local PHP user group last week. I really like these meetings because there is usually good interaction between some very experienced developers and some very inexperienced ones.

Following the usual “but why is it better then just running it in my browser and seeing that it works” question made by one of the younglings, we got into a discussion of why Unit Testing it so good, and especially, why is it such an addictive practice and why people who do it (including myself) tend to love it so much.

And then it hit me: [more...]

GNOME doesn’t detect MIME types anymore

After a recent upgrade (Gentoo being Gentoo) my GNOME desktop stopped detecting file MIME types. All files in Nautilus whould show as plain files with no type icons, and all application associations have stopped working.

I tried re-emerging a bunch of stuff like gnome-mime-data and mime-data and nothing helped.

After lots of research, I did this (as regular user):
$ update-mime-database .local/share/mime
This actually worked! It threw out some errors regarding specific files, but it did work! I’m not sure what it does, but after restarting Nautilus (by doing the usual killall nautilus) I got my desktop properly working again.

Ahh.. got to love Gentoo - no other distro gives you these challenges and the satisfaction that comes with solving them - or as Gentoo folks say, “If it’s broken - fix it. If it ain’t broken, break it” ;)

New Server

Well, some 36 hours after I’ve switched the DNS records, it’s safe to say the bulk part of my blog’s server migration is complete. I’ve moved it from some shared hosting space I rent (which I will still use for some other things) to a dedicated server I share with some friends.

Obviously, this means much more power, and probably better performance - I can finally install Zend Platform on my own blog ;)

If you still encounter any issues (broken links, etc.) drop me a line.

Zend Framework Components Presentation @ DLW08

I’ve just finished my one hour talk at Dynamic Languages Europe titled “Zend Framework Components for Non-Framework Development”. Despite the long name, the presentation’s concept is quite simple: It’s an overview of some of the use-at-will, standalone components of ZF and how you can use them even in a non-ZF application.

The presentation went quite well and the room was full (and hot) - the fact that people actually stood throughout the presentation shows how popular ZF is nowdays (well, it was a small room - but still ;)

I didn’t have time to go through all the components I planned to (skipped Zend_Json and Zend_Log) but I still feel it was a good session.

You can download the slides here, or see it on Slideshare:

A small recommendation for those of you who present a lot: I used my newly-bought Logitech Cordless Presenter for the first time, and it really helped me. It doesn’t look so sexy (even for a shaver) but it has everything you need - remote control for the slides, laser pointer, timer to manage time (it will vibrate every 5 minutes if you want which I find very useful because I have hard time managing time when I present) and even a button to blank the screen. It connects through USB and is detected like any keyboard - so it worked perfectly with my Linux/OpenOffice and should work with Windows/MS Office and Mac (I suppose) as well.

Travel Plans

After what is probably the longest period of being at home without flying anywhere (since November!) in the last 3 years, I am actually quite excited to be flying again.

After a quick visit to Zend’s Cupertino office, I will be attending two conferences in may: I’ll be visiting the last couple of days (May 22nd - 23rd) of php|tek in Chicago - in which I will not be presenting, but will probably hang around with the Zend guys and go to some lectures.

After spending the weekend with friends in New York City, I’m flying to Germany to attend DLW Europe - a first-year conference dedicated to dynamic languages (PHP, Ruby, Python, Perl etc.). There’s quite a lot of known PHPers attending and speaking, and it looks like it’s going to be a blast. Personally I will be giving a talk I call “Non-framework Zend Framework Components” (working title) - which will showcase some of the more useful components of Zend Framework for those who do not want to base their entire application on it - but rather just need to preform tasks and want to reuse the high-quality components of ZF in order to do that.

So it looks like quite a road trip: Tel Aviv -> San Francisco -> Chicago -> New York -> Karlsruhe -> Tel Aviv - by the end of it I might be able to buy a MacBook Pro using frequent flyer miles only ;)

If you’re in either conferences - come over and say hi!

Playing with CouchDB View Collations

I've been playing with CouchDB quite a lot lately. While it's still far from feature-complete, I think it's a cool project. Generally the concept of object databases is a new thing to me, growing up in the web where for most people "database" == "Relational Database".

Since CouchDB related documentation is still scarce, I decided to share a cool thing I managed to pull around today with CouchDB's view API.

For the purpose of playing with CouchDB, I decided to write a PHP-implemented CouchDB interface (yes, I know there are exiting ones) I currently dub "Sopha" and a Wiki using CouchDB and Sopha as backend (if I ever get those to a stage where they would actually work, I will probably release them as open source).

One of the design goals of my Wiki, was that previous revisions of each page are kept and can be accessed. While CouchDB keeps track of object revisions, access to old revisions is not guarantees as those eventually get deleted - So I had to implement my own revision tracking of pages. The design I went for was simple: each revision in it's own document in the DB. They all have the same "title" field - but an incrementing revision number, starting from 1 (for new pages) and going up.

This design poses one major problem: how do you easily access the single most recent revision?

I started by creating 3 different view functions for accessing wiki pages: one to access the most recent revision of a page by it's title, one to access a specific revision of a page by title and revision number, and another one - to fetch all the revisions of a specific page by it's title.

This was a mistake, and it resulted from my years of thinking relational (keys, indexes, SQL, etc.). As I worked my way through, I started understanding the power and magic of CouchDB's views and view collations. With proper collation use, it turns out it only takes one view function to rule them all:

CODE:
  1. function(doc) {
  2.   if (doc.doctype == "WikiPage") {
  3.     map([doc.title, doc.revision], doc);
  4.   }
  5. }

Using this view function, I could do the following ("titlerev" is the name of my view function, URLs are decoded for readability):

Access the specific revision 123 of a specific page titled "My Page":
GET /database/_view/wikipage/titlerev?key=["My Page", 123]

Access all the revisions of "My Page":
GET /database/_view/wikipage/titlerev?startkey=["My Page"]&endkey=["My Page", "Z"]
This will work because CouchDB orders the results according to their key - and has strictly defined ordering rules - so ["My Page"] will always come before ["My Page", 1] and ["My Page", "Z"] will always be after ["My Page", n] as long as n is a number.

Access the latest revision of "My Page":
GET /database/_view/wikipage/titlerev?startkey=["My Page", "Z"]&endkey=["My Page", 0]&decending=true&count=1
This works as well - because records are selected in reverse order from ["My Page", "Z"] to ["My Page", 0] - but only the first one is returned - so it will always be the one with highest revision number.

How cool is that?

BTW there is a good article which also explains CouchDB view collations at cmlenz's (one of the contributors to CouchDB) blog.

Security By Obscurity - “Not to Stand Up”

I am giving a security lecture at the local PHP users group tomorrow, and one of the topics is, ahm, security by obscurity. In fact, it's not really a topic - I just mention it and say that it's not really an approach to security, and should generally only be used as an extra measure and should not to be relied on.

This got me thinking about one of my old-time favorite Monty Python sketches:

The first rule of not being seen: not to stand up!

New year, new position

I spent the last 2.5 years working for Zend's Global Services department, first as a technical support engineer and later as a technical consultant. I've learned allot and met lots of very smart people - but for some time now I have a feeling it's time to move on.

Apparently, some people at Zend had the same feeling - don't worry, I wasn't fired. I didn't quit either. Starting from January 2008, I am now a part of Zend's Product Management group.

My new and awesome title is "Senior PHP Specialist" which kind of means nothing (and that's what so good about it!). My actual roles are varied and flexible and involve duties such as competitive analysis, benchmarking, prototyping, meeting with customers and PHP community folks, and generally getting more customer and community feedback and touch into Zend's product line. I'll be working with all products - mostly Zend Platform, Zend Studio and Zend Core, and will also maintain my involvement in Zend Framework, and perhaps other projects as they come.

I have to say this has the potential of a dream job: it's hands-on, and yet very dynamic. It's community related and touches commercial products. It means working closely with services people, R&D, and customers (and PHP users who are not our customers!). It involves studying emerging technologies, programming, testing software, writing and reading papers and generally keeping a finger on the pulse of the web.

Oh, and did I say my new direct manager is Zeev Suraski?

So good luck and happy 2008!

Reducing your bandwidth for benchmarking purposes

In the last few days I've been busy doing allot of web application performance benchmarks. For some of these benchmarks, it was important to simulate a real end-user's average effective bandwidth (real-world download / upload speed from the end user's perspective).

Since we used a fast, clean LAN for our benchmarks (you can't get consistent numbers otherwise), we had to find a way to somehow limit the bandwidth of our LAN so that it would resemble "real Internet" throughputs. Since it took some research and reading to find the best way to do that, I've decided to write a quick HOWTO to describe what we've done.

[more...]

Creating magic_quotes_gpc portable apps with Zend Framework

I've been working on a small ZF based application for work in the last few days, and it was running quite well on my local machine. But when time came to deploy - alas, we discovered that slashes are magically added before single quotes to all data. The dreaded magic_quotes_gpc "feature" was apparently on on that server - so instead of turning it off, I decided to make my application more portable by making it work regardless of magic_quotes_gpc's status.

Since my application was based on Zend Framework (as most of the stuff I write for work these days), I decided to do it in a reusable "Zend Way". So I created a Zend Controller Plugin to reverse the effects of magic_quotes_gpc:

PHP:
  1. <?php
  2.  
  3. /**
  4. * A Zend Controller Plugin dedicated to undoing the damage of magic_quotes_gpc
  5. * in systems where it is on.
  6. *
  7. * @author  Shahar Evron
  8. * @version $Id$
  9. */
  10.  
  11. require_once 'Zend/Controller/Plugin/Abstract.php';
  12.  
  13. class MyApp_StripMagicQuotesPlugin extends Zend_Controller_Plugin_Abstract
  14. {
  15.     /**
  16.      * Called before the action loop is started. Will internally strip all
  17.      * slashes off $request parameters
  18.      *
  19.      * @param Zend_Controller_Request_Abstract $request
  20.      */
  21.     public function dispatchLoopStartup(Zend_Controller_Request_Abstract $request)
  22.     {
  23.         $params = $request->getParams();
  24.         array_walk_recursive($params, array($this, 'stripSlashes'));
  25.         $request->setParams($params);
  26.     }
  27.  
  28.     /**
  29.      * Strip the slashes off an item in the Params array
  30.      *
  31.      * @param string $value
  32.      * @param string $key
  33.      */
  34.     protected function stripSlashes(&$value, $key)
  35.     {
  36.         $value = stripslashes($value);
  37.     }
  38. }

You place this plugin under your application library directory. Then, in your index.php bootstrap file, check if magic_quotes_gpc is enabled, at load and register the plugin:

PHP:
  1. /**
  2. * Setup controller
  3. */
  4. $controller = Zend_Controller_Front::getInstance()
  5.     ->setControllerDirectory('../application/controllers');
  6.  
  7. /**
  8. * Load the magic_quotes_gpc undoing plugin if needed
  9. */
  10.     require_once 'MyApp/StripMagicQuotesPlugin.php';
  11.     $controller->registerPlugin(new MyApp_StripMagicQuotesPlugin());
  12. }
  13.  
  14. // run!
  15. $controller->dispatch();

Now, this is only loaded and executed in systems where magic_quotes_gpc is enabled. It probably has quite allot of overhead - so a best solution in production environments would be to turn magic_quotes_gpc off (consider the fact that PHP works hard to escape the input, and then works hard to undo it... what a waste!), but if you want to produce a portable application that can be installed anywhere (including on shared hosting environments), this is a good solution.

BTW I'm not really sure if this handles cookies - so there might be a more "correct" way to do this. If you have any suggestions, I'd be happy to hear them!