Commenting on the code: in the loop, $j is pointless, as it's just $i%$key_len (and using strlen($text) in the loop iterator is also a needless waste of clock cycles).
The original code is horribly laid out (why? Was there an obfuscated PHP contest I didn' hear about?) - laserlight's reformatting makes it legible.
It's unnecessary to turn the key into an array; leaving it as a string also works and avoids the need to convert back and forth with ord() and chr().
Using exit() to kill the entire script just because the key is too short is nasty (and this is real, live code?).
It's possible for an ASCII 127 (delete) character to get into the cipherstream; for example if the plaintext character is 'n' and the corresponding character in the key is 'q'. This may not be desirable behaviour.
The purpose of the masking with 0x1f and 0xe0 is to keep the first three bits of each byte untouched; this is done to both the key and the plaintext, so only 62.5% of the plaintext is encoded.
In fact, since all the bitwise operations can be carried out on strings, just for a giggle I had a go at rewriting the algorithm using only strings and avoiding loops.
<?php
// String EnCrypt + DeCrypt function
// Author: halojoy, July 2006
// Modified and commented by: laserlight, August 2006
//
// Exploratory implementation using bitwise ops on strings; Weedpacket September 2006
function convert($text, $key = '') {
// return text unaltered if the key is blank
if ($key == '') {
return $text;
}
// remove the spaces in the key
$key = str_replace(' ', '', $key);
if (strlen($key) < 8) {
exit('key error');
}
// set key length to be no more than 32 characters
$key_len = strlen($key);
if ($key_len > 32) {
$key_len = 32;
}
// A wee bit of tidying in case the key was too long
$key = substr($key, 0, $key_len);
// We use this a couple of times or so
$text_len = strlen($text);
// fill key with the bitwise AND of the ith key character and 0x1F, padded to length of text.
$lomask = str_repeat("\x1f", $text_len); // Probably better than str_pad
$himask = str_repeat("\xe0", $text_len);
$k = str_pad("", $text_len, $key); // this one _does_ need to be str_pad
// {en|de}cryption algorithm. The whole thing. Right here.
$text = (($text ^ $k) & $lomask) | ($text & $himask);
return $text;
}
echo convert('To be or not to be, that is the question', 'mysecretkey');
echo "\n";
?>
As for the cryptography; not a lot to say. I already know the answers to my main questions (like, why bother whacking out something half-assed when it's easier to use something decent? If you want half-assed then base64_encode(strrev(gzencode($key.$text,9))) is plenty half-assed) because I already know the answer:
sci.crypt FAQ wrote:3.7. Why are many people still using cryptosystems that are relatively easy to break?
Some don't know any better. Often amateurs think they can design secure systems, and are not aware of what an expert cryptanalyst could do. And sometimes there is insufficient motivation for anybody to invest the work needed to crack a system.
In this case, the only justification would appear to be "insufficient motivation": no-one actually cares about your secrets enough to bother. Basically, after taking into account all the crippling that was done either to make the thing easy to break or just to fix each little bug as it cropped up there's not much more to add beyond what has already been said about it since its invention 450 years ago.