Yet another anti-PHP rant

I’m quite surprised to see this great stir in the blogosphere caused by Tim Bray and his essay On PHP. I mean, what’s the deal anyway? We all know that PHP is a lousy programming language. So instead on focusing on the big picture and trying to list as many of its faults as I can remember, I’ll stay on one specific problem, which is really a pain for me.

I’ve been programming in PHP for the past five years (I’ve started using it in the beginning of 2001, during my Computer Science studies). PHP is (was?) both my love and hate. My biggest complain about it, and probably about all other programming languages used for web development, is that there is no decent way of producing HTML code from your application. No matter how hard you try, you’ll always end up having spaghetti either in your HTML or in PHP code (or even worse, in both places). Sure, separating business from presentation logic is a common practice which helps the cause (apart from the fact that most PHP folks mix HTML with PHP whenever and wherever they can). Problem is, that it’s not good enough.

It would be all much simpler if you didn’t need to put any logic into your presentation code. The moment you introduce loops or conditionals – bam – you either get unreadable code or spaghetti HTML with way too much whitespace (or without any whitespace at all) and improper indentation. Not to mention that I am probably not the only one sick of typing all those nasty angle brackets all the time. But what about all that specialized templating engines? Frankly, they are not any better. Besides the fact that some of them require a certain overhead (like defining the variables you wish to use in your templates – Smarty, anyone?), they all still carry the same burden – they either produce spaghetti HTML or have spaghetti templates.

Actually, Rails, being my current weapon of choice, is no better in this area. My .rhtml templates are a complete mess. I strive to have my HTML as pretty as it can be, because (maybe strangely) I find it easier to debug if I have a nice HTML output to deal with, instead of a nice .rhtml template. Too bad that I feel utter disgust when I look at those templates. And just as Smarty is no better for PHP, Liquid and similar projects are no better for Rails. However, there is still hope, with projects like Markaby (which, unfortunately, has its own issues, check the comments).

Just a small digression, to sum all this up. Rails has solved one other, big inconvenience, namely writing your own SQL for each and every interaction with the database. Thanks to ORM provided by ActiveRecord, you don’t have to write SQL any more (at least in most of the cases; the 80/20 rule). This is one of the basic reasons that Rails is so much better than PHP. Markaby tries to do the same to HTML, what ActiveRecord did to SQL. No more those nasty < /> characters! We’ll see how (and where) it goes.

Custom HTTPS POST queries in Ruby

Complementing both the manual for the Net::HTTP class and Rail’s guide to rendering proxied pages (from the Rails wiki) here is a short script, which makes use of a custom made HTTPS POST query (btw. HTTP POST is basically the same, you just have to remove the ssl declaration and change the destination port).

First, the script makes a GET query to the target host (in the example, it is the login page for Wirtualna Polska webmail). In the next step it reads which cookies the website wants to set. After that, we can make our POST query. We send both filled in POST parameters (and hidden inputs too) and all of the cookies, which would normally be set in the browser. After that the script just prints out response headers and data (if there’s any).

The solution is simple, short and clean, although it took me few hours to find out that POST parameters must be a &-separated string and that the headers is a hash array. After that, it was a piece of cake.

Anyway, here’s the script:

#!/usr/bin/ruby

require 'net/http'
require 'net/https'

http = Net::HTTP.new('profil.wp.pl', 443)
http.use_ssl = true
path = '/login.html'

# GET request -> so the host can set his cookies
resp, data = http.get(path, nil)
cookie = resp.response['set-cookie']


# POST request -> logging in
data = 'serwis=wp.pl&url=profil.html&tryLogin=1&countTest=1&logowaniessl=1&login_username=blah&login_password=blah'
headers = {
  'Cookie' => cookie,
  'Referer' => 'http://profil.wp.pl/login.html',
  'Content-Type' => 'application/x-www-form-urlencoded'
}

resp, data = http.post(path, data, headers)


# Output on the screen -> we should get either a 302 redirect (after a successful login) or an error page
puts 'Code = ' + resp.code
puts 'Message = ' + resp.message
resp.each {|key, val| puts key + ' = ' + val}
puts data

Installing Ruby on Rails on Ubuntu

This guide is valid for the following distributions:

Ruby on Rails

While there is a nice tutorial in the Ruby on Rails wiki, it’s by no means complete. According to it, you should only type: apt-get install rails to have the newest Rails installed on Ubuntu. It installs both Ruby and Rails, but what about rubygems? Sorry, not this time. There is also another caveat. Although commands like rails test and ruby script/server are working properly, ruby/console is not. If you had the misfortune of experiencing the aforementioned behavior, then this tutorial is just for you.

Pre requirements:

nano /etc/apt/sources.list

Add the following at the end of the file (replace edgy with breezy if you are running Breezy, dapper for Dapper, etc.):

# All Ubuntu repositories
deb http://archive.ubuntu.com/ubuntu edgy main restricted universe multiverse

Update your apt sources:

apt-get update

Installation:

Install Ruby with developer’s libraries:

apt-get install ruby ri rdoc irb ri1.8 ruby1.8-dev libzlib-ruby zlib1g

Download and install Ruby Gems (no .deb package, unfortunately):

wget http://rubyforge.org/frs/download.php/17190/rubygems-0.9.2.tgz
tar xfvz rubygems-0.9.2.tgz
cd rubygems-0.9.2
ruby setup.rb

Update your RubyGems (also updates the gems cache):

gem update --system

If you get Could not find rubygems-update (> 0) in the repository or a similar error, you need to delete your RubyGems cache:

$ gem env gemdir
PATH_TO_DEFAULT_GEM_REPOSITORY
$ rm PATH_TO_DEFAULT_GEM_REPOSITORY/souce_cache

and

rm $HOME/.gem/source_cache

In the next step install the OpenSSL bindings for Ruby (needed to install signed gems). They are required if you get the following error: SSL is not installed on this system, while installing signed gems like rake:

apt-get install libopenssl-ruby

And the last one:

gem install rails -y

And this is basically it. There are, however, depending on your needs, some…

Additional steps:

One of them is setting up the Rails to connect to the MySQL database in a proper way. We will be using the MySQL C bindings, which, for one, support the MySQL old style passwords (which is set as default for Ubuntu 5.04), but are also significantly faster (in the 2-3x range) than the native Ruby MySQL bindings. First, we will need to install the gcc compiler (and libc6-dev if you don’t have it already installed). Although strange it may seem, as a default it is not installed on a clean Ubuntu installation.

apt-get install gcc libc6-dev

MySQL development libraries are also required (mysql_config plus mysql/include):

apt-get install libmysqlclient14-dev

(for MySQL 5.0 you might be better of with libmysqlclient15-dev).

And now we can install C MySQL bindings:

gem install mysql

If you get "sh: make: not found" do:

apt-get install make

or if you have it already installed, add it to your path:

export PATH=/usr/bin:"${PATH}"

And, of course, in the end install Mongrel:

gem install mongrel -y

And that’s it. Rails installation is complete. Complicated? Not really :) Happy coding!

Rails 0.13 released

Quoting David Heinemeier Hansson: with so much new stuff in there it’s not even funny. I suppose I just need to bang my head against the wall a few more times, first, to receive a little bit of motivation to finally finish the fourth day of Four Days on Rails and second, to receive a little bit of inspiration to develop a useful (at least for me, for a start) Rails application that has a little bit more of code apart from scaffold

Here’s the official announcement.

Trace your referrers in real-time

One of the magic things about Dreamhost is the ability to login to your account using ssh. Apart from standard things that you can do with it, like compile and install any program that you like (excluding those, which require root access, of course), you can also experience a little bit of magic if you run this command:

tail -f current-httpd-accesslog

There is really something special about tracking your website’s visitors as they come. And, of course, the most interesting thing is actually knowing where they come from (also known as referrers). The problem with this command is that it prints lots of garbage on the screen (like timestamps, response codes, sizes, etc.). The problem is that you cannot grep your real-time tailed log. Why? Don’t ask me, I’m not a Linux guru. You just can’t and that’s it. You can, however, write a script, which deals with that in its own way. And this is what I’ve been writing for the whole day. It was both fun and painful to learn for the n-th time all those shell hacks and quirks. Was it worth it? Sure it was! As a result I came up with this little bash script to trace your referrers in real-time. You can download it or view it below. I must warn you, though. It is highly addictive. Really…

#!/bin/bash

# ========================================================================
# REAL-TIME WEBSITE REFERERS TRACER
# ========================================================================
#
# What?
#   Real-time website referrers tracer is a shell script that lets you
#   trace your visitors as they come. Script works in an ultra compact
#   four-columns view :)
#
# Why?
#   Because you cannot do 'tail -f access_log | grep something' and you
#   really want to grep out most of the stuff that your httpd puts in
#   the logs.
#
# Requirements:
#   - website (with not too low and not too high traffic),
#   - shell account on the server where your website is hosted,
#   - access to httpd logs that use the COMBINED format.
#
# Installation:
#   - copy anywhere in your home directory,
#   - edit the script and set the 'log' variable so it actually
#     points to your current httpd log,
#   - make sure the script has execute rights (chmod +x trace-referers).
#
# Running:
#   - just run the script and watch the screen.
#
#
# Version: 0.2 (2005-06-18)
# Author: Paweł Gościcki, http://pawelgoscicki.com
#
# No copyright rights. You can do whatever you want with this. You may even
# claim this scrip has been written by you from the very beginning ;)
#
# If you, however, improve it, send me a copy (paul_AT_pawelgoscicki.com).
#
# Based heavily on the tgrep script by Ed Morton (morton_at_lsupcaemnt.com):
# http://unix.derkeiler.com/Newsgroups/comp.unix.shell/2004-01/0818.html


# CONFIGURATION
# =============

# Where your httpd log file is
log="current-httpd-accesslog"

# What files to exclude (request for those files won't be shown, regexp syntax)
exclude="\.gif|\.jpg|\.png|\.ico|\.css|\.js"

# Width of request and referrer columns (set it to match your terminal's width)
col_width=35


# MAIN SCRIPT
# ===========

# Check if log file actually exists (and is readable)
if [ ! -r "${log}" ]; then
echo "Cannot access log file: $log"
exit 0
fi

# After startup we will output few lines
start=`wc -l < "${log}"`
start=$(( $start - 30 ))
if (( ${start} < 0 ))
then start=$((0))
fi

# Main loop
while :
do
  end=`wc -l < "${log}"`
  end="${end##* }"
  if (( ${end} > ${start} ))
  then
    start=$(( $start + 1 ))
    sed -n "${start},${end}p" "${log}" | egrep -v "${exclude}" | \
    awk -v col_width=$col_width '{

      # we are only interested in GET/POST requests
      if ( match($0, /\"(GET|POST).*?\"/) > 0 )
      {
        split($0, fields, "\"")

        # IP_ADDRESS
        tmp = $1
        while ( length(tmp) < 15 ) tmp = tmp " "
        printf "%s", tmp " "
    
        # HTTP_REQUEST (GET/POST)
        tmp = substr(fields[2], 0, index(fields[2], "HTTP/") - 1 )
        tmp = substr(tmp, index(tmp, " ") + 1, col_width)
        while ( length(tmp) < col_width ) tmp = tmp " "
        printf "%s", tmp " "
    
        # REFERER (the juice)
        tmp = fields[4]
        while ( length(tmp) < col_width ) tmp = tmp " "
        printf "%s", tmp " "
    
        # USER_AGENT
        printf "%s", fields[6]
    
        # new line at the end
        printf "\n"
      }
    }'

    start=${end}
  fi

  # this is an endless loop executed every second
  sleep 1
done

Your current hosting provider does not support ssh access? You might then want to read my other post about hosting with dreamhost for as little as 9$/year. Have fun!

Rolling with Ruby on Rails on Dreamhost

As of yet it is unofficial, but Dreamhost has indeed added support for Ruby on Rails (v0.12.1) together with FastCGI!

I have just tested it briefly and it works as it is supposed to.

If you want to turn FastCGI on, you must log in into your Dreamhost panel and go to Domains -> Web. Single checkbox and FastCGI is enabled. Couldn’t be simpler.

Dreamhost, regarded by many as the hosting company is indeed staying on the cutting edge, being the first major player to support Rails.

UPDATE: It’s now official.

(via)