Month: January 2009

  • How to setup and use the Xdebug Extension for PHP Profiling

    A profiling tool can provide valuable information about bottlenecks in your code. I believe profiling is a critical aspect of optimizing because it will tell you about your real code bottlenecks as opposed to your perceived bottlenecks. This enables you to focus your resources on areas that will provide the most performance benefit for your effort. Most programming languages and environments have one or more profiling tools available and PHP is no exception.

    Xdebug is a PHP extension that provides valuable debugging information such as stack traces, functions traces, profiling, code coverage analysis, etc. There is another PHP tool called DBG that has similar functionality but this post will focus on using Xdebug.

    Setup Xdebug

    Xdebug is a PECL module and can be installed using the PECL installation instructions in one of my previous posts.

    • If you have already setup PEAR you just need to run the following from a shell:
      sudo pecl install xdebug
      

      If everything goes well Xdebug should download, build, and install. You may get a message telling you:

      You should add "extension=xdebug.so" to php.ini

      Go ahead and add the line. On an Ubuntu server you will probably find the php.ini file here: /etc/php5/apache2/php.ini

    • Restart Apache, or whatever web server you are using, so the change will take effect.
      If you are running Apache on Ubuntu it would be:

      sudo /etc/init.d/apache2 restart
      
    • Write a phpinfo.php page with the following code and then point a browser at it. It should show the Xdebug module there in addition to many other things:
      
      

    At this point the Xdebug extension should be installed. For more detailed instructions on a PECL extension install see my post: How to install a PHP PECL extension/module on Ubuntu. Note that there is a problem running the Xdebug extension with Zend Studio since it has it’s own debugger.

    Enable Xdebug profiling

    • By default, profiling is disable in Xdebug. Enable it by adding the following entry to the php.ini file:
      xdebug.profiler_enable=On
      

      On on a linux box there is often a php.d or conf.d folder that holds additional .ini file settings PHP will use. On Ubuntu the path for this folder is “/etc/php5/apache2/conf.d”. To prevent further cluttering my php.ini file with Xdebug settings, I created a xdebug.ini file to store all my Xdebug .ini file settings. This file is located in the “/etc/php5/apache2/conf.d” so it is automatically scanned when Apache is restarted.

      Now you might be tempted to enable the profiler in your script using the ini_set() function which, normally allows you to temporarily set a .ini setting for only the current script execution. Unfortunately this does not work. You must set it in the php.ini or a sub .ini file and restart the web server.

    • Restart your web server (I.e. Apache) once you have “xdebug.profiler_enable” set to “On”.

    By default, Xdebug will write a cachegrind.out file to the /tmp folder. It will be named something like cachegrind.out.22373 where the number at the end is the ID of the process that was profiled. If you are using Windows you will probably need to change the default folder. Also by default, this file will be overwritten by each script execution so you don’t have to worry about it getting too big. The output file behavior is highly customizable and a complete list of Xdebug settings can be found here.

    Call your script and display the analysis

    With Xdebug enabled, pull up the page in your browser that you want to profile. If everything is working OK a cachegrind.out file should show up in the /tmp folder.

    There are a couple programs you can use to open and analyze the cachegrind file:

    WinCacheGrind

    WinCacheGrind is not very featured but it will tell you the main thing you need to know, which is where your PHP application is spending its time. Click on the screen shot below to see the full output of my test script:

    wincachegrind screen shot

    The script makes an external call to example.com using a file_get_contents() function. Based on this analysis I might try caching the call results and only make the call at some interval to keep the cache updated. This would eliminate almost 75% of the application’s overhead and is just one example of an easy-to-fix bottleneck that profiling will help identify.

    KCacheGrind

    KCacheGrind does essentially the same thing as WinCacheGrind but it is geared for the Linux desktop and has quite a few more bells and whistles:

    kcachegrind screen shot

    KCacheGrind includes a map feature that graphically represents the percentages of where the test application spent the time:

    kcachegrind screen shot

    KCacheGrind also includes a graph feature with an export option that displays a tree diagram of the linkage between all the includes and functions:

    kcachegrindexport1.jpg

    That’s it for this post. Have fun profiling!

  • Review: RC Wall Climber/Clamber Remote Control Mini Car (Updated)

    2 out of 5 stars

    RC Wall Climber/Clamber Remote Control Mini Car

    Update: Warning

    I have received at least one report of a non-working car and the manufacturer has does not seem to have a web site that I can find to get a replacement. I have downgraded my rating to 2 stars accordingly. If you buy one of these make sure you get it from some place you can return it if it doesn’t work.

    NeweggMall.com recently sent me an e-mail pushing a wall climbing RC car called the Clamber!!! Master-Hand. It is actually listed under RC Wall Climber Remote Control Mini Car but the name on the box is “Clamber!!! Master-Hand” by Top Race R/C Series. Although similar, this is not the same as the Spinmaster Air Hogs Zero Gravity Micro Cars, which are a bit more expensive. It was cheap and cool enough looking that I naturally felt compelled to give it a try.

    How it works

    If you are not familiar with these, they have a vacuum inside that holds them to the wall. The four outer visible wheels are actually fake and just look nice. There are two inner wheels that are not visible (unless you flip it over) that sit against the wall and propel the car.

    The switch on the back has three different modes: off, on without vacuum, and on with the vacuum. This way if you just want to run it on the floor you don’t have to turn on the vacuum and waste your charge.

    The underside has two strips of fabric that sit against the wall to help maintain the vacuum. There are two intake holes on the bottom and 4 slits in the windows on top for the air output.

    The car itself looks pretty cool although the fake tires are a little less than authentic. It comes in three colors: Red, Black, and Blue.

    Performance

    The car does not go too fast but fast enough. It drives similar to a tank because it is actually only using two wheels. To steer, it changes the speed of the wheel on the appropriate side. While you are driving the turn radius is not precise and tends to be a bit large. When you are stopped it will turn on a dime.

    As power starts to run down, the vacuum does not hold the car as tightly to the wall as a full charge so sometimes the drives wheels will start to slip and you have to turn around and go in a different direction to get moving again.

    Run time on the wall is about 7 minutes although performance slopes off and the car will start loosing its traction around 4 minutes. Even after 7 minutes the vacuum was still strong enough to keep the car on the wall. I didn’t time it but I am guessing run time on the floor without the vacuum on would be quite a bit longer. When you get close to 8 minutes the power will cut off before the battery is drained too far. It uses a built in Lithium-Polymer battery which is probably why a charge last as long as it does for something so light. Charge time is about 10 minutes.

    Here are some pros and cons:

    Pros

    • Pretty good amount of drive time per charge (about 7 minutes)
    • Only a 10 minute charge
    • Can rotate on a dime while stopped
    • Fun!

    Cons

    • It will get stuck on even flat, clean surfaces occasionally after the battery has run down a bit.
    • The turn radius between running and when it is stopped is quite different. When it is stop it turns on a dime. When it is running it has a very wide turn radius in some cases.
    • IR controller does not perform well under strong light.

    Conclusion

    Overall I rate the wall climber 3 out of 5 stars. I would give it more stars if the steering were a bit more consistent and it didn’t get “stuck” as often. Overall it was pretty fun but I would say the Microfly is a bit more entertaining just because for about the same price or less, it flies around and that is hard to beat in my opinion.

    Images

    RC Wall Climber Clamber Remote Control Mini Car

    RC Wall Climber/Clamber Remote Control Mini Car

    RC Wall Climber/Clamber Remote Control Mini Car

    RC Wall Climber/Clamber Remote Control Mini Car

    RC Wall Climber/Clamber Remote Control Mini Car

    RC Wall Climber/Clamber Remote Control Mini Car

    RC Wall Climber/Clamber Remote Control Mini Car Charging

    Video

  • Review: Senario NRG MicroFly RC Hovering UFO

     

    Senario NRG MicroFly RC Hovering UFO

    In a previous post I talked about the Senario Alien Microfly a bit and in this post I will provide a full review. I gave a few units to some of my family for Christmas so I have flight reports from them as well.

    The Senario Alien Microfly kit comes with a transmitter and the Microfly itself. The transmitter takes 6 “AA” batteries and also serves as the charger for the Microfly. It is pretty small (see the pictures below) and a lot of fun to fly around the house or office.

    I put in many, many flights. Each flight is about 5 minutes with a 15-20 charge time. The cats gave it a few taste tests but mostly they like to just stalk it as it flies around the living room. 😉 I bought 5 of these for myself and my family for Christmas and all of them worked out of the box. Here is a list of pros/cons:

    Pros

    • It is simple to fly. There is only one control to make it go up or down so you don’t need a lot of experience.
    • Cheap. You will probably find it for $25 or less.
    • Durable. You can’t sit or step on it (it is mostly just foam board) but mine has been through many crashes and even survived a few taste tests by the cats.
    • The flight time is about 5 minutes which I think is pretty good for something so small.

    Cons

    • In very large rooms (gym/church/wharehouse) it can quickly get out of range if it doesn’t have walls for the IR signal to bounce off of.
    • After running through three or four sets of “AA” batteries (rechargable) flight times have fallen off quite a bit although I did get many flights on each set of batteries
    • Fragile. Although it can withstand being bounced off a few walls it is very small and made of foam so you don’t want to leave it someplace where it will be sat/stepped on.
    • No directional flight. It only goes up and down.
    • Charge time is kind of high… about 15-20 minutes per flight

    Conclusion

    Overall I give the Microfly 3 out of 5 stars. I would easily rate it higher if it maintained its power after extended use. I don’t know if the built in battery has just been recharged too many times or if the motor is reaching the end of it’s life since it is so tiny and spins at such high RPMs. Despite this, I would say it is easily worth the price and would recommend it to anyone that enjoys RC toys.

    Images

    Senario NRG MicroFly RC Hovering UFO

    Senario NRG MicroFly RC Hovering UFO

    Video

     

  • How to use the file_get_contents() function to make an HTTP request from PHP

    In a previous post I talked about using the HttpRequest object and functions in the PECL_HTTP extension to make HTTP requests from PHP. In some cases you may be limited to using functionality built into the PHP core. The file_get_contents() function has less features than the PECL_HTTP extension but it is built into PHP 4.3 and up. Here is an example of using it to retrieve the landing page at www.example.com:

    
    

    Someone hit that easy button.

    The file_get_contents() functions as well as many other PHP file functions implement a streams abstraction layer largely conceived by Mr. Wez Furlong. This abstraction layer is what enables many of the PHP file functions to access network resources. Given this functionality “file” seems a misnomer.

    The file_get_contents() function uses an HTTP GET request but what if you want to do a POST without using cURL or the PECL_HTTP extension? Furlong posted an article here on how to do just that.

    This next code example uses the file_get_contents() function again but this time a few options are set first using the stream_context_create() function:

     array(
            'user_agent' => "Mark's Browser",
            'max_redirects' => 3)));
    echo file_get_contents("http://www.example.com", false, $http_options);
    
    ?>
    

    Note that the array passed to the stream_context_create() function can also be used to specify a POST method, which is how Furlong does so in his blog post.

    There is still yet another way to make an HTTP request from PHP that I haven’t covered yet using the PHP built-in cURL functions. I will cover these in a separate blog post.

  • How to make your PHP application check for its dependencies

    The very informative phpinfo() function

    The phpinfo() function displays just about everything you want to know about your PHP installation. It includes info on all your PECL and PEAR modules so it is a quick way to check what’s installed. It will also tell you useful web server information including any query strings you pass. To display all this good info just point your browser at a page on your server that contains the following code:

    
    

    That’s it!

    Automatic dependency checking

    The phpinfo() function will give us a page that displays a lot of info. You can pass it bitwise constants to narrow down the information displayed but what if we want to check for specific items?

    In my humble opinion, when developing software or anything in general, it is a good idea to design things so that the end user will not even need a manual because the user interface is obvious. When something doesn’t work, it should be equally obvious how to fix it.

    If you write a PHP application that others will install and use, it is a good idea to check for dependencies when they try to use the application. This way even if they don’t read your documentation they will quickly know why the software is not working.

    Using phpversion(), PHP_VERSION, and version_compare() to check the PHP verson

    To get the core PHP version you can use either of the following methods:

    or
    "; echo PHP_VERSION; ?>

    The above code should output something like this:

    5.2.6-2ubuntu4
    or
    5.2.6-2ubuntu4

    If you are using Ubunto or some other distribution, you will note that some additional stuff is tack on to the version number (I.e. “-2ubuntu4”). This makes a comparison to your expected version a little tricky but you can use a substr()/strpos() combo to get what you need. There is an easier way to do the comparison though. The version_compare() function is “PHP-standardized” version aware. So we can do something like this:

    
    

    Now you can check the PHP version and notify the user if it is not the minimum required version.

    The PHP function documentation for each function at www.php.net include the PHP versions that contain the function in the upper left hand corner:

    substr function version on php.net

    You can use this to learn what versions of PHP include the functions you are using in your code to help identify your minimum PHP version requirement.

    Using get_loaded_extensions() to check for extensions

    The get_loaded_extensions() function will return an array of PHP extensions that you can use to check if a specific extension is installed. Use it in combination with with the in_array() function to check if the extension you require is loaded. In this example I check if the PECL_HTTP module is installed:

    
    

    You can use the phpversion() function to check if extension is listed and if so, its version. This code example not only checks if the PECL_HTTP module is installed, but also checks it’s version:

    here '.
          ' and install it.';
    } else {
        if (version_compare(phpversion('http'),'1.6.0','>=')){
            echo 'The PECL_HTTP extension is installed and '.
              'version 1.6.0 or higher. You are all set!';
        } else {
            echo 'Please upgrade your PECL_HTTP extension to '.
              'version 1.6.0 or higher. You can download it '.
              'here'.
              '.';
        }
    }
    
    ?>
    

    Use function_exists() to check for individual functions

    So far the methods for checking dependencies have been somewhat broad. They check that the script has a certain version of PHP or extensions installed and that will likely be good enough in most cases. If you really want to be thorough you can also check if specific functions are available using the function_exists() method. In this example I check that the http_request() module, which is part of the PECL_HTTP extension, is there before I use it. If it is not, I use the less featured, built in, file_get_contents() function.

    ' .
            http_parse_message(http_get("http://www.example.com"))->body;
    } else {
        echo 'Using the file_get_contents():
    ' . file_get_contents("http://www.example.com"); } ?>

    Check for include files

    Here is a simple way to check for include files. It doesn’t verify their content but you can at least make sure they are there:

    
    

    Wrap up

    Checking dependencies is an important part of building robust software and hopefully the above techniques will help accomplish that. Even if your end user is a very technical they will likely appreciate a good dependency checking mechanism that quickly tells them whats missing to save them time. If your software will be used by non-technical users you might want to automatically and gracefully downgrade your software feature set instead of generating errors and asking them for something they won’t know how to do. Usability is king!

  • 25 ways to insecurity

    The 2009 CWE/SANS Top 25 Most Dangerous Programming Errors was recently released by CWE/SANS.

    Most of the items are old news but I think it is a good checklist that should be on the boiler plate for web application design documents. By putting security requirements in the software specification and design documents, the project manager can then allocate time and resources to security aspects of development. In addition, it reminds developers to ask themselves if the software is meeting those requirements throughout the development process. This is opposed to thinking about security after the entire application has been written and discovering a fundamental design flaw that will require re-writing a good portion of the application.

    I particularly appreciate that each item on the CWE/SANS list is weighted including weakness prevalence, remediation cost, attack frequency, attacker awareness, etc. No project has an unlimited budget but you can prioritize on where to focus your resources to achieve the most secure solution. Generally it is a good idea to ensure that the cost of defeating an application’s security far outweighs any benefits to be gained from doing so. The cost of defeating an application might include labor time, computing resources, fines, and threat of jail time with a cell mate named Bubba, etc.

    It is quite a challenge to develop secure web applications because generally by their nature they need to accept user input. I believe that it is typically much more difficult develop a secure system than it is to break in to the system given the same number of hours so there is often more burden on the developer. It might take only two or three days to develop a working database driven web application but many additional weeks to harden it against attacks and make it reliable, scalable, and highly available. Including security requirements in the software specification and design is essential to planning and allocating resources.

    Ideally automated tests should be included to continuously test vulnerabilities throughout the life of an application. This way security vulnerabilities introduced by code changes will be detected early in the development process instead of later in production. Automated tests could attempt buffer overflows, sql injections, etc. and could be executed prior to a developer’s check-in or on a nightly cron job that automatically checks out the code and runs the tests against it. Although costly to implement initially, automated security testing will likely pay for itself many times over the course of an application’s life. I plan to talk more about automated testing in future posts.

  • PHP HttpRequest class options and notes

    In a recent post I talked about the PECL_HTTP extension for PHP. In this post I will cover a few of the options you can set for the HttpRequest object and related functions.

    The PECL_HTTP extension allows you to set a number of options when you make a request. Usually you put the options in a key=>value array and pass the array as an argument to the request functions (I.e. http_get(), http_post_data(), http_request(), etc.) or assign the array to the HttpRequest object using the setOptions() method. Here is a code example using the HttpRequest object:

    $http_req = new HttpRequest("http://www.example.com");
    $http_req->setOptions(array(timeout=>10,useragent=>"MyScript"));

    In the above code the timeout was set to 10 seconds and the user agent, which is a request header that identifies the browser to the server, is set to “MyScript”. I am going to cover just a few of the options but a full list of all the request options can be found here.

    timeout

    The timeout option specifies the maximum amount of time in seconds that the request may take to complete. Set this too high and your HTTPD process that PHP is running in could be stalled for quite a bit waiting for a request that may never complete. If you set it too low you might have problems with sites that are just slow to respond. This may require some tweaking depending on what you are doing. If you are making requests to a web server in Taiwan you might want to set the timeout a bit higher. The default timeout does not appear to be documented in the HttpRequest options page on PHP.NET (that I could find) but if you look at the http_request_api.c file in the HTTP_PECL source code, it looks like it is 0L AKA nothing:

    HTTP_CURL_OPT(CURLOPT_TIMEOUT, 0L);

    This indicates it will wait forever unless you explicitly set a timeout so it might be a good idea to set one! I put together a page that makes an HTTP request and then another one that will sleep for some number of seconds that I can test against.

    Here is the code for the page that will sleep:

    <?php

    echo "Sleeping.";
    sleep(30);

    ?>

    Here is the code for the page that will make the HTTP request:

    <?php
    $http_req = new HttpRequest("http://localhost/alongtime.php");
    $http_req->setOptions(array(timeout=>10, useragent=>"MyScript"));
    try {
        $http_req->send();
    } catch (HttpException $ex) {
        if (isset($ex->innerException)){
            echo $ex->innerException->getMessage();
            exit;
        } else {
            echo $ex;
            exit;
        }
    } //end try block
    echo $http_req->getResponseBody();
    ?>
    

    When I pull up the page that makes the HTTP request in my browser I get the following error:

    Timeout was reached; Operation timed out after 10000 milliseconds with 0 bytes received (http://localhost/alongtime.php)

    If I don’t set the timeout option at all, the page responds 30 seconds later since it will wait forever or at least the 30 second sleep time on the target page.

    connecttimeout

    The connecttimeout option indicates the maximum amount of time in seconds that the request may take just connecting to the server. This does not include the time it takes for the server to process and return the data for the request. This option will have the same considerations as above although the number should be considerably lower since it is only the connection timeout and not the timeout for the whole request. Again, the default value is not documented but if you look at the http_request_api.c file in the HTTP_PECL source code, it looks like it is 3 seconds:

    HTTP_CURL_OPT(CURLOPT_CONNECTTIMEOUT, 3);

    dns_cache_timeout

    One of the interesting features of the HTTP_PECL extension is that it will cache DNS lookups. Some of the Windows operating systems do this but many of the Linux distributions do not by default. By the way, if you want to clear your cached DNS lookup entries on a Windows box use the command “ipconfig /flushdns”. If you are making multiple requests to the same site, DNS lookup caching should provide a significant performance advantage because a round trip to the DNS server isn’t required for every request. The dns_cache_timeout option sets the number of seconds that will pass before the cached DNS lookup results will expire and a new DNS lookup will be performed. Again, the default value is not documented but if you look at the http_request_api.c file in the HTTP_PECL source code, it looks like it is 60 seconds which is probably fine for most applications:

    HTTP_CURL_OPT(CURLOPT_DNS_CACHE_TIMEOUT, 60L);

    redirect

    The redirect option determines how many redirects the request will follow before it returns with a response. The default is 0 (this IS documented), which may not work in many situations because some applications respond with one or two redirects for authentication, etc. If you set this too high your application may get bounced around too many times and never return. I have not tried it but you could probably put someone in a redirect loop. Anyway, a value of around 4 or 5 should be adequate for most applications I would imagine.

    useragent

    The useragent option allows you to specify a different User-Agent request header to send to the server than the default which is “PECL::HTTP/x.y.z (PHP/x.y.z)” where x.y.z are the versions.

    I made a little one-liner test page that returns the user agent info sent to the server:

    <?php

    echo $_SERVER[‘HTTP_USER_AGENT’];

    ?>

    If I make an HTTP request to this page using the HttpRequest object without setting the useragent I get:

    PECL::HTTP/1.6.2 (PHP/5.2.6-2ubuntu4)

    If I do something like this:

    $http_req->setOptions(array(timeout=>10, useragent=>"Mark’s Browser"));

    I will get:

    Mark’s Browser

    The reason I bring this up is because some applications that you might make a request to may respond different depending on your user agent setting. In some cases you may need to spoof a specific browser to get what you are after.

    Conclusion

    As mentioned before, there are many more HttpRequest options. I just covered a few notable ones that I have some limited experience with.

  • Review: Lego 6211 Star Wars Imperial Star Destroyer

    Jen gave me the Lego 6211 Star Wars Imperial Star Destroyer for Christmas and I finished building it over the following week.

    The build is pretty easy (even for a 35 year old) and a lot fun. The kit comes in over 1300 parts so you really feel like your building something and not just putting a couple halves together. The parts come in numbered bags that correspond to the numbered sections in the instructions. There are often multiple bags with the same number for a single section. Lego included a few extras of the tiniest parts that tend to get lost in the carpet.

    There are only a couple downsides to the kit. The two “laser blasters” that launch projectiles work by you just quickly depressing the launch button that drives a wedge piece behind the projectile to push it out. This is kind of silly to me and I think the kit would have been better if they were just static elements in my opinion.

    The other negative was the capsule that goes inside. It is assembled by connecting two specially molded pieces together. I don’t like this kind of Lego construction and would have preferred it if they just left it out or designed it to build from smaller, standard Lego pieces.

    I put together a list of pros and cons:

    Pros

    • Over 1300 parts so it will keep you building for a bit.
    • Numbered bags.
    • Spare tiny pieces.
    • Looks great!
    • It’s big. About 23 inches long.

    Cons

    • The laser blasters that shoot projectiles are kind of cheesy.
    • The capsule that goes inside is mostly just two halves that go together.
    • Doesn’t shoot real bolts of green light. 😉

    Build gallery

    I took some pictures while my Imperial Star Destroyer was under construction:

    Embellishment

    I felt the kit would have been better if they included lights and a small universe. Fortunately, I was able to accomplish this with a small string of Christmas lights, a telescope photo of the stars, black velvet, and a little Photoshop magic:

    Conclusion

    I easily give this kit 5 out of 5 stars. It was fun to build and looks great.

  • How to: PECL HTTP request exception and error handling

    In a previous post, we created a simple PHP page that told us if http://www.example.com is up or down by using the PECL HTTP extension to make an HTTP request to the site and look for the string “example” in the response. Here is the code for our test page, httptest.php:

    <?php
    
    $http_req = new HttpRequest("http://www.example.com");
    $http_req->setOptions(array(timeout=>10,useragent=>"MyScript"));
    $http_req->send();
    
    if (stripos($http_req->getResponseBody(), "example") === false){
        echo "The page is down!";
    } else {
        echo "The page is up!";
    }
    
    ?>
    

    The problem with this code is that there is no error handling. Below are a few examples of what can go wrong and the resulting errors:

    DNS Lookup Failure

    If the DNS lookup fails the page will return the following error:

    Fatal error: Uncaught exception 'HttpInvalidParamException' with message 'Empty or too short HTTP message: ''' in /var/www/httptest.php:12 inner exception 'HttpRequestException' with message 'Couldn’t resolve host name; Couldn’t resolve host 'www.somewebsitethatdoesnotexist.com'
    (http://www.somewebsitethatdoesnotexist.com/)' in /var/www/httptest.php:4 Stack trace: #0 /var/www/httptest.php(12): HttpRequest->send() #1 {main} thrown in /var/www/httptest.php on line 12

    Since www.example.com is a valid DNS name I used “www.somewebsitethatdoesnotexist.com” instead to demonstrate what happens with an invalid name or failed DNS lookup. Note the “inner exception” that says “Couldn’t resolve host name”. More on “inner exceptions” in a bit. This is not very pretty for a diagnostic page.

    Connection Failure

    In this example I again used “www.somewebsitethatdoesnotexist.com” but I added the following entry to the /etc/hosts file on the server:

    10.10.10.10 www.somewebsitethatdoesnotexist.com

    Now the DNS entry will resolve using the /etc/hosts file but this is not a valid IP for any machine on my neetwork so I see this error:

    Fatal error: Uncaught exception ‘HttpInvalidParamException’ with message ‘Empty or too short HTTP message: ''' in /var/www/httptest.php:12 inner exception ‘HttpRequestException’ with message ‘Timeout was reached; connect() timed out! (http://www.somewebsitethatdoesnotexist.com/)’ in /var/www/httptest.php:4 Stack trace: #0 /var/www/httptest.php(12): HttpRequest->send() #1 {main} thrown in /var/www/httptest.php on line 12

    Again we have a inner exception buried in all of that telling me that the connection time out.

    404 Error

    In this example I put in “http://localhost/notarealpage.php” for the URL. This will connect to the local Apache server but that page doesn’t exist so the server will return a 404 file not found error. The server responded but since we are not checking the response code from the server our code just tells us the page is down and that is true but it would be useful to know that it is because the page is missing!

    The page is down!

    If the server responds OK we will get a 200 status code. We should handle any other response appropriately.

    Handle the exceptions

    The first thing we can do is put a try catch block around our code and try catching the HttpException as shown in example section of the documentation for the HttpRequest::send method:

    <?php
    
    $http_req = new HttpRequest("http://www.example.com");
    $http_req->setOptions(array(timeout=>10,useragent=>"MyScript"));
    
    try {
        $http_req->send();
    } catch (HttpException $ex) {
        echo $ex->getMessage();
    }
    
    if (stripos($http_req->getResponseBody(), "example") === false){
        echo "The page is down!";
    } else {
        echo "The page is up!";
    }
    
    ?>
    

    If there is a time out or connection failure the HttpException is caught and we see this:

    Empty or too short HTTP message: ''The page is down!

    Hmm… that is not very informative and the same error is displayed for both a name lookup failure and a connection timeout. We can also try changing:

    echo $ex->getMessage();
    to
    echo $ex;

    Now we get this:

    exception 'HttpInvalidParamException' with message 'Empty or too short HTTP message: ''' in /var/www/httptest.php:16 inner exception 'HttpRequestException' with message 'Couldn’t resolve host name; Couldn’t resolve host 'www.ssomewebsitethatdoesnotexist.com'
    (http://www.ssomewebsitethatdoesnotexist.com/)' in /var/www/httptest.php:5 Stack trace: #0 /var/www/httptest.php(16): HttpRequest->send() #1 {main}The page is down!

    That is painfully ugly but at least get the “Couldn’t resolve host name” message in there so we know what went wrong. Still, we can do better.

    In addition to putting a try-catch around the send() method you probably should surround all of your HttpRequest code with a try-catch that eventually catches “Exception” to be safe.

    The undocumented inner exception

    The HttpException object, which is not really documented all that well as of this writing, has something completely undocumented called an inner exception. The inner exception is a more detailed exception that is nested inside the HttpException object. We can check if an inner exception is set and if so, display that instead:

    <?php
    
    $http_req = new HttpRequest("http://www.example.com");
    $http_req->setOptions(array(timeout=>10,useragent=>"MyScript"));
    
    try {
        $http_req->send();
    } catch (HttpException $ex) {
        if (isset($ex->innerException)){
            echo $ex->innerException->getMessage();
            exit;
        } else {
            echo $ex;
            exit;
        }
    }
    
    if (stripos($http_req->getResponseBody(), "example") === false){
        echo "The page is down!";
    } else {
        echo "The page is up!";
    }
    
    ?>
    

    Now we get just the part we are interested in:

    Couldn’t resolve host name; Couldn’t resolve host 'www.ssomewebsitethatdoesnotexist.com'
    (http://www.ssomewebsitethatdoesnotexist.com/)

    If the lookup is OK but we get a connection timeout we now see this:

    Timeout was reached; connect() timed out! (http://www.somewebsitethatdoesnotexist.com/)

    If no inner exception is detected the HttpException is echoed.

    Check status codes

    Sometimes the server may be responding but we do not get a 200 status. This could because of a redirect, security error, missing page, or a 500 server error. The HttpRequest object provides a getResponseCode() method so we can check what the response was and handle it appropriately. If redirects are followed the last received response is used. For this example we will simply echo out some of the common status codes if we don’t get a 200:

    <?php
    
    $http_req = new HttpRequest("http://www.example.com/blah");
    $http_req->setOptions(array(timeout=>10,useragent=>"MyScript"));
    
    try {
        $http_req->send();
    } catch (HttpException $ex) {
        if (isset($ex->innerException)){
            echo $ex->innerException->getMessage();
            exit;
        } else {
            echo $ex;
            exit;
        }
    }
    
    $response_code = $http_req->getResponseCode();
    
    switch ($response_code){
        case 200:
        break;
        case 301:
        echo "301 Moved Permanently";
        exit;
        case 401:
        echo "401 Unauthorized";
        exit;
        case 404:
        echo "404 File Not Found";
        exit;
        case 500:
        echo "500 Internal Server Error";
        exit;
        default:
        echo "Did not receive a 200 response code from the server";
        exit;
    }
    
    if (stripos($http_req->getResponseBody(), "example") === false){
        echo "The page is down!";
    } else {
        echo "The page is up!";
    }
    
    ?>
    

    This handles a few of the more common response/status codes. To test the code we can put in a valid URL but a bogus page (I.e. http://www.example.com/blah) If everything works right we now see the following response from our diagnostic page:

    404 File Not Found

    Final Notes

    Our little diagnostic page can now handle most of the errors it will likely encounter when it attempts to test our example site, example.com. If we wanted to take this a bit further we could add a database back-end that maintains a list of multiple sites we would like to test. To take things a step further we could execute this PHP script from the command line via a cron job that runs every 5 minutes. We could then have the script send an e-mail when a site was down with the problem indicated in the message. If we wanted to maintain some up-times stats would could log the outages to a database and generate uptime/SLA reports daily, weekly, yearly, etc.

    In reality, I would just use something like IPSentry or Nagios to conserve effort for future generations but it was nice to think about. 😉 Happy coding!

  • How to: Find your php.ini file and enable PHP error reporting

    On some distributions PHP error reporting or display of errors is disabled by default as a security precaution. This is a good idea for production systems because errors may reveal useful information to undesirables. In a development environment on the other hand, it is generally useful to see your errors. 😉 If error display is disabled you may just see a blank browser window/empty page when you expect an error. To enable errors and error display, find the your php.ini file and make sure the following lines are set:

    ;Show all errors, except for notices and coding standards warnings
    error_reporting = E_ALL & ~E_NOTICE

    display_errors = On

    On Ubuntu you can find the php.ini file here:
    /etc/php5/apache2/php.ini

    On other distributions try:
    /etc/php.ini

    On Windows you might find it here:
    c:\windows\php.ini

    If you are running XAMPP it will be in the php folder off the XAMPP root.

    You will need to restart Apache (or IIS as the case may be) so your changes will take effect:

    On Ubuntu:

    sudo /etc/init.d/apache2 restart

    On other distributions you might try:

    sudo /etc/init.d/httpd restart
  • How to use the PECL HTTP (PECL_HTTP) Extension to make HTTP requests from PHP

    PECL HTTP is a feature-rich PHP extension that allows you to make HTTP and HTTPS (SSL) requests from your PHP code and handle the responses. If you are not familiar with PECL, it is a library of extensions to add functionality to PHP. It uses the same package and delivery system as PEAR.

    Many distributions do not install PECL_HTTP by default even if you install PHP. If you try to use one of the PECL_HTTP object or functions (I.e. http_get()) without the extension installed you will likely get something like this:

    Fatal error: Call to undefined function http_get()

    If this error comes up but you think you installed the PECL_HTTP package and it shows up in phpinfo(), then it is possible your PECL_HTTP install failed and did not get cleaned up so phpinfo() still sees it. This may happen if you didn’t install the cURL source library dependency first (see below).

    So let’s pretend we own the site http://www.example.com (See RFC 2606.) We want to build a PHP diagnostic page that will tell us that www.example.com is returning the string “example” somewhere in the page indicating if the page is up or down. First I need to install the PECL_HTTP extension. For details on how to install a PECL extension see my post “How to install a PHP PECL extension/module on Ubuntu“. For now I am going to assume that the php-pear and php5-dev packages have already been installed. These instructions are based on a Ubuntu install:

    • Install the libcurl3-openssl-dev package. The HTTP_PECL extension requires some of the cURL source libraries so we will have to install the cURL library package first:
      sudo apt-get install libcurl3-openssl-dev

      If you don’t install the cURL source library package you will likely see the following error when you attempt to install the PECL_HTTP extension:

      checking for curl/curl.h... not found
      configure: error: could not find curl/curl.h
      ERROR: ‘/tmp/pear/temp/pecl_http/configure --with-http-curl-requests --with-http-zlib-compression=1 --with-http-magic-mime=no --with-http-shared-deps’ failed
    • Install the HTTP_PECL module with the following command:
      sudo pecl install pecl_http

      The installer may ask you about some specific options but unless you really know what you want, you can probably just hit enter one or more times to accept all the defaults. If all goes well, the module should download, build, and install.

    • Once the install is complete, it will probably ask you to add a “extension=http.so” line to your php.ini file. Open up the php.ini file in your favorite text editor and add the line under the section labeled “Dynamic Extensions”. On Ubuntu the php.ini file seems to be located in the /etc/php5/apache2 folder:
      sudo nano /etc/php5/apache2/php.ini
    • Now that the php.ini file has been updated, Apache will need to be restarted so the new extension will be loaded:
      sudo /etc/init.d/apache2 restart

      That should restart Apache on Ubuntu but if that doesn’t work you can try:

      sudo /etc/init.d/httpd restart

    At this point hopefully the PECL_HTTP extension is installed so now we can create a PHP script that will make an HTTP request to http://www.example.com and display the results. For this example I will use the http_get() function. The first argument is a predefined constant of the request method type (GET, POST, etc.) and the second argument is a string containing the URL. I created a file named httptest.php (using “sudo nano /var/www/httptest.php” with the following code and put it in the /var/www folder (The default HTTP root on a Ubuntu server):

    <?php

    echo http_get("http://www.example.com");

    ?>

    or you could use the http_request function instead to do the same thing:

    <?php

    echo http_request(HTTP_METH_GET,"http://www.example.com");

    ?>

    When the page is opened in a web browser (I.e. http://sparky/httptest.php) it returns something like this:

    HTTP/1.1 200 OK Date: Sun, 04 Jan 2009 22:41:54 GMT Server: Apache/2.2.3 (CentOS) Last-Modified: Tue, 15 Nov 2005 13:24:10 GMT ETag: "b80f4-1b6-80bfd280" Accept-Ranges: bytes Content-Length: 438 Connection: close Content-Type: text/html; charset=UTF-8

    You have reached this web page by typing "example.com", "example.net", or "example.org" into your web browser.

    These domain names are reserved for use in documentation and are not available for registration. See RFC 2606, Section 3.

    That’s it. Those are some pretty quick one-liners if we are fine with the default options. This time we’ll do something similar but use the HttpRequest object instead and set a timeout and a different user agent:

    <?php

    $http_req = new HttpRequest("http://www.example.com");
    $http_req->setOptions(array(timeout=>10,useragent=>"MyScript"));
    $http_req->send();
    echo $http_req->getRawResponseMessage();

    ?>

    The output is the same as the previous two commands but this time the server could have taken up to ten seconds to respond before the request timed out. In addition, we sent the user agent string “MyScript” in the host header to the server. If you don’t want the HTTP response headers included in the the output, you use the getResponseBody() method instead:

    <?php

    $http_req = new HttpRequest("http://www.example.com");
    $http_req->setOptions(array(timeout=>10,useragent=>"MyScript"));
    $http_req->send();
    echo $http_req->getResponseBody();

    ?>

    This outputs:

    You have reached this web page by typing "example.com", "example.net", or "example.org" into your web browser.

    These domain names are reserved for use in documentation and are not available for registration. See RFC 2606, Section 3.

    No response headers this time. In fact, it looks as though you typed http://www.example.com in the browser.

    I could set some URL query parameters using the setQueryData() if example.com was a dynamic page that accepts arguments but I am pretty sure it does not.

    For the purpose of our example it doesn’t look like we have gotten very far but PHP is now getting a hold of the response data before we see it so we are halfway there. Now all we need to do is search for the string “example” and return some type of indicator letting us know that the example.com page is up or down:

    <?php
    
    $http_req = new HttpRequest("http://www.example.com");
    $http_req->setOptions(array(timeout=>10,useragent=>"MyScript"));
    $http_req->send();
    
    /*Note: The stripos() function just returns false if it doesn't find an upper or lower case version of the string we are looking for.*/
    if (!stripos($http_req->getResponseBody(), "example")){
        echo "The page is down!";
    } else {
        echo "The page is up!";
    }
    
    ?>
    

    If everything is working correctly we will see:

    The page is up!

    If example.com is broken or doesn’t return the string “example” our test page returns:

    The page is down!

    This is great and all but you may have noticed there is no error handling to speak of which isn’t good. I will talk about HTTP request/PECL_HTTP error handling in a separate post but until then, happy HTTPing!

  • How to install a PHP PECL extension/module on Ubuntu

    PHP PECL extensions provide additional functionality over the base PHP install. You can browse the PHP PECL extensions available at the PECL repository here. The following steps show how to install a PECL extension/module on Ubuntu using the PECL_HTTP extension as an example and assumes that you already have Apache 2 and PHP 5 installed:

    • First, you will need to install PEAR via apt-get to get the necessary package and distribution system that both PEAR and PECL use. From a shell prompt enter:
      sudo apt-get install php-pear

      You will be prompted to confirm the install. Just press “y” and enter. If all goes well you should see it download and install the php-pear package.

      Note: “sudo” is used to provide the super user privileges necessary for the following command. So in this case the command “apt-get install php-pear” is being executed with super user privileges by preceding it with “sudo”. Unless configured otherwise, you will normally be prompted to enter a password when you use sudo. This is usually the same password that you logged in with.
    • Now you will need to install the php5-dev package to get the necessary PHP5 source files to compile additional modules. Enter the following from a shell prompt:
      sudo apt-get install php5-dev

      If you do not install the php5-dev package and try to install a PECL extension using “pear install”, you will get the following error:

      sh: phpize: not found
      ERROR: `phpize’ failed
    • The PECL_HTTP extension requires an additional dependency package to be installed. You can probably skip this for other extensions:
      sudo apt-get install libcurl3-openssl-dev
    • Now we are finally ready to actually install the extension. From a shell prompt enter following but substitute “pecl_http” with the PECL extension name you are installing:
      sudo pecl install pecl_http

      The installer may ask you about some specific options for the extension you are installing. You can probably just hit enter one or more times to accept all the defaults unless you want to set specific options for your implementation. If all goes well, the module should download, build, and install.

    • Once the install is complete, it will probably ask you to add a “extension=” line to your php.ini file. Open up the php.ini file in your favorite text editor and add the line under the section labeled “Dynamic Extensions”. On Ubuntu the php.ini file seems to be located in the /etc/php5/apache2 folder:
      sudo nano /etc/php5/apache2/php.ini

      In this example, the pecl_http extension install asked me to add “extension=http.so”.

    • Now that the php.ini file has been updated, Apache will need to be restarted so the new extension will be loaded:
      sudo /etc/init.d/apache2 restart

      That should restart Apache on Ubuntu but if that doesn’t work you can try:

      sudo /etc/init.d/httpd restart

    If all went well your PECL extension should now be working. You might want to write a PHP test page that will test the basic functionality of the extension to make sure everything is working OK. You can use this later to check that all your required extensions are installed and working when you deploy to a new server. In this example where I installed the PECL_HTTP module, I might write a PHP page that uses the extension’s HttpRequest class to go get a page and return the results.

    That’s it. For the next extension install you can skip the steps to install the php-pear and php5-dev packages.