Announcing Ping Brigade

Ping Brigade is my latest project. It allows you to measure ping, web page load times and web server latency from multiple servers I run around the world. Give it a try!

Tags:

No Comments

Proper way to send e-mail from PHP

Depending on your setup, PHP might not be sending properly encoded e-mails if you just use the mail() function. Specifically, headers might not be properly encoded, and this includes the subject, the To, and Reply-To, etc.  Just give it a try using some non-ASCII characters and see if it works. If it doesn’t, here’s a better way:

// At the beginning of each page load, set internal encoding to UTF-8
mb_internal_encoding('UTF-8');

// ... rest of initialization code

// Headers are an associative array, unlike the original mail() function
function better_mail($email, $subject, $body, Array $headers = array(), $additional_parameter = NULL) {
    // Make sure we set Content-Type and charset
    if ( !isset( $headers['Content-Type'] ) ) {
        $headers['Content-Type'] = 'text/plain; charset=utf-8';
    }

    $headers_str = '';
    foreach( $headers as $key => $val ) {
        $headers_str .= sprintf( "%s: %s\r\n", $key, $val );
    }

    // Use mb_send_mail() function instead of mail() so that headers, including subject are properly encoded
    return mb_send_mail( $email, $subject, $body, $headers_str, $additional_parameters );
}

better_mail( 'example@example.com', 'Résumé with non-ASCII characters', 'Résumé content.', array( 'From' => 'noreply@example.com' ) );

For more information see:

Tags: , ,

No Comments

Introducing LovelyCo.de

LovelyCo.de is a social website for people to share code samples they find particularly elegant. My goal in creating it was to make the experience as smooth as possible. If you have a piece of code, in any language, that you think is worth, sharing, head on over!

No Comments

How to set up nginx with PHP on Ubuntu

In an environment where RAM is the major constraint, Apache might not be your best bet. Since I have moved all of my web projects over to an unmanaged VPS, I was looking for ways to either optimize or replace the LAMP stack with something less resource hungry. One of the ways I found to decrease the RAM requirement of my web services was to replace Apache with an event driven web server called nginx. There are quite a few resources on setting it up but not many discuss how to marry nginx to PHP (to run a WordPress blog for example). The best guide I found so far is this one. I built upon it to create the simplest nginx+FastCGI/PHP setup possible.

Step 1: Installation

$ sudo apt-get install nginx php5-cgi

Many of the nginx/PHP guides out there will tell you that you need to install spawn-fcgi, and most of them will have you compiling it from source. It turns out that php5-cgi package contains a FastCGI wrapper already, so the above two packages are all you need to get going.

Step 2: Startup script for FastCGI

We want to create a Startup script for FastCGI PHP processes to run on every boot up. Here is the script I use:

!/bin/bash
BIND_DIR=/var/run/php-fastcgi
BIND="$BIND_DIR/php.sock"
USER=www-data
PHP_FCGI_CHILDREN=8
PHP_FCGI_MAX_REQUESTS=1000

PHP_CGI=/usr/bin/php-cgi
PHP_CGI_NAME=`basename $PHP_CGI`
PHP_CGI_ARGS="- USER=$USER PATH=/usr/bin PHP_FCGI_CHILDREN=$PHP_FCGI_CHILDREN PHP_FCGI_MAX_REQUESTS=$PHP_FCGI_MAX_REQUESTS $PHP_CGI -b $BIND"
RETVAL=0

start() {
    echo -n "Starting PHP FastCGI: "
    mkdir $BIND_DIR
    chown -R $USER $BIND_DIR
    start-stop-daemon --quiet --start --background --chuid "$USER" --exec /usr/bin/env -- $PHP_CGI_ARGS
    RETVAL=$?
    echo "$PHP_CGI_NAME."
}
stop() {
    echo -n "Stopping PHP FastCGI: "
    killall -q -w -u $USER $PHP_CGI
    RETVAL=$?
    rm -rf $BIND_DIR
    echo "$PHP_CGI_NAME."
}

case "$1" in
    start)
        start
  ;;
    stop)
        stop
  ;;
    restart)
        stop
        start
  ;;
    *)
        echo "Usage: php-fastcgi {start|stop|restart}"
        exit 1
  ;;
esac
exit $RETVAL

Put the text above into /etc/init.d/fastcgi-php. Then run:

$ sudo chmod 755 /etc/init.d/fastcgi-php
$ sudo update-rc.d fastcgi-php defaults
$ sudo /etc/init.d/fastcgi-php start

Note the variables at the top of the script and adjust to fit your available RAM. The the php-cgi processes will get bigger after a while so allot at least 16-20MB for each. This script is slightly different than most I’ve found, in that it uses a UNIX socket instead of a TCP one for communication. UNIX sockets are faster, and you never have to worry about your firewall setup.

Step 3: Enable PHP processing

Create a new file /etc/nginx/fastcgi_php with this content:

# pass the PHP scripts to FastCGI server listening on UNIX socket
location ~ \.php$ {
    fastcgi_pass   unix:/var/run/php-fastcgi/php.sock;
    fastcgi_index  index.php;
    fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
    include /etc/nginx/fastcgi_params;
}

Now define you virtual servers. Here is a sample config:

server {
    listen   80;
    server_name  example.com www.example.com;

    access_log  /var/log/nginx/example.com.access.log;

    root   /var/www/example.com;
    index  index.php index.html index.htm;
    autoindex off;

    error_page  404  /404.html;
    error_page   500 502 503 504  /50x.html;

    # deny access to .htaccess files, if Apache's document root
    # concurs with nginx's one
    location ~ /\.ht {
        deny  all;
    }
    # Enable PHP
    include /etc/nginx/fastcgi_php;
}

Notice the next to last line of the file. You can include this line in all of your server definitions to enable PHP processing through FastCGI.

Step 4: Enable the site:

Enable the site and reload the configs:

$ sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/example.com
$ sudo /etc/init.d/nginx reload

Optional tweaking

There are several other things you might want to consider once this setup is in place. First of all, nginx does not process htaccess files since those are Apache specific. For the most part this means that mod_rewrite rules you’ve had in place won’t work. The good news is that nginx has its own URL rewriting engine, which is quite capable. The bad news is that you will have to translate your mod_rewrite rules to the syntax used by nginx.

WordPress compatibility

A “quick fix” exists for WordPress:

server {
    # Your server definition
    # ...

    location / {
        # this serves static files that exist without running other rewrite tests
        if (-f $request_filename) {
            expires 30d;
            break;
        }

        # this sends all non-existing file or directory requests to index.php
        if (!-e $request_filename) {
            rewrite ^(.+)$ /index.php?q=$1 last;
        }
    }

    # End of server definition
}

Note that if you are using the above rules and WP Super Cache, the cache will be used in only “half-on” mode, so you might want to at least consider translating the rewrite rules used by it to take full advantage of the caching.

Security considerations

Security of this setup can be increased if you define separate pools of PHP processes for each virtual server or even application, running as separate users. You can do so by running separate startup scripts. Just define each pool to use its own UNIX socket and instead of inlining the /etc/nginx/fastcgi_php file, write its contents with the customized socket name in each virtual server config.

Tags:

1 Comment

New server

At the beginning of February I decided to move off my shared hosting and put all my projects to a small VPS. My old hosting provider, HostMonster, has been good to me, but my needs have grown beyond a simple shared plan. The new server is with BuildYourVPS, a TOCICI subsidiary. It is a new and no frills company. There is little documentation and no control panel. On the other hand the support staff is quick to respond, friendly and efficient. With my favorite Debian-based distro, Ubuntu, I feel right at home so the lack of docs doesn’t bother me. The performance has been more than satisfactory and their prices are very decent.

The goal of this move has been to level out the performance of this blog and Disc ID DB and to allow more room for expansion. As I keep expanding capabilities of Disc ID DB, Server robustness will become more and more important, so this is a good long term move.

Tags:

No Comments

Disc ID DB now supports movies

Thanks to the Movie DB, my pet project Disc ID DB now supports movies as well as TV shows. I have made several other improvements to the code which should help performance and reliability of the service:

  • Now using prepared statements for database queries
  • Returning more detailed errors
  • Database backups available to the public
  • Stats page available to the public

In addition I have been brewing a client for the database which will allow everyone and anyone to backup their DVD’s with all the metadata attached. More to come soon.

Tags:

No Comments

This does not scale well

Here is a piece of code I just found:

  # new location
  # creates new record or seeks empty record marked by group_id = -2
  if($CGI_DATA['new'] == 'New Location') {
    # look for empty - abandoned record
    $SQL  = "SELECT * FROM location WHERE group_id = -2";
    $result = mysql_query($SQL);
    if($row = mysql_fetch_array($result)) {
      $CGI_DATA['location_id'] = $row['location_id'];
    } else {
      $SQL  = "INSERT INTO location SET group_id = '-2',location_bname='New Location',location_roomnum='',
              location_capacity=0,location_address='',location_order=0,location_status='active'";
      $result = mysql_query($SQL);
      $CGI_DATA['location_id'] = mysql_insert_id();
    }
    $CGI_DATA['edit']='New';
  }

A little background: this application has a number of groups each of which can specify several locations. What the above code does is it inserts a location with an “invalid” (-2) group_id, and then allows you to “edit” that record on the next page load. I don’t know how they thought this was acceptable.

Tags: ,

No Comments

Web apps don't have the "push"

Recent debate about web apps vs native apps has stirred me up enough to throw my two cents out there. You see, I am a web developer and I think that the web as a platform certainly has a future. However, I am not going to say that web apps have already won. They haven’t. They are very far away from winning and the biggest problem with them is the lack of ability to exchange data to their environment.

Case 1: GMail

GMail is an excellent web based interface. I use it whenever I am on someone else’s computer, but when I am in my home environment I use Thunderbird and IMAP. Why? Because I normally have several Firefox windows open, with several tabs each. If one of them has GMail open in it, I have to consciously open that window and check the title of the GMail tab to see if I have any new messages. Unlike Thunderbird, GMail cannot push a new mail notification into the notification tray of my desktop. With GMail, I have to consciously bring up the window and check for a particular tab. Of course I could use something like Prism from Mozilla, but notice then GMail will not be a conventional web app in the sense that they are being debated.

