established 10 years ago
Subscribe to this blog RSS Feed


(This is a re-post of an article I wrote last year. I used this analogy to explain to non-technical people why software patents are such a terrible idea.)?

Having mice in your kitchen sucks. They eat your apples. They spread disease. They freak out your girlfriend. She becomes unhappy and refuses to cook.

You face another lonely night eating ramen noodles.

So, because you are highly motivated by having a happy girlfriend and being fed a real dinner, in a moment of genius clarity, you design a better mouse trap.

You build a prototype.

Eureka! It works!

There is much happiness because now your kitchen is mouse free, your girlfriend is happy and you are no longer subsisting on noodles alone in the dark.

You think to yourself, society could really benefit from this better mouse trap.

The problem is you dont have the money to mass produce and market it. But if you show your design to manufacturers whats to prevent them from producing it themselves and cutting you out?

You decide to keep it secret. This is not good for society because we all need a better mouse trap.

Enter patent law.

Patent law is intended to protect the inventor and simultaneously provide a public good. You file a patent in which you describe your invention in detail along with exactly whats new and novel about it. This is good for society. Its a better mouse trap and now society at large knows how to make it.

In exchange for sharing your invention with the world, assuming the patent office agrees that it is not something obvious that anyone could have thought of, society grants you a temporary monopoly on your particular better mouse trap. No one else is allowed to produce the same mousetrap or use it without your say so. Usually you grant your permission for others to produce it in exchange for some payment in the form of license fees.

If someone goes ahead and makes your mouse trap exactly as you have described in the patent without your permission, you can sue them for huge damages. You can even file an injunction against them and prevent them from continuing to produce the mousetrap you designed. Whats even better for you is that the full weight of patent law is behind you, the patent holder, so its really difficult for even big companies to defend themselves against your claims.
A patent is a very powerful monopoly which is good because we need a better mouse trap and we want you to design one and be rewarded for your efforts.

But because it is such a powerful monopoly and monopolies are bad for competition and innovation, we want to make certain that you can only patent your mouse trap and not something else. This is relatively straight forward because your better mouse trap is a physical invention and the mechanism of the invention is clearly described in the patent application along with what makes it unique. We can all agree on what makes it novel and more importantly we can compare your mousetrap and somebody elses attempt at a better mousetrap and all agree whether or not the two are the same. Normal mouse traps snap. Yours, for instance, spins. Does their mousetrap spin in the same way? If not, then its a different mouse trap and your patent doesnt apply. If it does, you have the power to ruin their day.

But we also want competition. We want, for the public good, some other inventor to look at your new mousetrap and think Thats a good idea, but I can do better. Even with your new better mouse trap we need better mouse traps because mice are damned smart and adaptable and continue to make for unhappy girlfriends. After all, you dont want to starve. Patents are supposed to foster innovation and invention.

Now with patent in hand and the full weight of patent law behind you, you can go to manufacturers with confidence and negotiate to get your better mouse trap produced without fear that they will cut you out.
Its such a powerful idea that its ingrained in American mythology. Even today getting a patent is a mark of success, intelligence and status.

But there is a dark side to patents that we need to avoid.

We want to prevent someone from patenting in a way that has unintended consequences. For instance, we dont want someone to be able to patent the idea of a mousetrap. If a person could do that, they would have the power and right, based on current patent law, to go and demand money from anyone who produces mouse traps, even if those people have been producing mouse traps for years. Worse yet, because of the power of patent law, such an individual could even shut mouse trap manufactures down.

Imagine if someone could patent the idea of using a spring in a mousetrap. Or the concept of a spring in a trap. Suddenly, with such a patent in hand, someone could go out and start suing manufacturers of mouse traps, rat traps, cat traps, rhinocerous traps, you name it.

method and process for releasing stored potential energy to effect intruding entity capture.

That doesnt seem right, now does it?

If Ive been building something for years you should not be able to patent some part of it and then demand money from me or force me out of business.

Luckily for us, such a thing doesnt happen. Or does it?

Well, unfortunately for all of us this is exactly what is happening in the software industry right now and its getting much worse.

No lie. No exaggeration.

How can that be?

Lets take our example above of a better mouse trap and change it.

Consider a virtual reality game where theres a kitchen, a freaked out girlfriend, some food thats not getting cooked and some mice.

So for the game you come up with a better mouse trap. You write some code. Save it in a text file and include it in the game. It lays out the way the mouse traps looks and works. Its identical in every way to your physical mouse trap. In the video game it rocks. It is as effective as your real mouse trap and your virtual girlfriend is just as happy as the real girlfriend you wish you had would be, if you werent single spending all your time inventing virtual mouse traps.

You go to apply for a patent on your virtual mouse trap. Most people would think that if the physical mouse trap is patentable, and we all agree it is, then the virtual copy of that mouse trap should also be patentable.

Makes sense, right?

There is a serious problem with this that has far reaching consequences.

There is no mouse trap.

Nor is there a kitchen or freaked out virtual girlfriend.

There are only 1?s and 0?s in a computer simulation and what those 1?s and 0?s mean is entirely up to interpretation.

Its software after all.

I dont know if you know this but a computer, no matter how advanced or powerful, is just a set of switches that are either on or off.

Youve heard about gigs, right? Gigs of memory? Gigs of disk space? Gigs of pirated music on your ipod?

A gig is short for gigabyte which is 1073741824 bytes. A byte has 8 bits. A bit is a switch. It can be on or off. On represents 1. Off represents 0.

All the magic that happens in a computer is reduced to these 1?s and 0?s. Billions and billions of switches. Even this article you are reading right now. Each point on your screen is represented by a bunch of bits.

So when I say there is no mouse in your virtual game I mean it literally. What you perceive as a mouse on the screen is just a series of dots represented by a series of 1?s and 0?s. The same goes for the virtual kitchen, the freaked out virtual girlfriend and your newly invented virtual mouse trap. What you think you see is all an illusion. Its just changing patterns of bits.

But you still want to file a patent to protect your better virtual mouse trap, because thats what you see. What do you patent? A virtual mouse trap? Of course not. There is no mouse trap. Its just 1?s and 0?s.

Have I lost you yet? We have what looks like a trap. We have what looks a mouse. But really its all software and data, just changing patterns of 1?s and 0?s.

So faced with this conundrum, maybe you describe your invention in generic terms of matching an entity pattern that youre interested in, i.e. virtual mouse, and then triggering some interrupting action that prevents further copying of the entity pattern, i.e. springing the trap.

The sample code might look something like:

while we have not detected the pattern of an entity (i.e. mouse) in memory we're interested in

continue to look

otherwise interrupt the program to halt the entity (i.e spring the trap killing the virtual mouse).

You file to get a patent for your software invention, i.e. a software patent, and the patent office grants it to you because maybe its a Friday and they have quota to make so they rubber stamp it.

What have you patented? What power have you been granted? How do you tell who is infringing on your newly minted intellectual property?

Clearly you could go after any video game makers that have representations of your virtual mouse trap. A jury would probably buy that. But, because its software, how do we tell if some virtual mouse trap is the same as yours? Because it looks like the same on the screen? What if its a black and white screen? What if there is no screen? What if the interface the user whos playing the games uses is for the blind and its based on sound? How do we tell if its the same mouse trap?

You look at the patent claims. Theres a monitoring entity. Check. Theres a pattern being looked for. Check. Hmm. Based on this it looks like youve patented every kind of virtual mousetrap that could possibly be created. A jury in East Texas might buy that.

Because there is no mouse trap. Its just software monitoring other software searching for a pattern.

Then you meet a lawfirm who sees the patent you have been granted. They buy it off of you and aggregate it with other patents they have.

And they go and sue all makers of anti-virus software out there because clearly your mouse trap algorithm sounds like what anti-virus vendors do, doesnt it? Anti-virus software does pattern searching for patterns its interested in and halts offending programs. Clearly its a virtual mouse trap.

But all you wanted to do was to patent a mouse trap in a video game and now this lawfirm you sold the patent to is going out and ruining the day of some anti-virus vendors.

Unintended consequences.

Now it gets bad for the anti-virus makers. The lawfirm sues them because they are able to convince a court they have a right to sue. Clearly you would expect that if it goes to court the court will see that what was patented was intended to be a virtual mouse trap and the patent would be thrown out?

Unfortunately for the anti-virus vendor, they have to hire really expensive attorneys to defend themselves. As of 2004, the average cost just to get to the point where you are in front of a judge is over $1M. Yes, thats a 7 figure number.

Again, all you did was patent a virtual mouse trap.

Most patent litigation happens in East Texas. From what I have read, the population there is very property rights friendly and if the patent office granted you the patent then clearly you have something valid.

So even if the anti-virus vendors spend seven figures and go to court they might lose because what anti-virus vendors do sounds very similar to what a virtual mouse trap does. The risk is great because the damage awards in patent litigation are out of this world.

So the anti-virus vendors do what most people in this situation do. They settle. Even though they do not write virtual mouse traps the costs of litigation are so high and awards so great that it often doesnt make sense to try to fight.

And they pass the added costs onto consumers.

With a little imagination the patent troll could probably find a whole bunch of other kinds of companies to sue that produce a wide variety of software systems that all infringe on your mouse trap patent. The patent troll is happy because for little work he gets to retire rich without actually contributing anything to society.

This is not what patent law was intended to do. It was supposed to make it so inventors would have an incentive to invent. It was not meant as a way for people to make a living through lawsuits.

Now you may say that there have to be a class of software inventions that would be worthy of patent protection. But heres the rub. All software is 1?s and 0?s. With software there is no way to have an unambiguous and verifiable result. We cant all hold it in our hand and agree on exactly where the limits of the invention are. There is no way to, ahead of time, know whether or not a piece of code might be seen by some jury to infringe on some patent. (And then theres the whole thing of people patenting really obvious things they learned in school, but thats another, albeit related, story.)

Because software is just an idea. It doesnt actually exist.

Software is 1?s and 0?s and therefore always left up to interpretation. So its more like the story in a book. What it means and where its boundaries are are left up, in part, to the reader.

This is why software should never have been allowed to be patented in the first place. Because of the written prose nature of software, any software patent suffers from unintended consequences and will by definition always be over-broad and can be re-interpreted to match situations that the original inventor never envisioned.

What should protect software is the same as what protects books and other works. Copyright. I write it you cant copy it without my permission. If you want to write something similar go for it. Its good for society for us to compete and see which of us can do the better job.

Of course you are thinking it couldnt be that bad. Clearly a virtual mouse trap is a contrived example. But unfortunately the mouse trap patent above has more merit than many that are being litigated now.

Recently, one company, LodSys, claims to own a patent on in-app purchases from smart phones and their strategy is to go after small one and two man shops and sue them for a percentage of their revenue to establish precedent.

