Jan 22, 2012

Packaging the Yii framework as an archive

With PHP 5.3 came the new phar extension, which allows you to package scripts and other files into an archive, and enables you to run scripts or serve documents from that archive.

I've built several applications on the Yii Framework, my personal PHP framework of choice. Deploying most frameworks, with dozens of megabytes and typically several thousand files, has a tendency to dwarf the actual application somewhat. Checking 1700 files into subversion can be a real chore. (and God forbid you ever have to update the framework.)

I've been thinking for a while how it would be nice if you could check-in the framework as a single file - using a phar archive, that is now possible, and I decided to try it on an existing application I built on Yii, which needed a framework upgrade anyhow.

Archiving Yii

First things first, I had to get the Yii Framework codebase into phar archive format - so I went ahead and wrote a script, which you can drop into a Yii framework folder and run from a command-line.

The documentation for the phar extension completely fails to mention the command-line utility, which comes with the PHP distribution, which does something very similar. (You may not need my script, which doesn't really do anything Yii-specific at the moment.)

Bootstrapping the Yii archive

Assuming you ran my script, you now have a file with a name like "yii-1.1.9.r3527.phar", containing the just over 1,700 files, neatly packaged and ready to ship.

Eager to prove my point, I went ahead and deleted my Yii folder at this point, placing the new phar archive in my application's "protected" folder. Bootstrapping your application to run the packaged Yii framework is easy - in your dispatch script ("index.php") add the following at the top:
new Phar('./protected/yii-1.1.9.r3527.phar');
This makes the Yii framework available through the phar stream-wrapper - configure the path to the Yii framework root folder as follows:
"phar://yii"
And you're good to go - anything under this path will address files in the Yii framework package, which will be unpacked as needed, on the fly.

CAssetManager

I did run into one little problem with CAssetManager, which was built with the assumption that the framework's built-in assets (jQuery, etc.) are stored as physical files on the local filesystem.

Fortunately, this was relatively painless to fix - I submitted a patch for this issue, which you should apply if you're going to attempt this.

Performance Considerations

You'll find some posts around the net from early after the PHP 5.3 release, claiming that phar archives slow down your applications. Not so - perhaps surprisingly, running a framework like Yii (with a bytecode cache, such as APC) from a phar archive, is actually slightly faster than running from flat files!

The bytecode cache normally has to check the modification-time of every script when retrieving from the cache - and because there is only one physical file (the archive) that needs to be checked, most of this file-system overhead goes away.

Conclusion

I can't guarantee that there aren't any other incompatibilities - although I am already using this solution in production, on a fairly large Yii-based application, which is currently running smoothly.

If you run into any other problems, please submit a comment below.

Update

I recently forked the Yii-framework on Github and implemented a shell-command that lets you package the Yii-framework as a Phar-archive:

https://github.com/mindplay-dk/yii

Jan 16, 2012

The short-sightedness of CSS3 image-fragments


So everyone is raving about this new CSS3 feature for cropping images.

example from the W3C specification (working draft 12) 

This is a good solution to one very specific problem.

However, the reason we put multiple images in single image-files in the first place, is not because we think that's practical or fun. It's a work-around, enabling us to deliver many small images more efficiently, packaged in a single file.

You're already addressing the same problem for JavaScript files, by minifying and single-filing JavaScript and CSS assets, right?

In other words, the real problem is this: delivering many small files efficiently.

But what you get with image-fragments, is something very specific - an image-specific solution that makes one particular image-specific work-around a bit more workable.

It's too short-sighted.

Since this problem is important enough to warrant another HTML/CSS extension, why we can't we have a solution that addresses the root of the problem?

Both servers and clients have support for gzip already, so the technology is already there - it just needs a bit of adaptation. For example, a URL-notation for addressing files in archives. Since we don't use the "#" sign in resource URLs, we could apply it like so:
http://site.com/awesome-design.gz#images/button-hover.png
This is a much simpler solution, more general-purpose, and probably a whole lot easier to implement (for browser vendors) than futzing around with images.

In my opinion, the internet needs more general-purpose tools - not more problem-specific solutions, which complicate the medium and lead to more browser-incompatibilities, and more work-arounds.

On a related note, you already gave us the power to futz around with images - rather than forcing us to hack that, why not integrate canvas with background capabilities?

Semantically, cropping doesn't even make any sense for "backgrounds", and that's not what developers are going to use it for - note the close semantic relationships between the words "canvas" and "background"? as opposed to the non-relationship between "button" and "background"...

My verdict: This solution is not elegant.