Thursday, November 26, 2009

Suppress rm No such file or directory

rm: cannot remove `*.html': No such file or directory


If you have a cron job that deletes files daily or on another schedule you probably don't want to get the email that tells you something like that. There's always the option of redirecting the output to /dev/null but then you're screwed if there's any other errors that you actually want to know about.

Instead, use the -f or --force flag of the rm program. That flag literally means ignore nonexistent files, never prompt. So instead of getting that cannot remove error, it will just go about business as usual.

Instead of the following to delete two types of files,
rm /path/to/*.html; rm /path/to/*.html.gz


Use the following to delete them and not have to worry if one type doesn't exist.
rm -f /path/to/*.html; rm -f /path/to/*.html.gz

Monday, November 2, 2009

svnserve.conf: Option expected

If you get this error when trying to checkout an SVN repository you likely have whitespace before one of the settings in the svnserve.conf file the path in the error refers to. There should be a number in the error, which will tell you what line the whitespace is on.

For instance, the following error is given if I remove the hash from the beginning of the passwd line and leave the whitespace there between the beginning of the line and the start of the option.

svnserve.conf:20: Option expected

Saturday, October 31, 2009

X-Pad: avoid browser bug

If you're looking for an explanation to this "X-Pad: avoid browser bug" header you should feel lucky. The X-Pad header is a work around Apache uses for a bug in really old versions of Netscape and it only shows up if there's a chance the 256th or 257th byte of a response is a newline.

It's a junk header, all it does is prevent the 256th and 257th byte of the response from being a newline. If Apache didn't do this, old versions of Netscape would hang.

It's a wonder why this is still part of Apache, we're talking really old versions of Netscape here.

Tuesday, October 13, 2009

IE8: Intranet Always in Compatibility Mode

I was having some odd problems with websites on my local intranet and eventually I traced it back to the sites being forced into IE7 Compatibility Mode for some odd reason. I could view the exact same page on a remote server and it would act as expected.

The culprit, was a little setting in the IE8 Tools menu called Compatibility View Settings, more specifically it was a checkbox in the resulting dialog labeled "Display local intranet sites in compibility view" that was automatically forcing every page on every server in my local intranet to automatically use compatibility mode without even displaying the broken page icon in the address bar.

Sunday, September 27, 2009

PHP MySQLi bind_result Empty LONGTEXT

The problem is that when using the PHP MySQLi extension with prepared statements, I was getting an empty value in one of my bound variables after using $mysqli->execute(), $stmt->bind_param(), and $stmt->fetch(). If I executed the exact same query using $mysqli->query() and subsequently using $result->fetch_object() I would get the values I was looking for.

I went as far as copying and pasting the variable names associated with the column from every place they were used in the script and comparing them to make sure there were no typos.

Now, if I leave everything exactly how it is, I can toggle this behavior by switching the data type of the problematic column between TEXT and LONGTEXT. When the column is LONGTEXT then the prepared statement returns an empty string to the bound variable. If the column is TEXT then everything works as expected.

Strange behavior to say the least. I've caught a few unresolved PHP bug reports that appear to be related to this when looking for PHP MySQLi LONGTEXT, but nothing too detailed.

In any event, we'll be able to work with a TEXT column instead of using a LONGTEXT column in this application. You should probably research the impart if could have on you before switching though. Some of the older bug reports appear to mention Wordpress users struggling with this when reading from the Wordpress database for plugins.

Wednesday, September 16, 2009

Wordpress xargs: xgettext: No such file

I was getting the following error when trying to use the Wordpress i18n-tools to generate POT files for a Wordpress plugin.

xargs: xgettext: No such file or directory
Couldn't generate POT file!


At first it didn't make sense. I couldn't figure out why it wasn't finding my plugin directory or file. It hadn't donned on me that the file which couldn't be found was actually xgettext.
I'd assumed I already had gettext installed. I know it's installed on at least one of the machines around here.

In any event, took less than 5 minutes to fix by installing gettext.

sudo apt-get install gettext

Wednesday, September 2, 2009

PHP Get Oldest File

I was looking around to make sure there wasn't some sort of built-in function in PHP now for determining the oldest file in a directory. I didn't find a built-in function that returns the oldest file, but I found plenty of user functions that were not what I was looking for.

So, I wrote my own old file getter function. The function will accept either an array of file paths or a string which will be passed to glob in order to get an array of file paths. The function returns the oldest file found.

function oldest_file($dir)
{
if(is_string($dir))
{
$dir = glob($dir);
}
$oldest = array_shift($dir);
foreach($dir as $file)
{
if(filemtime($file) < filemtime($oldest))
{
$oldest = $file;
}
}
return $oldest;
}

Tuesday, September 1, 2009

PHP GD Heatmap Generation

I recently set out to write my own tools to generate a heatmap from clicks on my websites. So far the collection of click positions has been a little tricky because of things like the visitors screen being a different size than mine, javascript being enabled but Adsense being blocked which shifts the position of some elements, and a whole host of other annoyances that don't come to mind at the moment.

One thing that did come sort of easy was figuring out how to generate a heatmap image using the PHP GD image functions and x/y pairs from clicks. At first I was wondering how to get the three color areas without having later clicks overlap other clicks and throw off the flow of the colors.

Rather than working with a click at a time, I needed to generate the heatmap image one color and one click at a time. I would need to loop through the image three times, each time drawing progressively smaller circles using different colors.

I put together a simple function to draw a heatmap onto an image using a list of x/y points and an image created using GD.

<?php

function draw_heatmap($image, &$clicks)
{
if(function_exists('imageantialias'))
{// Only available with compiled in version of GD
imageantialias($image, true);
}

// Heatmap colors
$cold = imagecolorallocate($image, 0, 0, 255);
$warm = imagecolorallocate($image, 0, 255, 0);
$hot = imagecolorallocate($image, 255, 0, 0);

// Loop through the clicks and draw the largest/coldest circles first
foreach($clicks as $click)
{
imagefilledellipse($image, $click['x'], $click['y'], 30, 30, $cold);
}

// Next draw middle/warm circles over the cold ones
foreach($clicks as $click)
{
imagefilledellipse($image, $click['x'], $click['y'], 20, 20, $warm);
}

// Finally draw the smallest/hot circles over everything
foreach($clicks as $click)
{
imagefilledellipse($image, $click['x'], $click['y'], 10, 10, $hot);
}

return true;
}

$width = 200;
$height = 200;
$image = imagecreatetruecolor($width, $height);
$clicks = array(
array('x' => 123, 'y' => 123),
array('x' => 45, 'y' => 113)
);
draw_heatmap($image, $clicks);
header('Content-Type: image/png');
imagepng($image);

?>

Tuesday, August 18, 2009

ORDER BY RAND Alternative

If you're reading this chances are you know everything you need to know about why using ORDER BY RAND() in MySQL is not such a good idea so I'll skip all of that and get right to the alternative.

Add a new column to your database table called rand_id and make it large enough to hold a UNIX timestamp. The index is extremely important. This table modification may take awhile if you have a large table.

ALTER TABLE my_table ADD `rand_id` INT NOT NULL ,
ADD INDEX(rand_id)


With the new column in place, setup a cron job which executes an SQL statement to update that column once a day (or more often if you wish). What this does is give each row a random ordering ID starting with the current time plus a random portion of the seconds in a day.

UPDATE my_table
SET rand_id = (UNIX_TIMESTAMP() + (RAND() * 86400))


To fetch a random row you use a query like this.

SELECT *
FROM my_table
WHERE rand_id > UNIX_TIMESTAMP()
LIMIT 1


Here's a few numbers from a test table with 1,572,851 rows. The server used isn't exactly optimized to be a database server either.

Selecting a random row using ORDER BY RAND() takes 37 seconds.
Executing the query to update the rand_id column takes 110 seconds.
Selecting a random row after the rand_id column is updated takes 0.0012 seconds.

Now if we needed a random row every second of every day, we would need 86,400 rows.

86,400 * 37 = 3,196,800 seconds spent selecting random rows. It would take more than a month to select a days worth or rows using ORDER BY RAND().

86,400 * 0.0012 = 103.68 seconds spent fetching random rows. If we add the 110 seconds needed to generate the rand_id column values that brings us to 213.68 seconds. That's less than 5 minutes spent fetching a days worth of random rows. Huge improvement over the ORDER BY RAND option.

Now, this solution can have a few serious drawbacks depending on your needs and table size.

The longer it has been since the rand_id column was generated, the more predictable the random row will be since you can make a note of the rows that have been selected throughout the day and narrow things down considerably.

Tables with less than roughly 90,000 rows are in danger of producing the same result multiple times in a row for seconds to minutes at a time.

Monday, August 17, 2009

Putty Ubuntu SSH Autologin

With the addition of a Windows Vista computer to my small network I find myself needing to get into the Ubuntu systems via SSH when I'm on the Vista computer. This is simple with Putty, but entering my username and password every time is annoying.

I've already setup the rest of the systems on my network to have Ubuntu login to SSH automatically. I don't see why I can't have the Windows Vista computer do the same with Putty.

Having already setup the other systems, I knew I needed a key to add to the authorized_keys file on the remote system, and by looking at Putty I knew I needed a private key file.

I tried using ssh-keygen on the Ubuntu system to generate keys, but the format used for the private key was different looking than the file format of the PPK file Putty was looking for.

In order to get the key pairs I needed a tiny utility called puttygen from the Putty downloads page.


Here is what the interface looked like. I left everything default and clicked Generate.

After moving my mouse around to generate randomness while it generated a new pair of keys I clicked the Save Private Key button, selected yes when asked if I wanted to save the key without a passphrase, then selected the place I wanted to store the PPK file.

Next I copy and pasted the public key from the text area that showed up above the buttons and below where it says Public key for pasting into OpenSSH authorized_keys file, into my authorized_keys file on the remote system via nano in an open SSH session.

After closing Puttygen I closed my existing SSH session out and re-opened Putty to be presented with the settings dialog.


I entered my username in the Connection -> Data -> Autologin Username field as shown here.

Then I selected the PPK file I saved earlier in the Connection -> SSH -> Auth screen.

Viola! Autologin to Ubuntu via SSH using Putty worked like a charm.

Wednesday, May 13, 2009

Ubuntu SSH Autologin

Are you looking for Putty Ubuntu SSH Autologin ?


I've got a small network of Ubuntu computers at home and only one has a monitor. The rest I manage with SSH, FTP, and XDMCP logins.

Entering my password every time I want to get a terminal for one of the remote systems isn't very fun because my passwords are upwards of 16 characters. So I needed a way to login with SSH without needing to type a password.

On my main system, the one with the monitor, I used ssh-keygen at the terminal to generate a pair of public and private keys. By default ssh-keygen wants to create key files named id_rsa and id_rsa.pub but I decided to use home-network for my key files instead so I know what these ones are for.

I also just pressed enter for the passwords to leave them blank.

user@main-computer:~/Desktop$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/home/user/.ssh/id_rsa): /home/user/.ssh/home-network
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/user/.ssh/home-network.
Your public key has been saved in /home/user/.ssh/home-network.pub.
The key fingerprint is:
00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00 user@main-computer
The key's randomart image is:
+--[ RSA 2048]----+
| |
+-----------------+
user@main-computer:~/Desktop$


Once that was done I opened my FTP application and navigated the local and remote file lists to the following directory.

/home/user/.ssh/


I uploaded home-network.pub to the remote system and renamed it to authorized_keys so that on the remote system I had the following.

/home/user/.ssh/authorized_keys


If that file already existed on the remote system, I would have opened both files in my text editor and copied the contents of the *.pub file into that authorized_keys file.

Once everything was saved and uploaded I fired up SSH to login to the remote system and was logged in without needing to enter my password.

Monday, April 6, 2009

Digitalpoint Style "days old" phpBB3 MOD

One of the things I like about the Digitalpoint forum listings is that little gray indicator to the right of thread titles that lets you know how old a topic is in days. I don't think I've seen this handy little notice anywhere other than Digitalpoint (at least before now) and it kinda boggles my mind as to why.

Especially for phpBB3 forums, where adding it is as simple as adding a single line in three files.
Here's a screenshot of the prosilver theme with the MOD applied.

phpBB3 days old mod

And here's what needs to be done, and the order to do it so you don't get any errors during the change.

First open /language/en/viewforum.php and find the following line,
 'VIEW_FORUM_TOPICS'  => '%d topics',


After that line add this line and then save/upload the file.
 'OLD'     => 'old',


Next open /viewforum.php and find the following line,
   'TOPIC_TITLE'  => censor_text($row['topic_title']),


After that line add the following line then save/upload the file.
   'TOPIC_AGE_DAYS' => round((time() - $row['topic_time']) / 86400),


Next open /styles/prosilver/template/viewforum_body.html and find the following piece of code which will be at the end of the line it is on.
<a href="{topicrow.U_VIEW_TOPIC}" class="topictitle">{topicrow.TOPIC_TITLE}</a>


After that line add the following line then save/upload the file.
<!-- IF topicrow.TOPIC_AGE_DAYS > 0 --><small style="color:#999;"> - {topicrow.TOPIC_AGE_DAYS} <!-- IF topicrow.TOPIC_AGE_DAYS > 1 -->{L_DAYS}<!-- ELSE -->{L_DAY}<!-- ENDIF --> {L_OLD}</small><!-- ENDIF -->


Once those changes are made, clear the cache from the ACP and you should be up and running.

Thursday, April 2, 2009

apple-touch-icon

Have you looked at a website lately and saw a meta/link element with a rel attribute of apple-touch-icon wondering what it is ?

Well, it's similar to a favicon, except it's for the iPhone and iPod Touch menu screens. Apple calls them Web Clips.

Here's an actual example from Twitter.



<link href="http://assets1.twitter.com/images/twitter_57.png" rel="apple-touch-icon" />


You can use these elements to define the icon iPhone and iTouch users should use when they save your web appicaitons address on their device. Just like when browser users bookmark a page.

It's basically just a 57x57 pixel PNG image with no special effects applied. The device itself will add rounded corners, a drop-shadow, and a glassy reflection.

Here's some more details from Apple.