Tidbits @ Kassemi

A collection of opinions, thoughts, tricks and misc. information.

Tuesday, August 30, 2005

 

The AJAX Syntax Highlighter ... Coming soon!



Note: Still looking for file hosting. All open source stuff, just many different projects / advice pieces in one place. Anybody who's interested, please e-mail me (jkassemi at gmail dot com). Thanks.

Remember when I said I was going to work on that syntax highlighter with AJAX and the DOM? Well, I found the tool I'm going to use... http://colorer.sourceforge.net/

It offers loads of syntax highlighters, and it will be VERY easy to get this project done with it. The question is now whether I work directly off of the API and create code that everybody on all systems can use it with ( I have no life option ), or just use shell_exec ( I have no life option ( DAMN ) ) to read the output of the syntax...

Well, only time will tell, as today I only have a very limited of time to do anything but work. I'm right in the middle of some more optimizations and bug fixes for my main project. I'll probably have the code up tomorrow.

Until next time!

Monday, August 29, 2005

 

ARGH! (Learn good programming practice early part two)

First, let me inform everybody that I'm looking for a place to host files for this blog. It's difficult to take code that's posted all over a page, and blogger doesn't help much, as they take out some of the markup, so I'm never sure if the code I do post actually works when you copy and paste it. The solution is just to give everybody a tar.gz'd or tar.bz2'd file... I'm also going to start working on an AJAX syntax highlighter for the code here, that would search through the page for code elements and highlight them appropriately. I already have such a system for help information on my current project, so changing that wouldn't be that hard. The only problem is I need a place to put a javascript and php file, so I can include that functionality here.

Now to the ARGH! portion... When I first started programming in PHP (about a year or so), I took a look at a sessions tutorial so I could create a login page for my first project, a forum that allowed infinite category creation and customization... Pretty nice, but looking at it after I had done some work, I realized that it would never be commercially suitable. The tutorial, which I wish I could find, said that all I needed to do to provide a login for the user was something like this (I use my mysql class for this stuff, but you can figure it out):


session_start();
$db->query(sprintf("select password from users where username='%s'",
mysql_real_escape_string($_POST['username'])));
if($db->result() == $_POST['password']){
$_SESSION['username'] = $_POST['username'];
}else{
echo "ERROR!";
}


That was great. All I needed to do was present the user a form with a password and username, attach something like the above to it, and:


/* WARNING: THIS IS NOT GOOD. DON'T DO. JUST DEMONSTRATING SOMETHING */
session_start();
if(isset($_SESSION['username'])){
echo "I'm a valid log-in!";
}


Because sessions are the most secure fucking things on the planet, right? ARGH!

So I started programming that way for a while, until everything I'd done used that technique to get what user was logged in, whether the user was logged in, and whether the user's login was valid... Soon enough my code base was polluted, and I decided I'd fix it later, putting the date off forever. Sure enough, the day I had to fix it was today! I decided I didn't want to mess around with SSL for this site, which doesn't really have information that needs that much protection, but I didn't want any packet spy to get the passwords for my users when they loaded the page up on a public network. So I decided to go with a javascript md5 hash solution...

I create a database:


challenge | ip | created