Case 2: Hulu

Hulu is one of the best video streaming services out there. Recently, Hulu has released native app clients for all three predominant operating systems (Windows, Mac OS X and Ubuntu Linux). What are the advantages of the native clients? For one, currently no browser supports remote control devices. On the other hand the Ubuntu version of the client plays nice with the standard LIRC straight out of the box. This is one of the steps necessary to take Hulu from a geeky web based streaming service to the living room media center big screen TV. Another advantage is that the native client gets to control the window size, making itself full screen not just when a show is playing but also while you browse for your favorite show. Unless you create your entire web app in Adobe Flash (yuk!), you cannot get this functionality.

Case 3: Google Latitude on the iPhone

Google Latitude is usable on the iPhone. Sort of, kind of. First of all, there’s the address bar which pops up every now and again and covers the top portion of the screen. Next, it cannot take advantage of push notifications, so I cannot push an update of my location to a friend, the way HeyWAY does. I stopped using this app a month ago because the native app I replaced it with was much better.

Possible options

To have web apps catch up with their native bretheren, we would need to extend the browser to tie it in much closer with its native environment. We could even make some sort of an operating system that only runs web apps. This will, however, limit you in what kind of hardware you can run on and what peripherals you can support. For example how would you like it if you landed on a rouge web app that started printing hundreds of car insurance ads on your printer because it had access to the device? Or how would you feel about the web app taking control of your microphone and web cam and recording everything you are doing? Clearly some sort of a security policy would need to be in place to allow certain apps access to the browser environment, the same way that Safari on the iPhone can ask you if you want to allow Google Latitude to use the GPS.

As I mentioned web apps have a future. Their specific strengths already make them ideal for certain types of uses. The challenge is to expand those strengths so that they can be used in more cases.

Tags: , , ,

No Comments

Add jQuery to any page for some DOM-fu

If you are web-development inclined, and use a JavaScript development console, such as Firebug, you might wish that every page had jQuery, a excellent JavaScript library, for you to manipulate as you see fit. Well, it seems that Karl Swedberg over at Learning jQuery has come up with a neat bookmarklet to get the job done:

jQuerify

Head over to Better, Stronger, Safer jQuerify Bookmarklet for more details. To add this bookmarklet simply drag it to your bookmarks toolbar. When you press it, it will load jQuery and add it to the page you are currently viewing. Once it is loaded, simply open Firebug and have at it with your superior DOM-fu. Here’s what you might try:

var $ = jQuery; // Set $ to be jQuery

alert( $('a').length ); // Count anchor tags on the page

$('a').css('font-weight', 'bold'); // Make all links bold

$('object, embed').remove(); // Remove all the annoying flash crap

$.post( 'index.php', {data: 'value'} ); // Do a POST request from the current page

You can use these technique are nearly infinite: extracting data out of a page, re-styling it, automating form submissions, etc. I started using this method about a year ago, but discovered the bookmarklet only now. Trust me, once you try it you won’t be able to live without it.

Update: It appears that John Resig has also published a jQuerify bookmarklet. I guess this technique is pretty popular among the JavaScript developers.

Tags:

No Comments

Announcing E-mail Herald (a.k.a. Stop Spamming Yourself Framework)

It is amazing how much information I need on daily basis. Here is my informational morning routine:

  1. Check the weather.
  2. See what meetings I have today (thanks Google Calendar!)
  3. Check out the Woot Deal of the Day (silly I know but it’s fun)
  4. Check on various nightly scripts and see if they ran properly. This is about a half dozen scripts that send confirmations to my work or my personal e-mail.

The whole procedure takes quite a while for what it really is: getting tiny bite-sized pieces of information. I decided it was enough and I wanted to automate the whole process. That’s why I created E-mail Herald, a simple framework for extracting those bite-sized pieces of information out of various internet services and canning them into digest e-mails (heralds). Here’s a sample herald I got this morning:

Weather: 38-52 deg. F, Partly Cloudy

-----

Woot: Perfect Pullup - $14.99

-----

Calendar Igor Partola:
  --No events--

-----

Calendar Igor Partola NIS@BU:
  * Veteran's Day

-----

Cron Jobs:
  * bu:maps:****** - success
  * bu:maps:****** - success
  * bu:maps:******** - success
  * bu:*** - success
  * netstore - success - 2009/11/11 03:19:12 [3967] sent 1704120805 bytes  received 1443 bytes  1481201.43 bytes/sec
  * bu:*******-******* - success - 0 applicants e-mailed

Pretty nifty huh? This is the kind of functionality that I Want Sandy used to have before it closed down. The problem with Sandy was that she e-mailed you at 5am and you couldn’t change it. Also, you couldn’t collect information from other services such as Google Calendar, etc. E-mail Herald does it all and if it doesn’t do something you want it to do – write a plugin.

2 Comments