'Here is the claims section of their patent as mentioned in this article (Personally I do not agree with the recommended course of action. Small developers simply dont have the money.):

1. Asystem comprising:

units of a commodity that can be used by respective users in different locations,

a user interface, which is part of each of the units of the commodity, configured to provide a medium for two-way local interaction between one of the users and the corresponding unit of the commodity, and furtherconfigured to elicit, from a user, information about the users perception of the commodity,

a memory within each of the units of the commodity capable of storing results of the two-way local interaction, the results including elicitedinformation about user perception of the commodity,

a communication element associated with each of the units of the commoditycapable of carrying results of the two-way local interaction from each of the units of the commodity to a central location, and

a component capable of managing the interactions of the users in different locations and collecting the results of the interactions at the central location.

The whole patent is here:

The original intent of the invention was some kind of phone/fax machine that talked over dialup lines to some server back in 1988. LodSys somehow bought or otherwise obtained the patent and decided to start suing en-mass recently.

What are they saying this patent applies to? Buy Now and Upgrade buttons linked to iTunes or the Android Market.

Yes. Buy Now buttons. Just the buttons. Nothing else.

Quite the genius invention that needed to be disclosed for the benefit of society and could only be done through the protection of a patent because otherwise no one would ever have come up with the idea of a buy now button, eh?

So if you put a button in your software linked to a store they want a percentage of your revenue or theyll have the court of East Texas issue a summons for your sorry self to ruin your day. In other words, if they have their way they want to impose what amounts to a tax on all makers of software because everybody has buy now buttons and has had them in software since the early day of the internet. And, of course, its completely obvious. I sell something so I want to put a price tag on it and a way for people to buy it. Genius invention, eh?

Some of the guys in danger of getting sued are just little guys writing cool apps on their own without a company around them. What are they going to do when they get sued for doing something so obvious and normal as a hey, click here to buy my app kind of link? All of their personal assets are at risk. How on earth could any reasonable person think that such a thing could be patentable? How on earth does anyone who gets hit by one of these baseless lawsuits defend themselves when patent law is so skewed in favor of the patent holder? Patents were supposed to protect the little guy against the big guys, not make it easy for non-practicing patent trolls to bully the little guys.

Heres the kind of letters LodSys are sending out:

The problem is we small developers dont have 7 figures to spend defending ourselves. Hell, we cant even afford the initial consultations with an attorney.

Those of us in the software industry always held that software was something that should never have been patentable because we saw this future coming. But in 1994 a judge ruled that software could be patented and the mess of unintended consequences began.

Why should anyone outside of the software industry care about this kind of patent abuse?

Think about it the next time you buy a phone, a car, a music player, or any other device that has any code in it. What percentage of your hard earned, hard fought precious money is going to pay off some non-practicing patent holder, a.k.a. Patent troll, who figured out he could abuse the patent system to sue for a percentage of revenue not so he could build anything but instead just to get rich by taking.

Think about it the next time you wonder why things are so expensive.

Think about it when your kids are looking to start small companies or their employers downsize because of litigation expenses.

Or more importantly, think about it when you do anything online. Even if you just have a small business or personal site doing something completely normal you are not immune:

Software patents expose even average citizens to unacceptably high risk of litigation. Yes, even you.

Patent law must change. If it does not our other American industries will go the way of our auto industry and our cost of living will go up as a result. If you are anti-taxes, you should be even more incensed by the tax you pay every day to people who abuse the patent system and offer you no benefit in return whatsoever.

Its unlikely given how long this mess has been going on that software patents will be done away with, despite that being the correct solution, but something has to change to avoid letting patent trolls have too much power. Small business and startups are what drives the economy forward. The ideas that will keep your children employed in the future are being developed by small entrepreneurs today and this patent situation is putting a dark cloud over that part of our economy. Many who would otherwise be willing to start businesses are shying away because the risks are becoming too great.

Heres some additional reading for the interested:

After too long, and many many requests, I've finally managed to rebuild the daily digest. It summarizes the goings on on the site for members to let them know what's going on.

Previous versions had been text only so I figured, following the lead of just about everybody else, that I would try to send out something in HTML. Of course, I'm a backend developer server/network/database guy and not a designer.

It turns out that Gmail and the Android Gmail client do not support the <style> tags. In addition, they strip out the <body> tag and turn it into a <div> which can cause some havoc to your layout.

The ugly answer to this conundrum is to use style attributes everywhere, which can get quite ugly and be unmaintainable.

So instead of rewriting all the markup I had created, I looked for and found a PHP library that would rewrite the markup on the fly parsing the <style> section at the top of the page and applying style= attributes everywhere. This works surprisingly well.

The library can be found here

There's a bunch more work I could do on formatting the email and attempting to make it more responsive. But I think for the moment, this is probably good enough.

Quick Update on HHVM
Monday December 23rd 2013

I took Miles by Motorcycle live on HipHopVM on December 15th.

I was concerned about crash problems since it's a long lived process so I set it up to be monitored by ?upstartd, which will restart the thing automatically if it crashes. However, it's been remarkably trouble free.

It simply works.

I was playing with Google's Webmaster tools a bit when I came across this interesting graphic showing crawler page download times for the last few months:


It's pretty obvious when the site was switched over to hhvm. :)

Simply fantastic.

My intention with my my "Adventures in Configuring HipHopVM" article was to describe my experiences in the hopes that it might be useful for someone else who's trying to get hhvm running. Maybe I could save someone else some time and headache. I didn't do any rigorous performance benchmarking but I did post the observation that one one particularly slow page I have, which was loading in something around 5 seconds on my development machine under PHP, would load in around 0.6 under HHVM. HHVM is wickedly fast but I didn't think much about it because it wasn't what I was focusing on. I was just happy my code was running on HHVM at all.

Imagine my surprise when the article was shared out by the HipHopVM Facebook page. From there it found it's way to Reddit. Then an article was written about it on the HighScalability blog. A number seemed to latch on to the speed observation.

They say you should never read the comments because only pain and darkness awaits you there. But I did not heed this sage warning and went obsessively reading all comments I could find. My world darkened and I began to despair.

One comment posted to the HighScalability blog article stuck with me:

"How does it compare to a modern php (5.4, 5.5) best-practice implementation? This seems a very roundabout way to improve performance, verging on architecture astronautics, unless he is trying to get a job at facebook. ... We have to take his word for everything."

This got me thinking. While the focus on the article was on getting it working with a non-trivial codebase, he does have a point that there's no way to independently verify the result since my code is not opensource yet, and may never be.

My platform is a mix of SQL, noSQL on top of MySQL (akin to the way FriendFeed implemented a NoSQL layer), tons of classes, a custom XML domain specific language parser, expression evaluator and a lot of I/O. As such it has many external dependencies that are greatly affected by configuration changes and what else is happening on the machine. What it does not do is strictly isolate the core PHP language itself so that one can make a clear apples to apples comparison between PHP and HHVM language implementations. We could do something similar to compare the full stack but that would then involve comparing the HipHopVM stack to other components such as Apache.

Interestingly the commentor went on to state that "modern php is not slow".

In computing as in motorcycling, if you have never gone fast then slow may seem fast. PHP is an interpreter. Of course it's slow.

As a general rule, I don't believe in benchmarks. They give you little insight into how a given thing is going to perform in your use case. I can tell you, subjectively, across everything I have run through it, HHVM is "way faster" than PHP ranging from 2X to 9X faster depending on the situation. For most scenarios I've tried it seems to sit somewhere between 2X and 3X faster.

I don't specialize in benchmarking but I have spent some time trying to think of a real world problem one could use as a fairly decent benchmark that would have a few qualities:

  • it would be something useful.
  • it would test the speed of the core language without involving extensions and it would not be I/O bound.
  • it would clearly demonstrate how hhvm can allow PHP to be used in problem domains where it currently makes no sense to do so.
  • it would be something that can be independently verified.

I thought about some code I evaluated at one point when I was trying to increase the performance of my expression parser, an LALR1 parser generator for PHP. It allows you to build robust parsers in PHP much the way you can in C/C++ using Yet Another Compiler Compiler (YACC) or it's wonderfully named cousin Bison. Unfortunately, the parsers generated using this tool were unbelievably slow. I wondered if maybe one of the examples bundled with it could be used as a decent benchmark.

It turns out that one of the examples involves a generated parser for a custom expression language which is then used to evaluate a bunch of expressions. It's all in code and involves no I/O or external dependencies. It's also algorithmically intense and will work a good percentage of the core features of the language.

"Perfect", I thought as I went to modify the test to add some timing.

Reproducing the LALR(1) in PHP Performance Test

To reproduce this test, download Ppage the PHP Parser Generator project from: The code is in english. The example code in question is inppage/examples/expressionLanguage/test.php.

The intent of this test is to isolate it to the PHP runtime as much as possible so any errors or I/O need to be disabled. Luckily this is easy to accomplish.

The code generates two warnings which are annoying in a loop and will affect results. Add "@" error suppression to each. The two warnings are:

PHP Notice: Uninitialized string offset: 21 in ppage/examples/expressionLanguage/ on line 401

PHP Notice: Undefined index: codeopen in ppage/lib/ on line 74

There is an intentional parse error which generates a message on line 76. comment that out.

I altered test.php to remove the print statements and to execute all steps in a loop of 1000 iterations.

Alter test.php and replace everything after line 569 with:

$startTime = microtime(true); $counter = 0; while ( $counter++ < 1000 )     {     $i = 0;     $call = new ELCallBack(); foreach ($exprs as $expr)   {          $elex = new ELLexer($expr);   $elex->lex();   $parser = new ParserMachine ($elex, $parsertable, $parserproductions);   $parser->run($call);   $result = $call->getAST();   $call->reset();   } } $endTime = microtime(true); $time = $endTime - $startTime; print( "Time elapsed: " . $time . "\n"); 

Test Configuration

I'm running Ubuntu 13.10 64 bit on a cheap several years old Dell with an Intel(R) Core(TM)2 Duo CPU E6750 @ 2.66GHz and 4 gigs of ram.

PHP version:

yml@humility:expressionLanguage$ php --version PHP 5.5.3-1ubuntu2 (cli) (built: Oct  9 2013 14:49:12)  Copyright (c) 1997-2013 The PHP Group Zend Engine v2.5.0, Copyright (c) 1998-2013 Zend Technologies     with Zend OPcache v7.0.3-dev, Copyright (c) 1999-2013, by Zend Technologies 

Stock Ubuntu 13.10 configuration using mod_php and Apache.

HHVM version

yml@humility:expressionLanguage$ hhvm --version HipHop VM v2.3.0-dev (rel)  Compiler: heads/master-0-gfc37017a7e1a7d3fa835c3e09a2937f6f4f703ce  Repo schema: 5a59384aec1e7bb9b316f27ae87d6c2a5cd57f76

