Tuesday, December 11, 2007

Easier .htaccess On Windows

Now and then you'll see someone wondering how to create an .htaccess file for Apache on Windows. This usually appears to be people who have a private server setup on their local intranet for testing, then uploading to a remotely hosted server.
Windows apparently complains with an error message similar to the following when you attempt to create or rename a file to a name starting with a dot. Such as .htaccess.

You must type a filename !



What alot of people aren't aware of is that Apache actually has a setting you can alter to change the name of the file used for .htaccess.
The name of that setting is AccessFileName.

Now at first glance it would seem that altering the AccessFileName directive could cause major problems, and it can. You probably shouldn't alter this setting on anything other than a system in an intranet enviroment. You should also be prepared to rename existing .htaccess files when doing this.

That said, here's an example of what can be done with the AccessFileName directive. Note that this needs to be done in the Server Config or a Virtual Host container.
AccessFileName ht.htaccess

<Files ~ "^(ht)?\.ht">
Order allow,deny
Deny from all
</Files>


The line AccessFileName ht.htaccess should be pretty self explainitory. It makes the filename used ht.htaccess instead of just .htaccess
This way it's simple to create an ht.htaccess file on the Windows machine, then simply rename it to .htaccess once it gets uploaded to the server.

The second part of that example code isn't required, but it's done just in case you ever have other people with access to the machine. There's a similar section in your actual Apache configuration file already. That section doesn't include the (ht)? part that prevents the new ht.htaccess from being viewed as currently happens with the default .htaccess files.
It also will not conflict with anything if you later decide to revert to the default setting for AccessFileName & forget to remove it.

The Apache Manuals' htaccess page goes into much more detail about htaccess files.

Thursday, December 6, 2007

BOM Squad

Cartoony Bomb
Since posting about phpBB3 and UTF-8 BOM/Signature in October, I discovered there seems to be alot of people tripping over UTF-8 encoded files that have a BOM, otherwise known as a Signature embeded.
Most people seem to know what the BOM is and what it does, but don't know how to get rid of it or how it got there.

Well, now seems like a good time to go over how the BOM gets in files, how to find out if an editor is silently prepending a BOM to UTF-8 encoded files, and how it can be removed if needed.

A major source of these BOM headaches seems to be Notepad on Windows. When saving a file with UTF-8 encoding using Notepad on Windows, it automaticly prepends the BOM to the file but doesn't inform the user about this.

I think this is partly due to quite a few people suggesting that Notepad can be used to easily and quickly convert files to UTF-8 in order to solve issues with strange characters showing up in files.

utf-8 Windows Notepad
Here's a screenshot of the choices you get when saving a file using Notepad. You can see there's no mention of BOM, or Signature there.
I can't help but wonder why Microsoft decided to diferentiate between big & little endian for Unicode but not leave a choice for the UTF-8 BOM.

From what I understand Windows text editors are the main contributers of UTF-8 BOM in files. UNIX type system applications generally don't include the BOM because it can cause problems with configuration files, which are primarily text files.

The first thing to do is check your editors' settings, particularly areas having to do with encoding, very well for UTF-8, BOM, and or Signature. You may have controll over what your editor does and it's good to be aware if you do.

One method to determine if your editor is secretly prepending the BOM to your files is to save an empty file using UTF-8 encoding and look at the filesize. If what should be an empty file has a filesize of three(3), your editor is prepending a BOM. You might want to consider leaving a single character in the file & making sure it's not four(4) bytes instead, some editors may default to non-UTF encoding for empty files.

I use a Notepad replacement called Notepad2 for quick editing. That application gives me an option to save UTF-8 encoded files with or without the BOM, though it calls it a Signature. Notepad2 displays which encoding is used in the file on the applications status bar which comes in handy from time to time. The application is self-contained and compressed is only about 250KB, easily carried around on a USB memory stick.

Another option for getting rid of the BOM is using the Perl script in this forum thread. I tried it myself (as seen in that thread), it works exactly as expected. This is probably the one of the easiest options if the files are on a Ubuntu or Linux system.

I'm sure there's plenty of people looking for a PHP solution to removing the BOM, so here's function designed for that situation called debom_utf8. It should work in either PHP4, PHP5. The methods used are generic enough that it should continue to work in PHP6.

<?php
/*
@author: http://develobert.blogspot.com/
@description : PHP Function to remove UTF-8 BOM/Signature from the beginning of a file.
@param $filename: Name of the file a BOM should be looked for and removed from.
@returns (bool): Returns true if the file didn't, or no longer contain(s) a BOM, false on error.

@example usage: echo debom_utf8('BOM.txt') ? 'free of BOM' : 'error';
*/
function debom_utf8($filename = '')
{
if($size = filesize($filename) && $size < 3)
{// BOM not possible
return true;
}
if($fh = fopen($filename, 'r+b'))
{
if(bin2hex(fread($fh, 3)) == 'efbbbf')
{
if($size == 3 && ftruncate($fh, 0))
{// Empty other than BOM
fclose($fh);
return true;
}
else if($buffer = fread($fh, $size))
{// Shift file contents to beginning of file
if(ftruncate($fh, strlen($buffer)) && rewind($fh))
{
if(fwrite($fh, $buffer))
{
fclose($fh);
return true;
}
}
}
}
else
{// No BOM found
fclose($fh);
return true;
}
}
return false;
}
?>


Comments on other methods to deal with BOM disposal are more than welcome.