Which holds a randomly created variable, the challenge, the ip that requested the challenge, and the time in which the challenge was created... I actually used an additional column, `type', as I want to have those image challenges sent too (remember yesterday's cool spirals?).

So, whenever a user wants to log in, they are given a form that has the following inputs:



A challenge is randomly created using this code:


function genRandStr($length){
$st=array(48,65,97);
$en=array(57,90,122);
$chr="";
for($i=0;$i<$length;$i++){
$rnd=rand(0,2);
$chr.=chr(rand($st[$rnd],$en[$rnd]));
}
return $chr;
}


This is sent to a hidden field on the form, "challenge."

When the user fills out the username, password, and characters in the image, the following is executed:


var challenge = document.getElementById('challenge').value;
var username = document.getElementById('username').value;
var password = document.getElementById('password').value;
var challenge_image = document.getElementById('challenge_image').value;
var final_hash = hex_md5(password);
final_hash = hex_md5(final_hash+challenge+username);
location.href = "login.php?username=" + username + "&challenge_image=" + challenge_image + "&secured_pass=" + final_hash + "&challenge=" + challenge;



The md5 library for javascript that I use can be found here:
http://pajhome.org.uk/crypt/md5/index.html

Basically, I convert all the password, along with the challenge, to an md5 hash... Which gets sent over the network to my login script again. This means that the password itself is not sent, meaning a packet sniffer can't get a hold of them. The packet sniffer does see the challenge string, though, but it still can't do anything with it... Brute forcing that combination would take some time...

login.php takes a look to see if all of the information is in order, and then does the following:


/* The type is because this is the challenge image string... 1=challenge image, 0=login challenge */
$connection->query(sprintf("select * from security_challenges where ip='%s' and type=1 and challenge='%s'",
mysql_real_escape_string($_SERVER['REMOTE_ADDR']),
mysql_real_escape_string($_GET['challenge_image'])));
if($connection->numrows() == 0){ /* They didn't type the challenge image string in right */}


$connection->query(sprintf("select challenge from security_challenges where ip='%s' and type=0 and challenge='%s'",
mysql_real_escape_string($_SERVER['REMOTE_ADDR']),
mysql_real_escape_string($_GET['challenge'])));
$challenge_db = $connection->result();

if($connection->numrows() == 0){ /* We couldn't find the challenge that they said they used */}

/* Get the password, we're doing this the same way I did before */
$connection->query(sprintf("select password from br_registered where username='%s'",
mysql_real_escape_string($_GET['username'])));

if($connection->numrows() <> 1){ /* The username wasn't found */}
$password_db = $connection->result();
$hash_compare = md5($password_db.$challenge_db.$_GET['username']);

if($hash_compare <> $_GET['secured_pass']){
/* The hash we created with the javacript and the hash we just used to check the js hash didn't
* match. Do not allow the user access with whatever routine you put in here. */
}else{
/* The hashes DID match */
/* This is a little more secure. We're not holding the password in the session,
* but another hash. $secure_global_pass is a secret phrase that should get changed
* every two weeks or so. */
$password_secure_compare = md5(md5($password_db).$secure_global_pass.$username);
$_SESSION['username'] = strtolower($_GET['username']);
$_SESSION['password_secure'] = $password_secure_compare;
/* Do what you will to give the user access. Forward to another page, whatever.... */
}



Great. So we're able to get a user logged in securely. The image bit might be a little excessive, but I like it, so I'm going to use it. If I get a single complaint from a user, it'll come right down... But how am I now getting the username and checking that the username is valid? I include this file with everything I do that requires a login... "logincheck.php":


function username(){ /* Return the username of the logged in user. */
global $secure_global_pass;
/* Get the login information, if it's stored in a cookie or in an active session */
if(isset($_COOKIE['your_site'])){
@$username = $_COOKIE['your_site']['username'];
@$password_secure = $_COOKIE['your_site']['password_secure'];
}elseif(isset($_SESSION['username'])){
@$username = $_SESSION['username'];
@$password_secure = $_SESSION['password_secure'];
}else{
return false;
}
include_once('./class/mysql.php');
$db = new mysqlConnection();
$db->change('whatever_database_you_use');
$db->query(sprintf("select password from users where username='%s'",
mysql_real_escape_string($username)));
if($db->numrows == 0){
return false;
}
$password_database = $db->result();
$password_secure_compare = md5(md5($password_database).$secure_global_pass.$username);
/* We're comparing another generated hash with the one supplied to us. If they
* don't match, the user is spoofing something, and shouldn't be allowed to see
* this page */
if($password_secure_compare <> $password_secure){
return false;
}else{
/* Since somebody might be viewing this page after saving the information to a cookie,
* we should log them in. */
/* Place the log-in in the session. */
$_SESSION['username'] = $username;
$_SESSION['pass_secure'] = $password_secure;
}

return $_SESSION['username'];
}

/* And here's the routine that's called on every page: */
$current_user = username();
if($current_user === false){
/* However you prefer to do this is fine */
page_forward('./login.php');
exit;
}


So, if the user isn't logged in correctly, they are forwarded immediately to the login page... Now, to get rid of the old method took replacing over 2000 references to $_SESSION['username'] for a username with $current_user. Since some of the $_SESSION['username'] instances were actually needed to modify the session, I had check each instance before I replaced it. Too much work.

Hope you get some ideas from that!

Sunday, August 28, 2005

 

Proving human existence: user authentication images

You've seen them everywhere (and probably have already programmed yours, so this is useless, but if not), and you know they're effective at keeping scripts from posting comments (at least) to your site. They are simple images that contain a string of numbers and letters, that the user needs to type into an input box to prove they're not a shell script. We'll use my image class that I posted yesterday to start this out. Don't make fun of my image class for missing certain obvious things that I realized where missing today. I didn't fix the image class yet, but I might if I ever get an audience and that audience wants a good one. Here is the class that extends the image class for creating those functions:



/*
* Basic PHP Image class
* Copyright (C) 2005 James Kassemi
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.

* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.

* You can view the LGPL here: http://www.gnu.org/licenses/lgpl.html */
class image_manipulation extends image {
public $image;
public $width;
public $height;
public $color;

function new_image($width=200, $height=200){
$this->width = $width;
$this->height = $height;
$this->image = imagecreatetruecolor($width, $height);
imageantialias($this->image, true);
$background = imagecolorallocate($this->image, 225, 228, 169);
imagefill($this->image, 0, 0, $background);
}

function get_color($red, $green, $blue){
return imagecolorallocate($this->image, $red, $green, $blue);
}

function create_swirl_template($x, $y, $color, $angle_step=.05, $start_size=5, $size_stepx=.5, $size_stepy=.5, $revolutions=5, $rand_step_var=0){
$x = rand(0, $this->width);
$y = rand(0, $this->height);

$angle = rand(0, 360);
$sizex = $start_size;
$sizey = $start_size;

$steps_total = (360/$angle_step) * $revolutions;
for($i=0;$i<$steps_total;$i++){
if($rand_step_var > 0){
$size_0x = rand(-$rand_step_var, $rand_step_var) + $sizex;
$size_0y = rand(-$rand_step_var, $rand_step_var) + $sizey;
}else{
$size_0x = $sizex;
$size_0y = $sizey;
}
$y_0 = $size_0y * sin($angle);
$x_0 = $size_0x * cos($angle);
/* Optimizations */
while((
(($x_0 + $x) > $this->width || ($y_0 + $y) > $this->height) ||
(($x_0 + $x) < 0 || ($y_0 + $y) < 0)
)
&& $i < $steps_total){
$angle = $angle + $angle_step;
$sizex = $sizex + $size_stepx;
$sizey = $sizey + $size_stepy;
$x_0 = $size_0x * cos($angle);
$y_0 = $size_0y * sin($angle);
$i++;
}

/* END Optimizations */
$color_s = $color[rand(0,count($color)-1)];
//imagesetpixel($this->image, $x + $x_0, $y + $y_0, $color_s);
imagefilledellipse($this->image, $x + $x_0, $y+$y_0, 2, 2, $color_s);
$angle = $angle + $angle_step;
$sizex = $sizex + $size_stepx;
$sizey = $sizey + $size_stepy;
}

}
function string_it($string, $color){
$temp_string_placement = imagecreatetruecolor($this->width, $this->height);
imageantialias($temp_string_placement, true);
$background = imagecolorallocate($temp_string_placement, 125, 125, 125);
imagefill($temp_string_placement, 0, 0, $background);
$black = imagecolorallocate($temp_string_placement, 0, 0, 0);
$red = imagecolorallocate($temp_string_placement, 255, 255, 255);
$font = imagepsloadfont('./font.pfb');
$box_width = ($this->width / strlen($string))-10;
for($i=0;$i $x = $box_width * $i + 20;
$y = rand(40, $this->height);
if($i%2 == 0){
imagepstext($temp_string_placement, substr($string, $i, 1), $font, 40, $black, $background, $x, $y);
}else{
imagepstext($temp_string_placement, substr($string, $i, 1), $font, 40, $red, $background, $x, $y);
}
}

for($i=0;$i<$this->width;$i++){
for($i2=0;$i2<$this->height;$i2++){
$rgb = ImageColorAt($temp_string_placement, $i, $i2);

if($rgb == 0){
$color_s = $color[rand(0,2)];
imagefilledellipse($this->image, $i, $i2, 3, 3, $color_s);
}elseif($rgb==16777215){
$color_s = $color[rand(3,5)];
imagefilledellipse($this->image, $i, $i2, 3, 3, $color_s);
}

}

}
}

function print_display(){
$this->output($this->image, 'jpg', 100);
}

}


Okay. This one is pretty cool, really... I started out with grand intentions, but ended up with something that works just as well, and is a little quicker. What I was trying to do was create a spiral blur over text that was placed on an image. This would make it difficult for text recognition software to figure out what the text was... I would randomly create a spiral for every different blur, so they couldn't plot it out.

What I did instead was just use the spiral art, as it works without needing to add the additional blur layer... Just for kicks before I get started, with a few small changes to the spiral code, I generated these...


create_swirl_template(200,40,$colors, 0.01, 0.5, 0.2, 0.1, 3, 6);


create_swirl_template(250,250,$colors, 0.2, 0.5, 0.05, 0.04, 6, 5);


create_swirl_template(250,250,$colors, 0.002, 0.5, 0.05, 0.04, 6, 5);

Okay. I'm done showing off today's fun side of the work... We actually had something to do, right? Notice the commented imagepixelset() line? It was changed to imagefilledelipse() to make the shapes a little more clear... The following can be used to produce verification images:


$image = new image_manipulation;
$image->new_image(250,100);
$colors = array($image->get_color(24, 64, 130),
$image->get_color(0, 0, 20),
$image->get_color(0 ,0 ,10));
$image->create_swirl_template(200,40,$colors, 0.03, 0.5, 0.2, 0.1, 3,2);
$colors = array($image->get_color(50, 50, 0),
$image->get_color(50, 50, 50),
$image->get_color(100 ,100 ,100));
$image->create_swirl_template(5,75,$colors, 0.04, 0.5, 0.2, 0.1, 3,2);
$colors = array($image->get_color(0, 64, 130),
$image->get_color(0, 0,0),
$image->get_color(0 ,0 ,255),
$image->get_color(50, 50, 50),
$image->get_color(0, 0,0),
$image->get_color(0 ,0 ,255) );
$image->string_it("R5f2g", $colors);
$image->print_display();


That look exactly like this (changes spiral position, character position randomly when live):



Or you can obviously change colors, and layer things differently. Here's an example where the text is positioned below the spirals, and the text color matches the spirals:


$image = new image_manipulation;
$image->new_image(250,100);
$colors = array($image->get_color(50, 50, 0),
$image->get_color(50, 50, 50),
$image->get_color(100 ,100 ,100),
$image->get_color(24, 64, 130),
$image->get_color(0, 0, 20),
$image->get_color(0 ,0 ,10) );
$image->string_it("R5f2g", $colors);
$colors = array($image->get_color(24, 64, 130),
$image->get_color(0, 0, 20),
$image->get_color(0 ,0 ,10));
$image->create_swirl_template(200,40,$colors, 0.03, 0.5, 0.2, 0.1, 3,2);
$colors = array($image->get_color(50, 50, 0),
$image->get_color(50, 50, 50),
$image->get_color(100 ,100 ,100));
$image->create_swirl_template(5,75,$colors, 0.04, 0.5, 0.2, 0.1, 3,2);

$image->print_display();





With a quick little hack we can make it even more difficult to isolate the text from the background:


function create_swirl_template($x, $y, $color, $angle_step=.05, $start_size=5, $size_stepx=.5, $size_stepy=.5, $revolutions=5, $rand_step_var=0, $line=false){
$x = rand(0, $this->width);
$y = rand(0, $this->height);
$x_old = 0;
$y_old = 0;

$angle = rand(0, 360);
$sizex = $start_size;
$sizey = $start_size;

$steps_total = (360/$angle_step) * $revolutions;
for($i=0;$i<$steps_total;$i++){
if($rand_step_var > 0){
$size_0x = rand(-$rand_step_var, $rand_step_var) + $sizex;
$size_0y = rand(-$rand_step_var, $rand_step_var) + $sizey;
}else{
$size_0x = $sizex;
$size_0y = $sizey;
}
$y_0 = $size_0y * sin($angle);
$x_0 = $size_0x * cos($angle);
/* Optimizations */
while((
(($x_0 + $x) > $this->width || ($y_0 + $y) > $this->height) ||
(($x_0 + $x) < 0 || ($y_0 + $y) < 0)
)
&& $i < $steps_total){
$angle = $angle + $angle_step;
$sizex = $sizex + $size_stepx;
$sizey = $sizey + $size_stepy;
$x_0 = $size_0x * cos($angle);
$y_0 = $size_0y * sin($angle);
$x_old = $x_0;
$y_old = $y_0;
$i++;
}

/* END Optimizations */
$color_s = $color[rand(0,count($color)-1)];
//imagesetpixel($this->image, $x + $x_0, $y + $y_0, $color_s);
if(!$line){
imagefilledellipse($this->image, $x + $x_0, $y+$y_0, 2, 2, $color_s);
}else{
imageline($this->image, ($x + $x_0), ($y + $y_0), ($x + $x_old), ($y + $y_old), $color_s);
imageline($this->image, ($x + $x_0 + 1), ($y + $y_0 + 1), ($x + $x_old + 1), ($y + $y_old + 1), $color_s);
imageline($this->image, ($x + $x_0 - 1), ($y + $y_0 - 1), ($x + $x_old - 1), ($y + $y_old - 1), $color_s);
}

$angle = $angle + $angle_step;
$sizex = $sizex + $size_stepx;
$sizey = $sizey + $size_stepy;
$x_old = $x_0;
$y_old = $y_0;
}

}


Which turns out something like this:



The color array can be programmed for any RGB color values. As characters are printed, they alternate between using indexes 0-2 and indexes 3-5 on the color array for the string_it function. There is also an extra spiral on this image, but it is not truly necessary. Performance isn't bad. I have been getting an average of a single second rendering on my test server, which is quite good for a PHP program... If the calculations were to be done in C/C++, and then the result imported into PHP it might be a bit faster, but that's outside the scope of my discussion.

By using the interlapping lines and different colors, it is very difficult to get a good selection of the text by changing anything in your image editing software, which also indicates it will be very hard for a script to do it. I used a postscript font, but you can adapt this to use ttf very easily.

Saturday, August 27, 2005

 

PHP Image class

Hey everyone. I started to work with some image stuff today, and realized that I should allow members of this site that I'm working on to upload an image that doesn't meet the specs that my software needs. Now, that's an obvious thing that needs to be added to any site that lets it's users play with images, heck, any site that has a member base should allow the user to upload images (forums, community sites, comment sections, etc...). I'm not going to go into the uploading images aspect of PHP, at least today anyway, but I did just write something you might find useful... An image class... The main purpose is to allow a simple resize, but I'm sure you could write some classes that extend the functionality of this one.


/*
* Basic PHP Image class
* Copyright (C) 2005 James Kassemi
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.

* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.

* You can view the LGPL here: http://www.gnu.org/licenses/lgpl.html
*
* Requirements:
*
* PHP with compiled gd library
*
* Description:
*
* Very simple class for dealing with images. Main purpose was for simple resize.
*
* Functions:
*
* set_image(string $path)
* start off by setting the path to the starter image.
*
* image_type()
* returns the type of the image in plain text.
*
* create_image_resource()
* creates a resource image based on the type of the image set using set_image()
*
* resize($width, $height, $unit='px', $dest_x=0, $dest_y=0, $src_x=0, $src_y=0)
* resizes the image to a new image resource, which it returns.
* width => desired width after resize.
* height => desired height after resize.
* unit => Can be set to either px or %, adjusts size accordingly.
* dest_x => the starting x pixel on the resized image...
* dest_y => the starting y pixel on the resized image...
* src_x => the x pixel in which to start grabbing the source image...
* src_y => the y pixel in which to start grabbing the source image...
*
* save($image, $filename, $quality=100, $type='')
* saves an image resource to a file
* image => the image resource to save
* filename => filename to save to.
* quality => for jpegs, adjust quality of file.
* type => specify the type (jpg, png, gif, wbmp)
* if none is specified, will use the type of the image set with set_image
*
* output($image, $type='', $quality='100', $header=true
* outputs an image resources content to the browser
* image => the image resource to output
* type => the image type to output
* quality => for jpegs, adjust quality of output.
* header => true or false... Output the mime type...
*
* Sample usage:
*
* Takes the PHP logo from the php.net site, and resizes it to 200px by 200px
*
*
include ('./class/image.php')
$image = new image();
$image->set_image('http://us2.php.net/images/php.gif');
$new = $image->resize(200, 200);
$image->output($new, 'jpg');
?>

*/

class image {

public $path;

function set_image($path){
$this->path = $path;
}

function image_type(){
$type = getimagesize($this->path);
$type = $type[2];
switch($type){
case 1:
return "gif";
case 2:
return "jpg";
case 3:
return "png";
case 4:
return "swf";
case 5:
return "psd";
case 6:
return "bmp";
case 7:
return "tiff(intel)";
case 8:
return "tiff(motorola)";
case 9:
return "jpc";
case 10:
return "jp2";
case 11:
return "jpx";
case 12:
return "jb2";
case 13:
return "swc";
case 14 :
return "iff";
case 15:
return "wbmp";
case 16:
return "xbm";
default:
return false;
}
}

function create_image_resource(){
/* This will convert the set image to the proper resource, so we can work with it. */
$type = $this->image_type();
switch($type){
case 'gif':
return imagecreatefromgif($this->path);
case 'jpg':
return imagecreatefromjpeg($this->path);
case 'png':
return imagecreatefrompng($this->path);
case 'wbmp':
return imagecreatefromwbmp($this->path);
default:
return false;
}
}

function resize($width, $height, $unit='px', $dest_x=0, $dest_y=0, $src_x=0, $src_y=0){
$image_old = $this->create_image_resource();
$size = getimagesize($this->path);
$old_width = $size[0];
$old_height = $size[1];
switch($unit){
case 'px':
$new_width = $width;
$new_height = $height;
break;
case '%':
$width = $width / 100;
$height = $height / 100;
$new_width = $old_width * $height;
$new_height = $old_height * $height;
break;
default:
return false;
}
$image_new = imagecreatetruecolor($new_width, $new_height);
$success = imagecopyresampled($image_new, $image_old, $dest_x, $dest_y, $src_x, $src_y, $new_width, $new_height,
$old_width, $old_height);
return $image_new;
}

function save($image, $filename, $quality='100', $type=''){
if($type=''){ $type=$this->image_type(); }
switch($type){
case 'gif':
imagegif($image, $filename);
return true;
case 'jpg':
imagejpeg($image, $filename);
return true;
case 'png':
imagepng($image, $filename);
return true;
case 'wbmp':
imagewbmp($image, $filename);
return true;
default:
return false;
}
}

function output($image, $type='', $quality='100', $header=true){
if($type==''){ $type=$this->image_type(); }
switch($type){
case 'gif':
if($header==true)
header('Content-type: image/gif');
imagegif($image);
break;
case 'jpg':
if($header==true)
header('Content-type: image/jpeg');
imagejpeg($image);
break;
case 'png':
if($header==true)
header('Content-type: image/png');
imagepng($image);
break;
case 'wbmp':
if($header==true)
header('Content-type: image/wbmp');
imagewbmp($image);
break;
default:
return false;
}
}

}



?>


Friday, August 26, 2005

 

Martial arts are geeky

I've been struggling with this one for a little over two weeks. I take martial arts. Does that make me a geek? The question was raised after I watched "Napoleon Dynamite," a movie which I don't really understand. How can a film written by an average joe high school student (I don't really know if it was, but there wasn't anything special in it) about a semi-surrealistic high school, an obviously imaginary disfunctional family, and a fully grown idiot be a success in the box office? Never mind. This is America. I'm not surprised.

So I'm laboriously struggling through this film, and along comes the dojo visit. Inside the karate school are twiggy nerds, unsuccessful geeks and scrawny misfits listening to a redneck instructor screaming nonsense. I realize that this film was written by idiots, and would contain scenes that mirror their views on life. Several days passed, and one night I sat down in front of the television once more (I do waste my life away frequently), and a discovery channel show, "Is it Real?" popped up on the guide. I watched it, and along came a dojo scene. This one with a pot-bellied red-necked ball of a man who allegedly mastered the "chi no-touch knockout."

After several demonstrations I took a look at the audience. To my amazement, it was very Napoleon Dynamitish. Dungeons and Dragons, Magic the Gathering and Star Trek are apparently still all the rage. So I burried my head in my hands and cried. I had given up such obsessions years ago... Was I still a geek? I decided to lay it out:










CategoryGeekNormalMe
Style"Got Root" T-Shirt/JeansRegular T-Shirt/JeansDown with SCO T-Shirt/Jeans
HealthNo ExerciseFootballMartial Arts
CarVolkswagonMustangStratus + No Gas
Operating SystemBSDWindowsLinux
BlogYesNoYes
GirlPosterCheerleader/BlondeWallpaper
Coming to ConclusionsGraphsConclusions?Tables/Graphs


So. You add them up. I'm clearly not a geek... But I don't quite match the normal column, either. So what am I? I leave that to you... My non-existent audience...

'Till next time everyone.

Wednesday, August 24, 2005

 

Working with parents and children

Here's a quick little puzzle:

You have a database that contains the following:


id | parent | title | description
1 0 blah blah
2 1 blah subcat Subcategory under the blah title.
3 2 blah subcat subc Subcategory under id 2


This must be fairly common with category listings. The categories can be multi-leveled, a lot like the folder system on your hard drive (eg /, /usr, /usr/local, where /usr/local is a second level directory). The problem comes when you want to know what categories are children of the parent category to an unlimited number of levels.

Since I don't know my SQL that well, I decided to use a simple PHP solution... It's obvious that this needs to be recursive. My worry is that when there are thousands of categories, the processing requirements for sorting through them will be too high. If you can think of something better, please post. Here's what I've got:


function get_all_children($category="0"){
$children = array();
$this->db->query(sprintf("select distinct id from categories where parent='%s'",
mysql_real_escape_string($category)));

while($row = $this->db->fetch()){
$children[] = $row['id'];
}
$temp_array = array();
foreach($children as $child){
$temp_array=$this->get_all_children($child);
}

$children = array_merge($children, $temp_array);
$children = array_unique($children);
array_unshift($children, $category);
return $children;
}


There is a nice explaination here that recommends I don't store the data in this method, and instead suggests the Modified Preorder Tree Traversal method. But that really doesn't help someone who's already got a functional method for the simple parent method, and doesn't feel like modifying thousands of lines of code to get their program working faster. Argh. Wish I'd seen this earlier :)

http://www.sitepoint.com/article/hierarchical-data-database/1

Instead of changing everything right now, I've decided to run a cron job with my update procedure (which I will publish as soon as I'm no longer bound by confidentiality. Soon, I hope, as the project appears to be nearly done.

Take it easy everyone.

 

Adopt good programming practice before it's too late

I've been programming now for as long as I can remember. If you can name the language, I've dabbled with it. My first programs were on my old Packard Bell 500, and written in C. They weren't written well, but I was eight, and I didn't care. So long as the system made a beep or I returned a list of numbers with a for loop, I was happy.

When my neighbor learned that I was using the computer, they donated a Commodore, which I (despite the downgrade), I absolutely loved. I played text game after text game on it, and even attempted making my own. BASIC became my language of choice, as it was simple enough for me to fully understand. I didn't have to worry too much about strange syntax, and could always use the GOTO statements, which were so much easier than writing good code.

My switch to BASIC from C has turned into the biggest mistake I ever made. Instead of becoming proficient with a powerful language, I turned to something that would make quick work of small projects. I gave up true programming for a while, and started working on web pages back in middle school. These days that doesn't seem like much, but this was when the internet was still it's fastest at 14.4 and none of my teachers even realized that it was possible for them to put up their own pages. I remember the shoddy interface of JKLinks, my collection of valuable internet resources, of which I wish I had a copy today. The JKLinks Award was sent out to many sites, none of which accepted the obvious advertising ploy. The site was a failure, as all of mine have been so far.

Javascript was my next structured language, and with it I created a great menu system similar to the Windows start menu, but a year later a technology came out that made the system useless: CSS. Menus similar to what I programmed were (and are) popping up everywhere, and I had no chance of any type of commercial marketing - not that I was thinking of it.

Some friends' parents took a look at what I had done with JKLinks, and decided they'd hire me to make their web pages. I was making fifty bucks here and there fairly regularly, and then another parent approached me. This one in real estate. I spent countless hours on site designs for her, none of which were good enough. In the end I received a check for $25.00 for my effort, and none of the pages were ever used. I gave up.

During high school I explored mIRC and AOL chatroom 'servers'. I ditched mIRC when I was able to more reliably get content by the America Online method. I followed lead and started programming in Visual Basic. Another bad move. Luckily my time spent there didn't last long, and I quickly moved into Java, Delphi, C++ and currently, PHP.

To get to the point though, which I understand you must be dying to hear right now, I'm having a hell of a time getting some of my programming done because of my lack of focus early on in my programming lifetime. When I was working with each of the languages that I'd learned, I was never doing anything too important. Never anything that was to be released and expected to run well. Currently, though, I am working on an important project, the nature of which I cannot yet reveal. To get this project done, and done quickly, I heard I should use PHP with a mySQL database backend. The language was simple, much like C++, and very easy to work with. I started learning immediately, and felt I was doing fairly well.

The problem? NEVER start learning a programming language by programming what you're learning the language for. Let me qualify. NEVER for a program that you need to have running well, and NEVER for a very large program. I'm currently at the 52MB mark in code. And I just came across I huge problem that I need to fix with the code I started writing as I was learning. It's so sloppy and bug-ridden that it will take me weeks to fix it. That's my advice to you today. I know, promising introductory story, weak conclusion. Any of you with any more universal programming advice, feel free to comment here.

Monday, August 22, 2005

 

Acrobat Reader and why I hate Windows

First off, hello there. This is my first entry. And I'm happy to be joining the world of blogs. There are a few things that I've wanted to talk about for a while now, but can't (project confidentiality agreements), and decided I can do a pretty good job of blabbing away with the non-confidential things for now.

Linux is my operating system of choice. I started using it a little over a year ago, and have currently gotten to the point that I can use it for everything I used my old Windows boxes for. Unfortunately I'm in the process of cleaning out my main computer (hp ze4420us laptop), and am using a Windows machine to try to open the service manual. It's a pdf. A very simple pdf.

I placed the file on a USB flash drive before unplugging my laptop, and tried to gain access to that file from this system, running a clean install of Windows 2000. Since there are no pdf readers installed by default, I went over to adobe.com, and clicked "Get Acrobat Reader." The site detected that I was running Windows 2000, and asked me which version I wanted to download. I downloaded the appropriate file, and attempted to install. After 30 minutes (slow machine), the Netopsystems FEAD Optimizer finished "recomposing" some strange data, and I was then told that this machine did not support the version of Reader I had downloaded, and that I would need to update.

An hour later I finished a Windows Update, and tried to run the setup application again. Instead of quickly telling me that everything would be alright, and that the program had been installed, I instead am met again with the Netopsystems FEAD Optimizer, which runs slower than ever.

Now. My experience with pdf's on linux has been quite different. After a default slackware installation, I am able to launch X, and open a pdf file with gv or kpdf, or any of the other wonderful tools that are immediately available. I find it funny that an entire OS+ every tool you would ever need and more fit on just two CDs, but for a functional Windows installation I need to install hundreds of different applications.

Let's now examine the message that I just got on my computer: "This version of Adobe Acrobat will only run on Windows 2000 SP2". That's funny, since I just updated to SP1, and downloaded the SP1 edition of Acrobat. Anyway, let me get yet another adobe download. I'll be right back.

Okay. I just downloaded the proper installer downloading tool. What happened to the good old days when I didn't have to mess around with these downloading tools. I'd much rather just download the file by my own methods. I think my problem with such tools is that they automatically assume I know less than I do. Why allow somebody who doesn't know how to download the proper file from the fastest mirror install something on their computer?

Let's say for a moment that slackware didn't come with a pdf reader. Would I be going through the same things here? No. Here's why. With every slackware installation I have, I always install slapt-get (and use apt-get for debian systems). All I would need to do would be

$ slapt-get --install kpdf
or
$ slapt-get --install gv

And I would immediately have the proper package. If no such package existed, I would only need to download a VERY small (in comparison) file, and set it to compile with a ./configure, make and make install. The process doesn't take nearly as long as this has so far, and I get a software build optimized for my computer's architecture.

I'm back at the Netopsystems FEAD Optimizer. The third time. And I'm pretty much done ranting. I'll be back to bitch about more later :)

Archives

August 2005   September 2005   October 2005   November 2005   December 2005   January 2006   February 2006   March 2006   April 2006   June 2006   July 2006   August 2006   September 2006   October 2006   November 2006  

This page is powered by Blogger. Isn't yours?