Web Hosting

I have always used *.phtml file extensions for my php web applications. Today, my web hosting provider decided to no longer grant Apache execute permissions for web files ending in phtml. Consequently, all my websites were down while I investigated and determined this was the issue. To correct this problem I renamed all my *.phtml files to *.php following the steps below.

1) Backup everything.
2) Find extent of problem:
find -name *.php
3) Change *.phtml files to become *.php files within the current directory
for f in *.phtml; do mv ./”$f” “${f%phtml}php”; done
*I didn’t trust my ability to do this globally.
4) Fix links in files
for arg in `find www/ -name “*.php”`; do perl -pi -e ‘s/phtml/php/g’ $arg; done;
for arg in `find www/ -name “*.php3″`; do perl -pi -e ‘s/phtml/php/g’ $arg; done;
*I have some legacy *.php3 files. I probably should clean this up.
5) Change *.phtml references in db to *.php
I think I only needed to update meta_page table
Please let me know if you notice anything that is still broken.

.NET Timers

I needed to create a timer within a C# windows application. Since I write few windows applications (and many ASP.NET web applications) I was off to the MSDN knowledge base. It turns out that the .NET Framework offers three timers:

1) System.Windows.Forms.Timer
2) System.Timers.Timer
3) System.Thread.Timer

My windows application is a winform application without a winform. Say what? I needed to create an application that runs in the background and controls loading and focus of other windows applications. (However, a .NET console application can’t control other windows applications, so I created a winform application without a winform.)

First, I tried to implement the System.Timers.Timer since the first timer appeared to depend upon a winform. According to Microsoft’s documentation I had to create an “infinite” loop that is interrupted by the timer which performs my windows hocus pocus ends and only causes the loop to end when the desired conditions are met. I created a small test of this approach and discovered that it pegged the CPU and used 12Mb of RAM for a simple timer event (that only popped up a windows message box) and the CPU remained pegged when timer events weren’t executing.

Second, I tried to implement the System.Windows.Forms.Timer without a winform. I discovered that if I put a call to Application.DoEvents(); in the “infinite” loop that the timer was tricked into working without a form, since all the form events were fired. I created a small test of this approach and it used 13Mb of RAM and came close to pegging the machine when the timer event executed, but fortunately once the timer event completed the CPU utilization dropped to near nothing. This timer was a slightly better steward of system resources but I deemed it unusable.
I came up with my own approach:

while(true) {

It still uses ~13Mb of RAM which is too much for a 5 line C# program, but that is Microsoft’s fault. However, CPU utilization spikes to ~2% when the event executes, but is near nothing during the sleep which models the timer interval.

Did anyone else have better luck with .NET Timers?

Making Ruby on Rails and PHP connect to MySQL

I am developing a Ruby on Rails application that uses MySQL as the database back-end. Everything has been progressing well until I decided to hook up the PHP piece to the same MySQL database. The PHP errors out with:

Warning: MySQL_connect(): Client does not support authentication protocol requested by server; consider upgrading MySQL client in … on line …

Fatal error: Cannot connect to MySQL database: Client does not support authentication protocol requested by server; consider upgrading MySQL client in … on line …

Apparently, MySQL has improved security via a new stronger authentication routine and the MySQL (mysql-essential-4.1.14-win32.msi) install I used defaulted to the new routine and PHP (php-4.4.1-installer.exe) defaulted to the old routine. After googling around I found that I could force MySQL to use the old authentication routine and fix the PHP issue by executing the following SQL:

use mysql;
update user set password = old_password('password') where user = 'root';
flush privileges;

The PHP scripts worked great, but when I went back and used the Ruby on Rails (RoR) piece I got the dreaded “Lost connection to MySQL server during query…” error. Grrr… I wanted both PHP and RoR to access mysql without issue. The solution I came up with was to create a MySQL account for PHP access and another for rails access. The PHP account was configured via:

use mysql;
update user set password = old_password('password') where user = 'phpuser';
flush privileges;

Now PHP and RoR access MySQL without issue and they use a least privilege access approach (instead of using the super powerful MySQL root account).

Ruby on Rails

Another comment on the Four Days on Rails documentation.

The code provided to sort the items by category has an unintended side effect. If an item contains a reference to a deleted category then the code outputs ‘Unfiled’. However, when a list of items with ‘Unfiled’ item(s) is sorted by category the ‘Unfiled’ item(s) disappear since the equi-join (i.e. inner join) is too restrictive to handle this properly.

Original code:

def list_by_category
@item_pages = Paginator.new self, Item.count, 10, @params['page']
@items = Item.find_by_sql 'SELECT i.*, c.category FROM categories c, items i ' +
'WHERE ( c.id = i.category_id ) '+
'ORDER BY c.category ' +
'LIMIT 10 ' +
"OFFSET #{@item_pages.current.to_sql[1]}"
render_action 'list'

I came up with some new SQL:

SELECT i.*, c.category FROM items i
LEFT JOIN categories c on i.category_id = c.id
ORDER BY c.category

However the ‘Unfiled’ item(s) always appear at the top of the ordering since <NULL> is sorted first. I found a way to force MySQL NULL values to the end of the sorted list. Therefore the SQL becomes:

SELECT i.*, c.category, category IS NULL AS isnull FROM items i
LEFT JOIN categories c on i.category_id = c.id
ORDER BY isnull ASC, category

Resulting code to sort the items by category:

def list_by_category
@item_pages = Paginator.new self, Item.count, 10, @params['page']
@items = Item.find_by_sql 'SELECT i.*, c.category, category IS NULL AS isnull FROM items i ' +
'LEFT JOIN categories c on i.category_id = c.id ' +
'ORDER BY isnull ASC, category, due_date ' +
'LIMIT 10 '
"OFFSET #{@item_pages.current.to_sql[1]}"
render_action 'list'

This approach outputs all the item rows but <NULL> category entries mess up the sort order.

def list_by_category
@item_pages = Paginator.new self, Item.count, 10, @params['page']
@items = Item.find(:all, :include=>  :category, :order=>'category')
render_action 'list'

Any ideas to fix this approach and not resort to using SQL?

Ruby on Rails

I decided to give the Four Days on Rails documentation another try. I pre-loaded the database using the todos.sql script provided. However, after I followed all the steps up to and including those on page 17 the list categories page (http://localhost:3000/categories/list) errored out:
undefined method `strftime’ for nil:NilClass

I decided that the strftime function might not like the value ‘0000-00-00 00:00:00’ stored in both the create_on and update_on fields. Consequently, I emptied the categories table. Then, the list categories page worked for the no results case. Then, I added a category and the list categories page executed as expected.

Ruby on Rails

I have been playing with Ruby on Rails and I am very impressed so far. I need to thank Bryce for pointed out what a great tool this is and recommending that I check it out. I found the Rolling with Ruby on Rails, Part 1 and Rolling with Ruby on Rails, Part 2 tutorials very helpful. However, I have found that the Four Days on Rails documentation wasn’t as helpful.
The source code provided for the to do tracking application doesn’t appear to work under the WEBrick web server.

F:\Ruby\rails\todo>ruby script/server
f:/ruby/install/lib/ruby/site_ruby/1.8/rubygems.rb:144:in `activate’: can’t acti
vate activesupport (= 1.1.1), already activated activesupport-1.0.4] (Gem::Excep
from f:/ruby/install/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:2
3:in `require’
from f:/ruby/install/lib/ruby/gems/1.8/gems/activesupport-1.0.4/lib/acti
ve_support/dependencies.rb:197:in `require’
from ./script/../config/..//config/environments/development.rb:6
from f:/ruby/install/lib/ruby/gems/1.8/gems/activesupport-1.0.4/lib/acti
ve_support/dependencies.rb:189:in `load’
from f:/ruby/install/lib/ruby/gems/1.8/gems/activesupport-1.0.4/lib/acti
ve_support/dependencies.rb:189:in `load’
from f:/ruby/install/lib/ruby/gems/1.8/gems/activesupport-1.0.4/lib/acti
ve_support/dependencies.rb:38:in `require_or_load’
from f:/ruby/install/lib/ruby/gems/1.8/gems/activesupport-1.0.4/lib/acti
ve_support/dependencies.rb:21:in `depend_on’
from f:/ruby/install/lib/ruby/gems/1.8/gems/activesupport-1.0.4/lib/acti
ve_support/dependencies.rb:167:in `require_dependency’
from f:/ruby/install/lib/ruby/gems/1.8/gems/activesupport-1.0.4/lib/acti
ve_support/dependencies.rb:167:in `require_dependency’
from ./script/../config/environment.rb:45
from f:/ruby/install/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:1
8:in `require__’
from f:/ruby/install/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:1
8:in `require’
from script/server:42

I know that Ruby supports multiple versions and I installed rails version 0.12.1 via “gem install rails –version 0.12.1″ that the provided source code is supposed to be compatible with. I verified that the installation was successful by comfirming the installed versions:

F:\Ruby\rails\todo>gem list –local
F:\Ruby\rails\todo>”f:\ruby\install\bin\ruby.exe” “f:\ruby\install\bin\gem” list
*** LOCAL GEMS ***
actionmailer (1.0.1, 0.9.1)
Service layer for easy email delivery and testing.
actionpack (1.9.1, 1.8.1)
Web-flow and rendering framework putting the VC in MVC.
actionwebservice (0.8.1, 0.7.1)
Web service support for Action Pack.
activerecord (1.11.1, 1.10.1)
Implements the ActiveRecord pattern for ORM.
activesupport (1.1.1, 1.0.4)
Support and utility classes used by the Rails framework.
fxri (0.3.2)
Graphical interface to the RI documentation, with search engine.
fxruby (1.4.2, 1.2.6)
FXRuby is the Ruby binding to the FOX GUI toolkit.
rails (0.13.1, 0.12.1)
Web-application framework with template engine, control-flow layer,
and ORM.
rake (0.6.2)
Ruby based make-like utility.
sources (0.0.1)

This package provides download sources for remote gem installation
Any ideas? Does it matter that version 0.12.1 was installed after the newer version 0.13.1?

PHP Lacks Quoting Power

Why doesn’t PHP have a quoting function similar to qq() in Perl? PHP is a web scripting language used to build dynamic HTML and output it to a browser. Why shouldn’t it be easy to output HTML strings that contain double quotes?

Firstly, I don’t want to escape every double quote (\”) which results in:

$html .= "&lt;table border=\"$color\" background=\"ccccff\"&gt;\n";

Secondly, I don’t want to use PHP’s heredoc syntax (<<<): [php]$html = <<< ENDHTML &lt;table border="$color" background="ccccff"&gt; ENDHTML;[/php] This is overkill for single lines of HTML. I want to do something like this in PHP: [php]$html = qq | &lt;table border="$color" background="ccccff"&gt; |;[/php] Any ideas?

Comment Spam Arms Race

Comment spam is a problem. I have been using MT-Blacklist to try to eliminate it. However, it is a time consuming game of one-up-man-ship. I read Dan’s “Spam Begone” approach and decided to give it a try.

I disabled MT-Blacklist and setup SCode. The first approach (MT-Blacklist) consisted of utilizing a blacklist of known strings to identify comment spammers and zap their spam. To maintain an effective blacklist required constant updates, which I hadn’t bothered to automate. In addition to being time consuming to maintain, false-positive string matches would eliminate useful comments. Therefore, strings need to be specific enough to eliminate comment spam while avoiding vagueness which would result in false positives. What a conundrum!

The new approach displays a security code and requires the end user to manually reproduce it before they can save their comment. This should stop spambots in their tracks (for awhile), by proving the end user is a person rather than a computer program (specifically, a bot which emulates a person). The only comment spam I will need to worry about is items that are manually typed in. That is until the next round in this comment spam arms race.