Configuration per my previous article. The build in question is not a debugging build and is one I compiled myself. (takes forever)

LALR(1) Test Results

I first ran the test on the command line using PHP:

yml@humility:expressionLanguage$ php ./test.php Time elapsed: 5.0141038894653

then followed by HHVM:

yml@humility:expressionLanguage$ hhvm test.php Time elapsed: 5.5141990184784

At this point I was a little disheartened. I had expected HHVM to be faster in all cases. I had been told by the HHVM developers that hhvm first profiles the execution before invoking the JIT. I believe they said it happens after 10 or so requests. Figuring that maybe this is not invoked when run as a command line interpreter, I repeated the experiment in the browser running the test 15 times. This should give the JIT compiler a chance to get involved.


Time elapsed: 5.0715029239655 Time elapsed: 5.067526102066 Time elapsed: 5.0686640739441 Time elapsed: 5.1444919109344 Time elapsed: 5.0798120498657 Time elapsed: 5.0674719810486 Time elapsed: 5.0758039951324 Time elapsed: 5.0680429935455 Time elapsed: 5.0671808719635 Time elapsed: 5.1225011348724 Time elapsed: 5.0637631416321 Time elapsed: 5.0711719989777 Time elapsed: 5.0798349380493 Time elapsed: 5.0700869560242 Time elapsed: 5.0699179172516


Time elapsed: 5.9072468280792 Time elapsed: 5.9045979976654 Time elapsed: 5.8999648094177 Time elapsed: 5.8969769477844 Time elapsed: 5.8965940475464 Time elapsed: 5.8854668140411 Time elapsed: 5.8934369087219 Time elapsed: 5.8918490409851 Time elapsed: 5.8934841156006 Time elapsed: 5.8858242034912 Time elapsed: 5.8903369903564 Time elapsed: 1.5902738571167 Time elapsed: 1.5128128528595 Time elapsed: 1.5166771411896 Time elapsed: 1.5109701156616 

And one can clearly see where the JIT was invoked yielding, in this case, a 70% reduction in execution time. Not as dramatic as 0.6 but still impressive.

There are many other aspects of the system that could be tested to paint a more detailed picture of the performance differences between PHP and HipHopVM. One can lose a lifetime trying to benchmark every feature of a given platform and emerge from the exercise no wiser.

HHVM vm-perf Tests

HipHopVM includes a few intense benchmarks that exercise narrower feature sets. These can be found in the github repository.

Out of curiosity, I decided to experiment with a few of these.

I used the same configuration as above except for these I used wget in a loop on the local machine and stopped it after 15 requests as in:

while true; do time wget -q http://localhost/vm-perf/fibr.php; done

The tests run long enough that the overhead of processing the tests and returning the result represents a negligible percentage.


This test computes the n'th Fibonacci number recursively up to 35.


This ran pretty consistently around:



Before the JIT kicked in it was slower than PHP.


But once the JIT kicked in:



This test is designed to be used as a benchmark and contains a number of different sorts and calculations.




Before JIT:


After JIT:



This is the one test case I've been able to find where PHP outperforms HHVM.




Before JIT:


After JIT


I found this test interesting in that the JIT had a profoundly negative impact in this one scenario. I suspect this is probably due to some issue that will get resolved. The HHVM team is constantly pushing the envelope of performance and I expect they will find many more ways of improving this platform as time continues.


As a general rule, benchmarks don't tell you much about how a given technology is going to perform in your particular use case. They just make an argument that it might bear investigation. Is PHP slow? Slow is relative. It is clearly much slower than HHVM in a wide range of use cases. Of course we would expect this since PHP is an interpreter and HHVM is a native compiler.

In my particular use case, which is likely representative of a wide range of web application platforms, HHVM represents a vast performance improvement over PHP without requiring me to change my code.

Parting Thoughts

Because of this constantly improving speed and the multi-threaded nature of the hhvm server, I suspect that the range of problems that PHP can be used to solve will expand.

Personally, I would love to see more multi-threaded features exposed in PHP. Yes, there is already some basic multithreading support added available. But it would be awesome if one could launch long lived services in separate threads. For particularly large and heavy frameworks like my own, this would be a boon. Build up your application object trees once and then re-use across requests, you know, like real server software.

Such support would also open a host of interesting possibilities. AMQP/STOMP in PHP? XMPP? NodePHP?

I'm getting a little closer to fielding Miles By Motorcycle on the HipHopVM (a.k.a. hhvm) stack. I, however, ran into a last minute snag having to do with some disconcerting warning messages in the error log:

HipHop Warning: Invalid argument: function: not a valid callback array

hhvm is much better than PHP at generating meaningful warnings about potential issues in your code. I was a little troubled by this message, however, since it did not provide me a call stack or even a function name. I always suspect my own code and understandings first, so I was fairly convinced it was something I was doing. It turned out to be an hhvm issue in that the custom session close handler was getting called twice. I originally tried using GDB to track through the code, but this was getting me nowhere I switched to configuring the hhvm debugger.

Unfortunately, this was not straightforward since there are a few gotchas.

The hhvm debugger can be invoked in two ways. You can run it interactively to debug local scripts, which in my case is of little use, or you can debug requests coming in from the browser. The latter case, once it works, is extremely cool.


From the documentation I had a few misconceptions:

  • There is a "-m debug" switch for hhvm to enable the debugger, but this does not, by itself allow you to debug server requests.

  • You configure the server to enable remote debugging but you must use a second instance of hhvm called with "-m debug" and connect it to the first.

  • You cannot, to the best of my knowledge, get access to the threads serving requests on the live site. You must set up a debugging "sandboxes".

  • "sandboxes" consist of a user name and a sandbox name and these must be included in the hostname part of the URL you use to pull the page. The sandbox name refers to an entry in a .hphp file in the users home directory.

  • The documentation shows the format of the .hphp file as [sandbox].path=... but the format is actually sandbox.path= where sandbox gets replaced by the name of the sandbox.

  • Each sandbox gets it's own document root, access log and error log that are completely separate from the main site. In my case I just created a symlink to my sites DOCUMENT_ROOT and called it done.

  • It does not appear that you have access to rewriting rules from sandboxes making debugging a full site somewhat challenging.

  • The user account that you run the debugger as (using the -u option) should match the name of your sandbox account to avoid a nasty hanging issue when running the server and debugger on the same machine.

Configuring the HHVM Server for Debugging

There are a few steps involved to configure the server.

Sandbox Account and Hostname

The sandbox user account and sandbox name must be included in the hostname part of web requests made to your sandbox server. i.e.

There are probably other ways to do it as the hhvm Debugger unit tests imply, but in my case it was easier to just add an entry in /etc/hosts for my sandbox account name.

Sandbox names are split on a - and have the form sandbox_user-sandbox_name. If no sandbox_name is included, then the name 'default' is used for the sandbox.

Since I'm only working on one site right now, I added a user 'sandbox' to my machine and added a entry to /etc/hosts. (replace mbymc with whatever domain your machine is on)

If I were working on more than one codebase, I could set up separate sandboxes like 'sandbox-site1', 'sandbox-site2', etc.

The HHVM Server Config File

Refer to the runtime options Sandbox Environment section:

You have to add a few blocks to your config.hdf.


Add this block to your servers config.hdf:

Sandbox{SandboxMode = truePattern = ([^-]*(-[^-]*)?).mbymc.comHome = /homeConfFile = .hphp}

Based on my testing, it looks like SandBoxMode must be set to true for this to be enabled.

The idea behind the Pattern setting is that it's a regex that must separate out two matches, one for the user account part and one for the optional sandbox name part. As I mentioned above, if there is no sandbox name part, the name 'default' is used.

The Home path is prepended to whatever the account name is and is used to search for the .hphp file. For example, if the request from the browser contains, the .hphp file for that request will be looked for in /home/sandbox/.hphp.


Add the following section after the Sandbox section:

EnableDebugger = true
EnableDebuggerServer = true
Port = 8089
DefaultSandboxPath = /path/to/docroot

The Sandbox Configuration File .hphp

The sandbox configuration file resides in the home directory of whatever account you're using for your sandbox. In my case I created a /home/sandbox account for this purpose. I created the file


This file contains name/value pairs that define your various sandboxes for that account.

default.path = www
default.log = error_log
default.accesslog = access_log

The path is relative to the home directory so I simply created a symlink from www to the DOCUMENT_ROOT of my site. You can have entries for multiple sandboxes. If you had an additional site, you could, for instance, add:

site1.path = www2
site1.log = site1_error.log
site1.accesslog = access_log

Testing the Sandbox

Fire up your newly configured hhvm server

hhvm --config /usr/local/etc/hhvm_debugger.hdf -m server

Create a test.php file in the DOCUMENT_ROOT of your sandbox. Have it do something like print hello:

print( "<p>Hello</p>" );

Now load the file from your browser. In my case, the url was

You should see some output on the page.

Using the hhvm Debugger

Make sure that you pull a page from your sandbox server BEFORE proceeding from this point. Once you have pulled a page, you can now attach a debugger to the sandbox.

Fire up the debugger in a separate terminal window.

Enter the following command:

hhvm -m debug -h localhost -u sandbox_user

where sandbox_user is whatever user you chose to host your sandbox.

NOTE: Specifying the right user seems to be key in making this work correctly. Originally I would run the debugger under whatever user account I was in at the time and I would notice that the debugger would hang indefinitely on the attach step below more times than not. After trial and error, it seems that specifying the sandbox user on the debugger command line (instead of listing and attaching to sandbox instances) avoids this problem.

You should see:

Welcome to HipHop Debugger!

Type "help" or "?" for a complete list of commands.

Connecting to localhost:8089...
Attaching to sandbox's default sandbox and pre-loading, please wait...

NOTE: You may need to run with root permissions to avoid a permissions error here. YMMV.

Refer to the Debugger overview documents here:

You can now set a breakpoint to fire at the beginning of every request.

break start

You should see:

Breakpoint 1 set start of request.



Now reload your sandbox page. You should also notice that the webpage is just hanging waiting for a response.

In the debugger you should see:

Web request /test.php started.

To let the request complete, you can enter the command:


You will notice that the prompt does not return after you do this. Reload the sandbox page in your browser in order to trigger the breakpoint and get the prompt back.

You can also press CTRL-C to get the debugger prompt back. This works as long as the debugger is running as the same user as the sandbox (at least in the case where both are running on the same physical machine).

From this point forward the debugger works as you would expect. You can set breakpoints, inspect variables and even execute arbitrary code.


In crawling around using GDB when I was looking at the HHVM source one of the traces seemed to indicate HHVM was trying to call a NULL custom session close handler. So I created a test file which is included on this issue: It's just a dummy custom session handler.

In the debugger, I made sure to set a start of request breakpoint.

break start

I loaded the page implementing my test_session_handler.php test and the page load was interrupted at the start.

Web request /test_session_handler.php started.

I could now set a breakpoint at the start of _session_close():

break test_session::_session_close()

Which replied:

Breakpoint 3 set upon entering test_session::_session_close()
But wont break until class test_session has been loaded.

Now at the prompt I could enter


which caused the breakpoint to fire on session close which displayed:

13 {
14* print( "session close<br>" );
15 return true;

I entered continue a second time and instead of having the script complete the same breakpoint fired again clearly indicating hhvm was calling the custom session close handler twice on exit.


The debugger has surprisingly decent online help. Just enter "help" at the debugger prompt for an overview. You can also get help on individual commands such as "help break".

An overview article on using the debugger:

HHVM Runtime Configuration Options:

More docs on using the debugger:

You can follow me on twitter:

Years ago, faced with the need to build and manage a number of content websites, I developed a novel content management system akin to what Joomla or Drupal are today. I've always run my own servers so I could have chosen any development language. I briefly considered Java. However, suffering from delusions of grandeur, I wanted to make certain that whatever I built was as widely installable as possible. I envisioned building a successful open source platform that I could then build a services company around. Low cost hosting featuring Apache, PHP and Mysql were abundant. Many people getting into programming were learning PHP. My feeling was PHP would take off, so I decided to adopt that language despite thinking it smelled funny. I second guessed myself, as I am want to do, and feared putting in huge amount of work only to have the platform it was built upon become non-viable. I knew the majority of the work would actually be in building the forms and views that made up the system. To hedge my bets, I created a pedestrian XML "web component description" language that allowed me to describe the forms, views, validation, and business logic. This isolated me from relying on PHP too much. I called this language the formVista Markup Language or FVML. Honestly, I always thought the PHP implementation would just be a prototype. My thinking was that eventually I would just rewrite the parser in some other better language because obviously only a madman implements a web development language in PHP.

Reimplementing the parser never happened because for all the projects that I needed, this codebase ended up being "good enough". I still prefer it to Wordpress, Joomla or Drupal. I decided to try and build Miles By Motorcycle on it because I still prefer it to those other platforms. (I really tried. I even installed Wordpress. I did a project in Drupal and even evaluated Diaspora.) In retrospect, I probably should have chosen other technologies and approaches since M-BY-MC doesn't need to be "installable" in the way the code needed to be before. Unfortunately, M-BY-MC highlights just how badly my legacy platform performs when stressed.

Pages are loading wickedly slowly and it's primarily in evaluating expressions in my FVML language because PHP's string handling is so slow. I really didn't want to rewrite the expression parser in C++. As a fallback I was going to write a "compiler" for FVML to translate it into static PHP instead of building the parse trees on the fly.

Enter Facebook's HipHopVM JIT Compiler

Facebook had an analogous problem. Programmers who only know PHP are relatively inexpensive to hire. Facebook hires bunches of them. But there's a cost in terms of hardware. Facebook has to run more hardware as a result of the inefficient PHP stack. So Facebook embarked on the insanity of building their own from the ground up complete PHP stack in-house. Originally this took the form of HipHop, a PHP to C++ translator which yielded around a factor of 5 performance improvement. The problem with HipHop was that it was a different development process. You couldn't just edit your files and immediately see the result. You had to compile and re-run.

So, expanding on their insanity because we all know it's simply not possible for any mortal to accomplish, Facebook boldly took the additional step of turning their PHP to C++ translator into a full fledged PHP to Native Binary Just In Time (JIT) compiler. This is nuts. It even features an integrated web server. Now, the development process was the same as with the original PHP stack. Just edit a file and load the page in your browser.

The original PHP in Apache uses up a bunch of RAM. A separate fork of Apache handles each page request. The PHP interpreter is constructed, the PHP files are loaded, compilied into bytecode, the bytecode is intepreted, output is generated and PHP is torn down again on each request. You can get it to skip the compiling into bytecode step for some modest performance gain.

HipHopVM is vastly better designed in that it's a multi-threaded long lived single instance. It loads everything once and then just checks to see if it's changed. After running a given PHP file a few times, it then compiles it to native binary code which is directly executable. This code is cached. It's only updated if the source PHP file changes. This alone represents a huge performance gain.

One of the developers told me that because they run the code first a few times they can do some profiling of a sort to actually generate more optimized binary code than a static compiler can in some if not many instances. There were some cases where PHP code run in HipHopVM ran faster than the equivalent C++ code.

We know this is not possible, but they have done it anyway.

Crash Testing HipHopVM with the Miles By Motorcycle Codebase

Of course, I knew there was simply no way in hell that HipHopVM was going to be able to run my codebase. But I was curious to give it a try to see how badly things broke.

The Miles By Motorcycle project now consists of over 500 PHP files and some 1200 FVML files in addition to a bunch of javascript, support scripts and static assets not to mention a modestly complicated MySQL backend. I do my own file loading and have a custom session manager. There's even a complete setup script.

It's a herculean effort to create something with parity to the massive number of extensions written for PHP. However, I was impressed by how many extensions they already supported. Luckily for me, because I was suspicious of PHP I limited my reliance on extensions whenever possible and this served me well as HHVM already supports all the extensions I need: mysql, gd, session, pcre, posix, xml, hash, imap, openssl, exif

I pulled down the binary distribution. I couldn't figure out how to get the rewrite rules working, so I just decided to see if it could run the setup script, parts of which were itself written in FVML which means the entire parser and all that support code would get tested. There was no way this was going to work.

Imagine my shock and horror when HipHopVM executed all the pages of my setup script including setting up the databases flawlessly!

Needless to say I was incredibly impressed.

I searched around github and on the web to get more information about the weird configuration file format HipHopVM uses. There wasn't much out there but with some trial and error I managed to get the public homepage of the site to load and was able to navigate around the site. Impressive.

The Problems I Ran Into


It wasn't all trouble free. The first problem I ran into was a HipHopVM crash on a certain page. I joined the IRC channel where it was said the developers tend to hang out. I lurked for a while to see how the conversations went. The instructions there are to type hhvm-help: with a question to get their attention.

While I didn't really expect a response, I did give it a try and to my great surprise I was immediately chatting with someone from Facebook who was taking my crash report very seriously.

I have to say everyone I have chatted with over there has been extremely nice, professional, and helpful. Despite being busy and deluged with lots of help requests, they were always pleasant and seemed honestly interested in helping. I have to say I appreciate it.

They gave me a few tests to run which required me to pull down the source and go through building the environment. This took quite a bit of time. Then came loading hhvm in GDB and giving them dumps. Interestingly, there are some options which you can provide when building which will enable GDB to display the PHP source line an HHVM crash happens on. You have to configure for debugging using cmake -DCMAKE_BUILD_TYPE=Debug . Then when you run the server add the options -vEval.SyncGdbChunks=1 -vEval.JitNoGdb=false

Very cool.

Dutifully, I went back and reported my findings. We went through a few more interations and they found the problem. It turns out I was doing something unanticipated but valid in one method, although they did not tell me what, and this was causing the JIT compiler to generate some bad code. Instead of telling me to change my code, they fixed the compiler and gave me a patch.


Custom Session Handler Support

The second problem I ran into was another crash bug. This one would manifest itself in between 3 and 5 page loads regardless of whether it was a same page reload or navigating through the site. Knowing a bit more this time, I was able to figure out that it was happening in my session handler. PHP allows you to override the default session handler to add in your own, which I do.

This bug had been reported. It's been a little while ago now, but if I remember correctly it was a repeat of my previous experience. Run some tests and report GDB dumps back. Try a patch. Again, everyone was so nice and helpful. After a few days, this bug was also fixed.


HipHopVM currently does not implement this function correctly. It returns garbage results. For this one, since it was clearly a bug (where as the two others before could easily have been something I was doing wrong), I filed a bug report.

One of the guys I had been chatting with in the IRC channel replied saying that this was a low priority for them but they would be grateful if I took a crack at it.

It's been 10 years since I've done any C++ and I haven't worked on a body of code this involved in a long time, but I dove in to see if I could get a handle on the codebase. While it's extremely lacking in comments or documentation, it is pretty well organized and the source files are clean. GDB, of course, doesn't know about the data structures in the code and can only give you basic types back. I asked if there was a way to inspect some of the larger data types and they quickly sent me some python scripts to source into GDB that allows you to view some of them. GDB has come a long long way. I eventually found the code that's misbehaving but not being that familiar with UNICODE implementations I figured I'd best leave it alone and just work around it in my code. I may go back to it and see if I can fix it in hhvm.

Note: HipHopVM defines HPHP_VERSION which you can test for in your PHP code for those rare instances where you need to work around some hhvm limitation or difference.


Interestingly, hhvm defines this function so that if you check for it's existence it will say it's there. i.e. function_exists("imap_rfc822_parse_adrlist") returns true. However, if you then call the function is raises a nasty exception because the function is just a stub that has not been filled in yet. So in an email class, I had to check for this and use a PHP implementation of the function instead.

The Fast Path Problem

This one took by far the longest to track down.

The Miles By Motorcycle codebase relies heavily on URL rewriting and this was working perfectly. However, I want to keep the option of running the same site on the old Apache and Zend PHP stack in case I run into problems with HHVM. This means I want to leave all my .htaccess files lying around but don't want hhvm to server them.

So I thought I could simply write a rewrite rule to present a 404 page when a .htaccess file request is made.

This did not work. No matter what I tried I could not get this to work and then, after some investigation, I realized rewriting only works if the source URL does not represent a file in the filesystem. For example, you can write a rewrite rule from image1.gif to image2.gif but only if image1.gif does not exist. If image1.gif exists in the filesystem, the rewriting rules get bypassed and image1.gif is served immediately.

This seemed very strange so I once again joined the developers in IRC and posted the question. They agreed it was likely a bug so I filed an issue.

Unfortunately for me, the team is currently focusing on getting FastCGI support ready so they won't have time to focus on this issue but mentioned that if I wanted to submit a patch they'd be happy to review it.

I didn't want to wait several months for FastCGI to work well and I thought if I could just get this issue resolved I'd be much closer to having a fully functional HHVM install. The code is so well organized it took me probably less than 15 minutes to find the offending function and to verify, thanks to a helpful comment, that in fact there was a "fast path" optimization that just automatically serves the file if it's present bypassing rewriting rules. The developers had asked that any changes I make should be governed by an additional configuration option and that the current behavior should remain the default. The config file handling is not as straight forward as I would like it to be but I found that I could easily add an option at the VirtualHost level. I submitted my first pull request. I had called the option StaticFastPath but they pointed out the same problem existed with PHP files, which I missed. So the option was renamed CheckExistenceBeforeRewrite and it is true by default to maintain the original behavior. The pull request was accepted so a few lines of code I wrote are in HHVM and I'm on the list of contributors.

Sometimes it's the little things in life, right? If this makes it onto Facebook's servers, the one if statement I wrote, which is invoked in every request, will be the most widely used code fragment I have ever written. Weird and somewhat depressing.

Setting CheckExitenceBeforeRewrite to false gets you the behavior you would expect coming from Apache mod_rewrite.

Configuration and Rewrite Rules

Once CheckExistenceBeforeRewrite was added to the codebase I could get my rewriting rules working. HHVM's configuration file is in an odd format called hdf which looks like some badly form JSON. The documentation is horrible and searching online quite a few people are running into problems working with it. I suspect it was, for many people, the odd rewrite bypass that was tripping them up. I could be mistaken.

Some things about the configuration file that confused me were:

  • sometimes names of sections are meaningful and sometimes they are not. When they are not an * is used apparently as a placeholder.

  • EnableStaticContentCache in the Server {} section does not seem to work. HHVM is unresponsive for an extended period and the process grows to be huge. I have not yet tracked this down or filed an issue about it. I just set it to false.

  • Setting FileCache in the Server {} section seems to break caching.

  • I need to explicitly set the PidFile in the Server {} section.

  • The DefaultServerNameSuffix setting in the Server {} section seems to break $_SERVER['SERVER_NAME']. I leave it blank.

  • In Rewrite rules there is a a condition {} block which is used identify items that you do NOT want to match. Think of it as an "except". Rewrite all of these URLs "except" the ones in the condition block. You must include negate = true in the condition block. I'm not sure what negate = false would be used for in this context.

  • Rewrite rules are in fact applied in the order they appear in the configuration.

  • In order to rewrite rules for files that exist, like to hide .htaccess files, make sure CheckExistenceBeforeRewrite is set to false.

Here's a santized version of the config that I have working on my development machine with some comments:

# HipHopVM configuration file for This is a structured config file format. ## '*' is used as a placeholder where hiphopvm doesn't care what's # present. More descriptive # strings could be used in their place.## See for # more, albeit incomplete, info. ## I have a large legacy PHP codebase that is in dire need of some # performance improvements. It's a content management/social networking# platform supporting user profiles, facebook logins, friends lists,# privacy, a search engine, blog, discussion forum, photo gallery, # interactive mapping, tagging of locations and routes, among many # other features. I've been working on for some time.  It consists # of 2958 PHP files including a number of third party projects # including htmlpurifier, markdownify, ImageManager, and Xinha to name # a few.## The number of PHP extensions used has been kept to an absolute minimum # making it easier to install this codebase on client servers and shared # hosting environments:## mysql, gd, session, pcre, posix, xml, hash, imap, openssl, exif## It's divided into a frontend where all content is served dynamically # through rewriting rules and a backend admin section. Cachebusting of # static files is supported.## To date it's been running under Apache and Zend PHP and makes heavy # use of mod_rewrite. ## This config represents my efforts to get this legacy codebase working # under HHVM. There is very little documentation so much has been # determined through trial and error. There are many config options I # have not experimented with.## HHVM does support VirtualHosts and rewrite rules but it's not well # documented and there was at least one bug preventing it from working, # which has been fixed:## Yermo Lamers## ---------------------------------------------------------------------Eval {   # set to true to enable JIT compiler   # If hhvm crashes you can turn this off to see if the problem    # is in the JIT.   Jit = true}# --------------------------------------------------------------------# access and error loggingLog {#   Level = Error#   NoSilencer = false   AlwaysLogUnhandledExceptions = true   RuntimeErrorReportingLevel = 8191#   Header = false   InjectedStackTrace = true   NativeStackTrace = true #   MaxMessagesPerRequest = -1   # error log settings   UseLogFile = true   File = /var/log/hhvm/error.log   # access log settings   AccessLogDefaultFormat = %h %l %u %t "%r" %>s %b   Access {      * {         File = /var/log/hhvm/access.log         Format = %h %l %u %t \"%r\" %>s %b      }   }   # admin server logging   AdminLog {      File = /var/log/hhvm/admin_access.log      Format = %h %t %s %U   }   # enable or disable hphp_log() that can be called from PHP code   ApplicationLog = true} # end of Log# ===================================PidFile = /var/log/hhvm/ ---------------------------------------------------------------------# Server wide settings.Server {   Host =   # IP =   Port = 80   # ThreadCount = 50   SourceRoot = /var/www/   # If ServerName is not specified for a virtual host, use prefix + this   # suffix to compose one   # 2013-11-18: NOTE this seems to get appended to $_SERVER["SERVER_NAME"]   # DefaultServerNameSuffix =   # Forcing $_SERVER['SERVER_NAME'] to come from request header   ForceServerNameToHeader = false   # startup options   DefaultDocument = index.php   # make sure your RewriteRules in the VirtualHost section take 404's    # into account. The same goes for favicon.ico.   ErrorDocument404 = error404.html   FatalErrorMessage = "Fatal Error"   # shutdown options   GracefulShutdownWait = 0   # in seconds   HarshShutdown = true   EvilShutdown = true   DanglingWait = 0   # HTTP settings   GzipCompressionLevel = 3   EnableMagicQuotesGpc = false   EnableKeepAlive = true   EnableEarlyFlush = true   ForceChunkedEncoding = false   MaxPostSize = 24  # in MB   LibEventSyncSend = true   ResponseQueueCount = 0   # static contents   # Setting this explicitly seems to break the cache.   #   # FileCache = /usr/local/WWW/   # EnableStaticContentCache worked for me in a previous version   # of hhvm, but recent builds haven't worked. I don't know if   # there is a way to control what gets cached and what doesn't.   EnableStaticContentCache = false   EnableStaticContentFromDisk = true   ExpiresActive = true   ExpiresDefault = 2592000   DefaultCharsetName = UTF-8   # file access control   SafeFileAccess = false}  # end of server# ---------------------------------------------------------------------AdminServer {   Port = 8088   ThreadCount = 1   Password = set_password_here}# end of admin server# ---------------------------------------------------------------------# Virtual Host DefinitionsVirtualHost {   * {      # strangely by default, hhvm will bypass rewrite rules       # if the file exists. (So you can't rewrite image1.gif       # to image2.gif if image1.gif exists.)      # This turns off that behavior.      #      # See      CheckExistenceBeforeRewrite = false      # which requests should this virtual host definition       # apply to? In my case, I have one site so everything       # goes through this virtual host.      Pattern = .*      # URL rewriting rules are applied in the order listed.       # The first rule that matches is applied.      RewriteRules {         # cachebust rewriting rules example         #         # In my app I send out css, js and ico files          # with a cachebust timestamp.          #         # For example, favicon.ico gets served as          # favicon.cb1234567.ico. So when the request          # comes back in to the server I need to map          # the cachebusted request to the original file          # name.          * {            pattern = ^(.*).cb([0-9]+).(css|js|ico)$            to = $1.$3            # do not append any query strings.                 qsa = false          }         # In my app I have a public side and and admin          # side. All requests to the public side should          # be rerouted through a script. All requests to         # the backend .php and static asset files should         # be allowed.         * {            # rewrite every request onto             # /myapp/page.php/<original request>            pattern = ^(.*)$            to = /myapp/page.php/$1            # append any query strings.            qsa = true            # we don't want this rewrite rule to be fired for static             # content such as images. Anything that matches the            # section below will NOT be rewritten.            #            # Note that if we fall through these rules and the file was            # not found, hhvm will attempt to serve the error404.html             # page, per config above. It will fall back through to the            # rewrite rule above dynamically serve the 404 page from my             # code.            conditions {                   * {                     # allow php and static asset files to be linked to                     # directly, otherwise any other requests get run                      # through the rewrite rule above and will generate                     # file not found errors.                     pattern = ^(/myapp/.*php|.*\.(css|js|jpg|gif|ico|png|jpeg|json))$                     # when set to true causes the wrapping rewrite                      # rule to be ignored when the pattern is matched.                     negate = true                  }               }            # end of conditions         }      }      # end of RewriteRules   }}# end of VirtualHost # ---------------------------------------------------------------------# PHP Debugging/Logging#Debug {   # when errors are logged include a full PHP backtrace (useful for    # debugging)   FullBacktrace = true   ServerStackTrace = true   ServerErrorMessage = true   TranslateSource = false    RecordInput = false   ClearInputOnSuccess = true   ProfilerOutputDir = /tmp   # CoreDumpEmail = email address   CoreDumpReport = true}# ---------------------------------------------------------------------# Static File Mime Types## from: {   Extensions {      123 = application/vnd.lotus-1-2-3      3dml = text/vnd.in3d.3dml      3ds = image/x-3ds      3g2 = video/3gpp2      3gp = video/3gpp      7z = application/x-7z-compressed      aab = application/x-authorware-bin      aac = audio/x-aac      aam = application/x-authorware-map      aas = application/x-authorware-seg      abw = application/x-abiword      ac = application/pkix-attr-cert      acc = application/vnd.americandynamics.acc      ace = application/x-ace-compressed      acu = application/vnd.acucobol      acutc = application/vnd.acucorp      adp = audio/adpcm      aep = application/vnd.audiograph      afm = application/x-font-type1      afp = application/      ahead = application/      ai = application/postscript      aif = audio/x-aiff      aifc = audio/x-aiff      aiff = audio/x-aiff      air = application/vnd.adobe.air-application-installer-package+zip      ait = application/vnd.dvb.ait      ami = application/vnd.amiga.ami      apk = application/      appcache = text/cache-manifest      application = application/x-ms-application      apr = application/vnd.lotus-approach      arc = application/x-freearc      asc = application/pgp-signature      asf = video/x-ms-asf      asm = text/x-asm      aso = application/vnd.accpac.simply.aso      asx = video/x-ms-asf      atc = application/vnd.acucorp      atom = application/atom+xml      atomcat = application/atomcat+xml      atomsvc = application/atomsvc+xml      atx = application/      au = audio/basic      avi = video/x-msvideo      aw = application/applixware      azf = application/vnd.airzip.filesecure.azf      azs = application/vnd.airzip.filesecure.azs      azw = application/      bat = application/x-msdownload      bcpio = application/x-bcpio      bdf = application/x-font-bdf      bdm = application/      bed = application/vnd.realvnc.bed      bh2 = application/      bin = application/octet-stream      blb = application/x-blorb      blorb = application/x-blorb      bmi = application/vnd.bmi      bmp = image/bmp      book = application/vnd.framemaker      box = application/      boz = application/x-bzip2      bpk = application/octet-stream      btif = image/prs.btif      bz = application/x-bzip      bz2 = application/x-bzip2      c = text/x-c      c11amc = application/vnd.cluetrust.cartomobile-config      c11amz = application/vnd.cluetrust.cartomobile-config-pkg      c4d = application/vnd.clonk.c4group      c4f = application/vnd.clonk.c4group      c4g = application/vnd.clonk.c4group      c4p = application/vnd.clonk.c4group      c4u = application/vnd.clonk.c4group      cab = application/      caf = audio/x-caf      cap = application/vnd.tcpdump.pcap      car = application/      cat = application/      cb7 = application/x-cbr      cba = application/x-cbr      cbr = application/x-cbr      cbt = application/x-cbr      cbz = application/x-cbr      cc = text/x-c      cct = application/x-director      ccxml = application/ccxml+xml      cdbcmsg = application/      cdf = application/x-netcdf      cdkey = application/vnd.mediastation.cdkey      cdmia = application/cdmi-capability      cdmic = application/cdmi-container      cdmid = application/cdmi-domain      cdmio = application/cdmi-object      cdmiq = application/cdmi-queue      cdx = chemical/x-cdx      cdxml = application/vnd.chemdraw+xml      cdy = application/vnd.cinderella      cer = application/pkix-cert      cfs = application/x-cfs-compressed      cgm = image/cgm      chat = application/x-chat      chm = application/      chrt = application/vnd.kde.kchart      cif = chemical/x-cif      cii = application/vnd.anser-web-certificate-issue-initiation      cil = application/      cla = application/vnd.claymore      class = application/java-vm      clkk = application/vnd.crick.clicker.keyboard      clkp = application/vnd.crick.clicker.palette      clkt = application/vnd.crick.clicker.template      clkw = application/vnd.crick.clicker.wordbank      clkx = application/vnd.crick.clicker      clp = application/x-msclip      cmc = application/vnd.cosmocaller      cmdf = chemical/x-cmdf      cml = chemical/x-cml      cmp = application/vnd.yellowriver-custom-menu      cmx = image/x-cmx      cod = application/vnd.rim.cod      com = application/x-msdownload      conf = text/plain      cpio = application/x-cpio      cpp = text/x-c      cpt = application/mac-compactpro      crd = application/x-mscardfile      crl = application/pkix-crl      crt = application/x-x509-ca-cert      cryptonote = application/vnd.rig.cryptonote      csh = application/x-csh      csml = chemical/x-csml      csp = application/vnd.commonspace      css = text/css      cst = application/x-director      csv = text/csv      cu = application/cu-seeme      curl = text/vnd.curl      cww = application/prs.cww      cxt = application/x-director      cxx = text/x-c      dae = model/vnd.collada+xml      daf = application/vnd.mobius.daf      dart = application/vnd.dart      dataless = application/vnd.fdsn.seed      davmount = application/davmount+xml      dbk = application/docbook+xml      dcr = application/x-director      dcurl = text/vnd.curl.dcurl      dd2 = application/vnd.oma.dd2+xml      ddd = application/      deb = application/x-debian-package      def = text/plain      deploy = application/octet-stream      der = application/x-x509-ca-cert      dfac = application/vnd.dreamfactory      dgc = application/x-dgc-compressed      dic = text/x-c      dif = video/x-dv      dir = application/x-director      dis = application/vnd.mobius.dis      dist = application/octet-stream      distz = application/octet-stream      djv = image/vnd.djvu      djvu = image/vnd.djvu      dll = application/x-msdownload      dmg = application/x-apple-diskimage      dmp = application/vnd.tcpdump.pcap      dms = application/octet-stream      dna = application/vnd.dna      doc = application/msword      docm = application/      docx = application/vnd.openxmlformats-officedocument.wordprocessingml.document      dot = application/msword      dotm = application/      dotx = application/vnd.openxmlformats-officedocument.wordprocessingml.template      dp = application/vnd.osgi.dp      dpg = application/vnd.dpgraph      dra = audio/vnd.dra      dsc = text/prs.lines.tag      dssc = application/dssc+der      dtb = application/x-dtbook+xml      dtd = application/xml-dtd      dts = audio/vnd.dts      dtshd = audio/vnd.dts.hd      dump = application/octet-stream      dv = video/x-dv      dvb = video/vnd.dvb.file      dvi = application/x-dvi      dwf = model/vnd.dwf      dwg = image/vnd.dwg      dxf = image/vnd.dxf      dxp = application/vnd.spotfire.dxp      dxr = application/x-director      ecelp4800 = audio/vnd.nuera.ecelp4800      ecelp7470 = audio/vnd.nuera.ecelp7470      ecelp9600 = audio/vnd.nuera.ecelp9600      ecma = application/ecmascript      edm = application/vnd.novadigm.edm      edx = application/vnd.novadigm.edx      efif = application/vnd.picsel      ei6 = application/      elc = application/octet-stream      emf = application/x-msmetafile      eml = message/rfc822      emma = application/emma+xml      emz = application/x-msmetafile      eol = audio/      eot = application/      eps = application/postscript      epub = application/epub+zip      es3 = application/vnd.eszigno3+xml      esa = application/vnd.osgi.subsystem      esf = application/      et3 = application/vnd.eszigno3+xml      etx = text/x-setext      eva = application/x-eva      evy = application/x-envoy      exe = application/x-msdownload      exi = application/exi      ext = application/vnd.novadigm.ext      ez = application/andrew-inset      ez2 = application/vnd.ezpix-album      ez3 = application/vnd.ezpix-package      f = text/x-fortran      f4v = video/x-f4v      f77 = text/x-fortran      f90 = text/x-fortran      fbs = image/vnd.fastbidsheet      fcdt = application/vnd.adobe.formscentral.fcdt      fcs = application/vnd.isac.fcs      fdf = application/vnd.fdf      fe_launch = application/vnd.denovo.fcselayout-link      fg5 = application/      fgd = application/x-director      fh = image/x-freehand      fh4 = image/x-freehand      fh5 = image/x-freehand      fh7 = image/x-freehand      fhc = image/x-freehand      fig = application/x-xfig      flac = audio/x-flac      fli = video/x-fli      flo = application/vnd.micrografx.flo      flv = video/x-flv      flw = application/vnd.kde.kivio      flx = text/vnd.fmi.flexstor      fly = text/      fm = application/vnd.framemaker      fnc = application/      for = text/x-fortran      fpx = image/vnd.fpx      frame = application/vnd.framemaker      fsc = application/vnd.fsc.weblaunch      fst = image/vnd.fst      ftc = application/vnd.fluxtime.clip      fti = application/vnd.anser-web-funds-transfer-initiation      fvt = video/vnd.fvt      fxp = application/vnd.adobe.fxp      fxpl = application/vnd.adobe.fxp      fzs = application/vnd.fuzzysheet      g2w = application/vnd.geoplan      g3 = image/g3fax      g3w = application/vnd.geospace      gac = application/vnd.groove-account      gam = application/x-tads      gbr = application/rpki-ghostbusters      gca = application/x-gca-compressed      gdl = model/vnd.gdl      geo = application/vnd.dynageo      gex = application/vnd.geometry-explorer      ggb = application/vnd.geogebra.file      ggt = application/vnd.geogebra.tool      ghf = application/vnd.groove-help      gif = image/gif      gim = application/vnd.groove-identity-message      gml = application/gml+xml      gmx = application/      gnumeric = application/x-gnumeric      gph = application/vnd.flographit      gpx = application/gpx+xml      gqf = application/vnd.grafeq      gqs = application/vnd.grafeq      gram = application/srgs      gramps = application/x-gramps-xml      gre = application/vnd.geometry-explorer      grv = application/vnd.groove-injector      grxml = application/srgs+xml      gsf = application/x-font-ghostscript      gtar = application/x-gtar      gtm = application/vnd.groove-tool-message      gtw = model/vnd.gtw      gv = text/vnd.graphviz      gxf = application/gxf      gxt = application/vnd.geonext      h = text/x-c      h261 = video/h261      h263 = video/h263      h264 = video/h264      hal = application/vnd.hal+xml      hbci = application/vnd.hbci      hdf = application/x-hdf      hh = text/x-c      hlp = application/winhlp      hpgl = application/vnd.hp-hpgl      hpid = application/vnd.hp-hpid      hps = application/vnd.hp-hps      hqx = application/mac-binhex40      htke = application/vnd.kenameaapp      htm = text/html      html = text/html      hvd = application/vnd.yamaha.hv-dic      hvp = application/vnd.yamaha.hv-voice      hvs = application/vnd.yamaha.hv-script      i2g = application/vnd.intergeo      icc = application/vnd.iccprofile      ice = x-conference/x-cooltalk      icm = application/vnd.iccprofile      ico = image/x-icon      ics = text/calendar      ief = image/ief      ifb = text/calendar      ifm = application/vnd.shana.informed.formdata      iges = model/iges      igl = application/vnd.igloader      igm = application/vnd.insors.igm      igs = model/iges      igx = application/vnd.micrografx.igx      iif = application/vnd.shana.informed.interchange      imp = application/vnd.accpac.simply.imp      ims = application/      in = text/plain      ink = application/inkml+xml      inkml = application/inkml+xml      install = application/x-install-instructions      iota = application/vnd.astraea-software.iota      ipfix = application/ipfix      ipk = application/vnd.shana.informed.package      irm = application/      irp = application/vnd.irepository.package+xml      iso = application/x-iso9660-image      itp = application/vnd.shana.informed.formtemplate      ivp = application/vnd.immervision-ivp      ivu = application/vnd.immervision-ivu      jad = text/      jam = application/vnd.jam      jar = application/java-archive      java = text/x-java-source      jisp = application/vnd.jisp      jlt = application/vnd.hp-jlyt      jnlp = application/x-java-jnlp-file      joda = application/vnd.joost.joda-archive      jp2 = image/jp2      jpe = image/jpeg      jpeg = image/jpeg      jpg = image/jpeg      jpgm = video/jpm      jpgv = video/jpeg      jpm = video/jpm      js = application/javascript      json = application/json      jsonml = application/jsonml+json      kar = audio/midi      karbon = application/vnd.kde.karbon      kfo = application/vnd.kde.kformula      kia = application/vnd.kidspiration      kml = application/      kmz = application/      kne = application/vnd.kinar      knp = application/vnd.kinar      kon = application/vnd.kde.kontour      kpr = application/vnd.kde.kpresenter      kpt = application/vnd.kde.kpresenter      kpxx = application/vnd.ds-keypoint      ksp = application/vnd.kde.kspread      ktr = application/vnd.kahootz      ktx = image/ktx      ktz = application/vnd.kahootz      kwd = application/vnd.kde.kword      kwt = application/vnd.kde.kword      lasxml = application/vnd.las.las+xml      latex = application/x-latex      lbd = application/      lbe = application/      les = application/vnd.hhe.lesson-player      lha = application/x-lzh-compressed      link66 = application/vnd.route66.link66+xml      list = text/plain      list3820 = application/      listafp = application/      lnk = application/x-ms-shortcut      log = text/plain      lostxml = application/lost+xml      lrf = application/octet-stream      lrm = application/      ltf = application/      lvp = audio/vnd.lucent.voice      lwp = application/vnd.lotus-wordpro      lzh = application/x-lzh-compressed      m13 = application/x-msmediaview      m14 = application/x-msmediaview      m1v = video/mpeg      m21 = application/mp21      m2a = audio/mpeg      m2v = video/mpeg      m3a = audio/mpeg      m3u = audio/x-mpegurl      m3u8 = application/      m3u8 = application/x-mpegurl      m4a = audio/mp4a-latm      m4p = audio/mp4a-latm      m4u = video/vnd.mpegurl      m4v = video/mp4      m4v = video/x-m4v      ma = application/mathematica      mac = image/x-macpaint      mads = application/mads+xml      mag = application/vnd.ecowin.chart      maker = application/vnd.framemaker      man = text/troff      manifest = text/cache-manifest      mar = application/octet-stream      mathml = application/mathml+xml      mb = application/mathematica      mbk = application/vnd.mobius.mbk      mbox = application/mbox      mc1 = application/vnd.medcalcdata      mcd = application/      mcurl = text/vnd.curl.mcurl      mdb = application/x-msaccess      mdi = image/      me = text/troff      mesh = model/mesh      meta4 = application/metalink4+xml      metalink = application/metalink+xml      mets = application/mets+xml      mfm = application/vnd.mfmp      mft = application/rpki-manifest      mgp = application/vnd.osgeo.mapguide.package      mgz = application/vnd.proteus.magazine      mid = audio/midi      midi = audio/midi      mie = application/x-mie      mif = application/vnd.mif      mime = message/rfc822      mj2 = video/mj2      mjp2 = video/mj2      mk3d = video/x-matroska      mka = audio/x-matroska      mks = video/x-matroska      mkv = video/x-matroska      mlp = application/vnd.dolby.mlp      mmd = application/vnd.chipnuts.karaoke-mmd      mmf = application/vnd.smaf      mmr = image/      mng = video/x-mng      mny = application/x-msmoney      mobi = application/x-mobipocket-ebook      mods = application/mods+xml      mov = video/quicktime      movie = video/x-sgi-movie      mp2 = audio/mpeg      mp21 = application/mp21      mp2a = audio/mpeg      mp3 = audio/mpeg      mp4 = video/mp4      mp4a = audio/mp4      mp4s = application/mp4      mp4v = video/mp4      mpc = application/vnd.mophun.certificate      mpe = video/mpeg      mpeg = video/mpeg      mpg = video/mpeg      mpg4 = video/mp4      mpga = audio/mpeg      mpkg = application/      mpm = application/vnd.blueice.multipass      mpn = application/vnd.mophun.application      mpp = application/      mpt = application/      mpy = application/      mqy = application/vnd.mobius.mqy      mrc = application/marc      mrcx = application/marcxml+xml      ms = text/troff      mscml = application/mediaservercontrol+xml      mseed = application/vnd.fdsn.mseed      mseq = application/vnd.mseq      msf = application/      msh = model/mesh      msi = application/x-msdownload      msl = application/vnd.mobius.msl      msty = application/      mts = model/vnd.mts      mus = application/vnd.musician      musicxml = application/vnd.recordare.musicxml+xml      mvb = application/x-msmediaview      mwf = application/vnd.mfer      mxf = application/mxf      mxl = application/vnd.recordare.musicxml      mxml = application/xv+xml      mxs = application/vnd.triscape.mxs      mxu = video/vnd.mpegurl      n3 = text/n3      nb = application/mathematica      nbp = application/vnd.wolfram.player      nc = application/x-netcdf      ncx = application/x-dtbncx+xml      nfo = text/x-nfo      ngdat = application/      nitf = application/vnd.nitf      nlu = application/vnd.neurolanguage.nlu      nml = application/vnd.enliven      nnd = application/vnd.noblenet-directory      nns = application/vnd.noblenet-sealer      nnw = application/vnd.noblenet-web      npx = image/      nsc = application/x-conference      nsf = application/vnd.lotus-notes      ntf = application/vnd.nitf      nzb = application/x-nzb      oa2 = application/      oa3 = application/      oas = application/      obd = application/x-msbinder      obj = application/x-tgif      oda = application/oda      odb = application/vnd.oasis.opendocument.database      odc = application/vnd.oasis.opendocument.chart      odf = application/vnd.oasis.opendocument.formula      odft = application/vnd.oasis.opendocument.formula-template      odg = application/      odi = application/vnd.oasis.opendocument.image      odm = application/vnd.oasis.opendocument.text-master      odp = application/vnd.oasis.opendocument.presentation      ods = application/vnd.oasis.opendocument.spreadsheet      odt = application/vnd.oasis.opendocument.text      oga = audio/ogg      ogg = audio/ogg      ogv = video/ogg      ogx = application/ogg      omdoc = application/omdoc+xml      onepkg = application/onenote      onetmp = application/onenote      onetoc = application/onenote      onetoc2 = application/onenote      opf = application/oebps-package+xml      opml = text/x-opml      oprc = application/vnd.palm      org = application/vnd.lotus-organizer      osf = application/vnd.yamaha.openscoreformat      osfpvg = application/vnd.yamaha.openscoreformat.osfpvg+xml      otc = application/vnd.oasis.opendocument.chart-template      otf = application/x-font-otf      otg = application/      oth = application/vnd.oasis.opendocument.text-web      oti = application/vnd.oasis.opendocument.image-template      otp = application/vnd.oasis.opendocument.presentation-template      ots = application/vnd.oasis.opendocument.spreadsheet-template      ott = application/vnd.oasis.opendocument.text-template      oxps = application/oxps      oxt = application/vnd.openofficeorg.extension      p = text/x-pascal      p10 = application/pkcs10      p12 = application/x-pkcs12      p7b = application/x-pkcs7-certificates      p7c = application/pkcs7-mime      p7m = application/pkcs7-mime      p7r = application/x-pkcs7-certreqresp      p7s = application/pkcs7-signature      p8 = application/pkcs8      pas = text/x-pascal      paw = application/vnd.pawaafile      pbd = application/vnd.powerbuilder6      pbm = image/x-portable-bitmap      pcap = application/vnd.tcpdump.pcap      pcf = application/x-font-pcf      pcl = application/vnd.hp-pcl      pclxl = application/vnd.hp-pclxl      pct = image/pict      pct = image/x-pict      pcurl = application/vnd.curl.pcurl      pcx = image/x-pcx      pdb = application/vnd.palm      pdf = application/pdf      pfa = application/x-font-type1      pfb = application/x-font-type1      pfm = application/x-font-type1      pfr = application/font-tdpfr      pfx = application/x-pkcs12      pgm = image/x-portable-graymap      pgn = application/x-chess-pgn      pgp = application/pgp-encrypted      pic = image/pict      pic = image/x-pict      pict = image/pict      pkg = application/octet-stream      pki = application/pkixcmp      pkipath = application/pkix-pkipath      plb = application/vnd.3gpp.pic-bw-large      plc = application/vnd.mobius.plc      plf = application/vnd.pocketlearn      pls = application/pls+xml      pml = application/vnd.ctc-posml      png = image/png      pnm = image/x-portable-anymap      pnt = image/x-macpaint      pntg = image/x-macpaint      portpkg = application/vnd.macports.portpkg      pot = application/      potm = application/      potx = application/vnd.openxmlformats-officedocument.presentationml.template      ppam = application/      ppd = application/vnd.cups-ppd      ppm = image/x-portable-pixmap      pps = application/      ppsm = application/      ppsx = application/vnd.openxmlformats-officedocument.presentationml.slideshow      ppt = application/      pptm = application/      pptx = application/vnd.openxmlformats-officedocument.presentationml.presentation      pqa = application/vnd.palm      prc = application/x-mobipocket-ebook      pre = application/vnd.lotus-freelance      prf = application/pics-rules      ps = application/postscript      psb = application/vnd.3gpp.pic-bw-small      psd = image/vnd.adobe.photoshop      psf = application/x-font-linux-psf      pskcxml = application/pskc+xml      ptid = application/vnd.pvi.ptid1      pub = application/x-mspublisher      pvb = application/vnd.3gpp.pic-bw-var      pwn = application/      pya = audio/      pyv = video/      qam = application/      qbo = application/vnd.intu.qbo      qfx = application/vnd.intu.qfx      qps = application/vnd.publishare-delta-tree      qt = video/quicktime      qti = image/x-quicktime      qtif = image/x-quicktime      qwd = application/vnd.quark.quarkxpress      qwt = application/vnd.quark.quarkxpress      qxb = application/vnd.quark.quarkxpress      qxd = application/vnd.quark.quarkxpress      qxl = application/vnd.quark.quarkxpress      qxt = application/vnd.quark.quarkxpress      ra = audio/x-pn-realaudio      ram = audio/x-pn-realaudio      rar = application/x-rar-compressed      ras = image/x-cmu-raster      rcprofile = application/vnd.ipunplugged.rcprofile      rdf = application/rdf+xml      rdz = application/      rep = application/vnd.businessobjects      res = application/x-dtbresource+xml      rgb = image/x-rgb      rif = application/reginfo+xml      rip = audio/      ris = application/x-research-info-systems      rl = application/resource-lists+xml      rlc = image/      rld = application/resource-lists-diff+xml      rm = application/vnd.rn-realmedia      rmi = audio/midi      rmp = audio/x-pn-realaudio-plugin      rms = application/      rmvb = application/vnd.rn-realmedia-vbr      rnc = application/relax-ng-compact-syntax      roa = application/rpki-roa      roff = text/troff      rp9 = application/vnd.cloanto.rp9      rpss = application/      rpst = application/      rq = application/sparql-query      rs = application/rls-services+xml      rsd = application/rsd+xml      rss = application/rss+xml      rtf = application/rtf      rtx = text/richtext      s = text/x-asm      s3m = audio/s3m      saf = application/vnd.yamaha.smaf-audio      sbml = application/sbml+xml      sc = application/      scd = application/x-msschedule      scm = application/vnd.lotus-screencam      scq = application/scvp-cv-request      scs = application/scvp-cv-response      scurl = text/vnd.curl.scurl      sda = application/vnd.stardivision.draw      sdc = application/vnd.stardivision.calc      sdd = application/vnd.stardivision.impress      sdkd = application/vnd.solent.sdkm+xml      sdkm = application/vnd.solent.sdkm+xml      sdp = application/sdp      sdw = application/vnd.stardivision.writer      see = application/vnd.seemail      seed = application/vnd.fdsn.seed      sema = application/vnd.sema      semd = application/vnd.semd      semf = application/vnd.semf      ser = application/java-serialized-object      setpay = application/set-payment-initiation      setreg = application/set-registration-initiation      sfs = application/vnd.spotfire.sfs      sfv = text/x-sfv      sgi = image/sgi      sgl = application/vnd.stardivision.writer-global      sgm = text/sgml      sgml = text/sgml      sh = application/x-sh      shar = application/x-shar      shf = application/shf+xml      sid = image/x-mrsid-image      sig = application/pgp-signature      sil = audio/silk      silo = model/mesh      sis = application/vnd.symbian.install      sisx = application/vnd.symbian.install      sit = application/x-stuffit      sitx = application/x-stuffitx      skd = application/vnd.koan      skm = application/vnd.koan      skp = application/vnd.koan      skt = application/vnd.koan      sldm = application/      sldx = application/vnd.openxmlformats-officedocument.presentationml.slide      slt = application/      sm = application/vnd.stepmania.stepchart      smf = application/vnd.stardivision.math      smi = application/smil+xml      smil = application/smil+xml      smv = video/x-smv      smzip = application/vnd.stepmania.package      snd = audio/basic      snf = application/x-font-snf      so = application/octet-stream      spc = application/x-pkcs7-certificates      spf = application/vnd.yamaha.smaf-phrase      spl = application/x-futuresplash      spot = text/      spp = application/scvp-vp-response      spq = application/scvp-vp-request      spx = audio/ogg      sql = application/x-sql      src = application/x-wais-source      srt = application/x-subrip      sru = application/sru+xml      srx = application/sparql-results+xml      ssdl = application/ssdl+xml      sse = application/vnd.kodak-descriptor      ssf = application/      ssml = application/ssml+xml      st = application/vnd.sailingtracker.track      stc = application/vnd.sun.xml.calc.template      std = application/vnd.sun.xml.draw.template      stf = application/vnd.wt.stf      sti = application/vnd.sun.xml.impress.template      stk = application/hyperstudio      stl = application/      str = application/      stw = application/vnd.sun.xml.writer.template      sub = image/vnd.dvb.subtitle      sub = text/vnd.dvb.subtitle      sus = application/vnd.sus-calendar      susp = application/vnd.sus-calendar      sv4cpio = application/x-sv4cpio      sv4crc = application/x-sv4crc      svc = application/vnd.dvb.service      svd = application/vnd.svd      svg = image/svg+xml      svgz = image/svg+xml      swa = application/x-director      swf = application/x-shockwave-flash      swi = application/vnd.aristanetworks.swi      sxc = application/vnd.sun.xml.calc      sxd = application/vnd.sun.xml.draw      sxg = application/      sxi = application/vnd.sun.xml.impress      sxm = application/vnd.sun.xml.math      sxw = application/vnd.sun.xml.writer      t = text/troff      t3 = application/x-t3vm-image      taglet = application/vnd.mynfc      tao = application/vnd.tao.intent-module-archive      tar = application/x-tar      tcap = application/vnd.3gpp2.tcap      tcl = application/x-tcl      teacher = application/      tei = application/tei+xml      teicorpus = application/tei+xml      tex = application/x-tex      texi = application/x-texinfo      texinfo = application/x-texinfo      text = text/plain      tfi = application/thraud+xml      tfm = application/x-tex-tfm      tga = image/x-tga      thmx = application/      tif = image/tiff      tiff = image/tiff      tmo = application/vnd.tmobile-livetv      torrent = application/x-bittorrent      tpl = application/vnd.groove-tool-template      tpt = application/vnd.trid.tpt      tr = text/troff      tra = application/vnd.trueapp      trm = application/x-msterminal      ts = video/mp2t      tsd = application/timestamped-data      tsv = text/tab-separated-values      ttc = application/x-font-ttf      ttf = application/x-font-ttf      ttl = text/turtle      twd = application/vnd.simtech-mindmapper      twds = application/vnd.simtech-mindmapper      txd = application/vnd.genomatix.tuxedo      txf = application/vnd.mobius.txf      txt = text/plain      u32 = application/x-authorware-bin      udeb = application/x-debian-package      ufd = application/vnd.ufdl      ufdl = application/vnd.ufdl      ulx = application/x-glulx      umj = application/vnd.umajin      unityweb = application/vnd.unity      uoml = application/vnd.uoml+xml      uri = text/uri-list      uris = text/uri-list      urls = text/uri-list      ustar = application/x-ustar      utz = application/vnd.uiq.theme      uu = text/x-uuencode      uva = audio/      uvd = application/      uvf = application/      uvg = image/vnd.dece.graphic      uvh = video/vnd.dece.hd      uvi = image/vnd.dece.graphic      uvm = video/      uvp = video/vnd.dece.pd      uvs = video/      uvt = application/vnd.dece.ttml+xml      uvu = video/vnd.uvvu.mp4      uvv = video/      uvva = audio/      uvvd = application/      uvvf = application/      uvvg = image/vnd.dece.graphic      uvvh = video/vnd.dece.hd      uvvi = image/vnd.dece.graphic      uvvm = video/      uvvp = video/vnd.dece.pd      uvvs = video/      uvvt = application/vnd.dece.ttml+xml      uvvu = video/vnd.uvvu.mp4      uvvv = video/      uvvx = application/vnd.dece.unspecified      uvvz = application/      uvx = application/vnd.dece.unspecified      uvz = application/      vcard = text/vcard      vcd = application/x-cdlink      vcf = text/x-vcard      vcg = application/vnd.groove-vcard      vcs = text/x-vcalendar      vcx = application/vnd.vcx      vis = application/vnd.visionary      viv = video/      vob = video/x-ms-vob      vor = application/vnd.stardivision.writer      vox = application/x-authorware-bin      vrml = model/vrml      vsd = application/vnd.visio      vsf = application/vnd.vsf      vss = application/vnd.visio      vst = application/vnd.visio      vsw = application/vnd.visio      vtu = model/vnd.vtu      vxml = application/voicexml+xml      w3d = application/x-director      wad = application/x-doom      wav = audio/x-wav      wax = audio/x-ms-wax      wbmp = image/vnd.wap.wbmp      wbs = application/vnd.criticaltools.wbs+xml      wbxml = application/vnd.wap.wbxml      wcm = application/      wdb = application/      wdp = image/      weba = audio/webm      webm = video/webm      webp = image/webp      wg = application/vnd.pmi.widget      wgt = application/widget      wks = application/      wm = video/x-ms-wm      wma = audio/x-ms-wma      wmd = application/x-ms-wmd      wmf = application/x-msmetafile      wml = text/vnd.wap.wml      wmlc = application/vnd.wap.wmlc      wmls = text/vnd.wap.wmlscript      wmlsc = application/vnd.wap.wmlscriptc      wmv = video/x-ms-wmv      wmx = video/x-ms-wmx      wmz = application/x-ms-wmz      wmz = application/x-msmetafile      woff = application/x-font-woff      wpd = application/vnd.wordperfect      wpl = application/      wps = application/      wqd = application/vnd.wqd      wri = application/x-mswrite      wrl = model/vrml      wsdl = application/wsdl+xml      wspolicy = application/wspolicy+xml      wtb = application/vnd.webturbo      wvx = video/x-ms-wvx      x32 = application/x-authorware-bin      x3d = model/x3d+xml      x3db = model/x3d+binary      x3dbz = model/x3d+binary      x3dv = model/x3d+vrml      x3dvz = model/x3d+vrml      x3dz = model/x3d+xml      xaml = application/xaml+xml      xap = application/x-silverlight-app      xar = application/vnd.xara      xbap = application/x-ms-xbap      xbd = application/      xbm = image/x-xbitmap      xdf = application/xcap-diff+xml      xdm = application/      xdp = application/vnd.adobe.xdp+xml      xdssc = application/dssc+xml      xdw = application/      xenc = application/xenc+xml      xer = application/patch-ops-error+xml      xfdf = application/vnd.adobe.xfdf      xfdl = application/vnd.xfdl      xht = application/xhtml+xml      xhtml = application/xhtml+xml      xhvml = application/xv+xml      xif = image/vnd.xiff      xla = application/      xlam = application/      xlc = application/      xlf = application/x-xliff+xml      xlm = application/      xls = application/      xlsb = application/      xlsm = application/      xlsx = application/vnd.openxmlformats-officedocument.spreadsheetml.sheet      xlt = application/      xltm = application/      xltx = application/vnd.openxmlformats-officedocument.spreadsheetml.template      xlw = application/      xm = audio/xm      xml = application/xml      xo = application/vnd.olpc-sugar      xop = application/xop+xml      xpi = application/x-xpinstall      xpl = application/xproc+xml      xpm = image/x-xpixmap      xpr = application/      xps = application/      xpw = application/vnd.intercon.formnet      xpx = application/vnd.intercon.formnet      xsl = application/xml      xslt = application/xslt+xml      xsm = application/vnd.syncml+xml      xspf = application/xspf+xml      xul = application/vnd.mozilla.xul+xml      xvm = application/xv+xml      xvml = application/xv+xml      xwd = image/x-xwindowdump      xyz = chemical/x-xyz      xz = application/x-xz      yang = application/yang      yin = application/yin+xml      z1 = application/x-zmachine      z2 = application/x-zmachine      z3 = application/x-zmachine      z4 = application/x-zmachine      z5 = application/x-zmachine      z6 = application/x-zmachine      z7 = application/x-zmachine      z8 = application/x-zmachine      zaz = application/vnd.zzazz.deck+xml      zip = application/zip      zir = application/vnd.zul      zirz = application/vnd.zul      zmm = application/vnd.handheld-entertainment+xml   }}

Current Status

It is in fact as fast as they say it is. In my testing, pages which load in 5 seconds (Yea, I know, I said it was slow), now load in 0.6 seconds without any modifications to my codebase except for the couple where I had to work around issues that I've listed above. All told I only modified two functions in my entire codebase. Out of over 500 files filled with classes processing 1200 FVML files, I'd say that's not bad at all.

hhvm also uses significantly less memory than php. Based on what memory_get_usage() reports I'd say it's about half as much, but under hhvm memory_get_usage() seems a bit unreliable.

I am not yet running it on this site, so my users will suffer with this slow performance for a bit longer. I'm putting together a new dedicated server to transition the site to. Once I take it live I'll report back but so far absolutely everything on the site works perfectly under hhvm on my development box and it's so much faster.


For more information on HipHopVM check the following links:

If you have any questions about what I've done, would like to point out mistakes or inaccuracies or other issues I ran into, you can use the Contact link above to get in touch with me or follow me on twitter at: