Monday, July 30, 2007

Executing background processes from Windows

I needed to execute background processes in a windows environment. This was because I had extensive processing to do on a file after it was uploaded via a web page. Here's how I ended up doing it (courtesy http://www.somacon.com/p395.php):


$WshShell = new COM("WScript.Shell");
$oExec = $WshShell->Run("whatever_command.exe", 0, false);


From the site:
You can start the process using the Run method of the WScript.Shell object, which is built-in to Windows. By varying the second parameter, you can make the window hidden, visible, minimized, etc. By setting the third parameter to false, Run does not wait for the process to finish executing. This code only works on Windows.

There are a few more strategies on achieving this which are outlined on somacon.com, but this is the one I ended up using. So, check out the page on somacon.com for more info if you'd like. I'd also like to express my thanks for the great tip!

Thursday, July 26, 2007

LOGO


OK, I know I'm trying to set up a php blog, but I just ran across something that I remember fondly from my childhood. LOGO! I haven't seen this since first grade on our Apple computers in the computer lab. This was the first "programming language" I learned. Check out this site:

http://www.fragmentarisch.net/svg/drawingboard.php

Official LOGO isn't exactly like this, but this is really close and it runs in your browser!

ODBC Browser


I was working on a project that required gaining access to an ODBC source (mdb file) on a windows box via PHP. I wanted a quick and dirty way to access the data. I did a google search on php odbc browser, but I couldn't find a thing. So, I decided to write my own. This is a very basic browser, but it seems to do what I need it to do. The only thing you should have to change is the DSN name, username and password (if the user & pass are set). This works great for my MDB file and it should work okay w/ other ODBC sources. Enjoy!

<?
/*
* Program Comments:
* This is a basic...very basic ODBC browser written in PHP
*/
session_start();

// odbc connection parameters
$dsn = "dsn_name_here";
$user = ""; // username and password may or may not be needed depending on the database source
$pwd = "";

$max_saved_queries = 15;

// the saved_query session variable isn't set, go ahead and define it as an array
if (!isset($_SESSION['saved_queries']))
{
$_SESSION['saved_queries'] = array("----------");
}


// A query was requested to be executed...
// Save it to history if it's not the duplicate of a previous entry in the query history
// Also, move the currently executing query to the top of the query history list
$query = $_REQUEST['query'];

if (isset($_REQUEST['query']) && isset($_REQUEST['execute_query']) &&amp; $query != "----------" && $query != "")
{
array_unshift($_SESSION['saved_queries'], $query);

for ($i=1; $i<count($_SESSION['saved_queries'])-1; $i++)
{
$q = $_SESSION['saved_queries'][$i];

// we have a query match.
// delete the match because we've already put the query at the top with our array_unshift function above
if (strtolower($q) == strtolower($query))
{
array_splice($_SESSION['saved_queries'], $i, 1);
}
}

if (count($_SESSION['saved_queries']) > $max_saved_queries)
{
array_pop($_SESSION['saved_queries']);
}
}


// connect to the odbc dsn
$dbh = odbc_connect($dsn, $user, $pwd);
?>

<html>
<head>
<style type="text/css">

body { font-family: arial; }
.tbl { font-weight: bold; padding-top:10px; }
.columns { display:none; }
.resultClass0 { background-color:#F5F5F5; padding-left:8px; }
.resultClass1 { background-color:#E0E0E0; padding-left:8px; }
</style>


<script language="javaScript">
var tableArray = new Array();

function showHide()
{
var selectBox = document.getElementById('tables');
var selectedTable = selectBox[selectBox.selectedIndex].value;

document.getElementById('columns').innerHTML = tableArray[selectedTable];
}


function showSavedQuery()
{
var selectBox = document.getElementById('saved_queries');
var query = selectBox[selectBox.selectedIndex].value;

document.getElementById('query').value = query;
}
</script>

</head>
<body>

<b><i><big>ODBC Browser</big></i></b><br><br>


<?
$table_result = odbc_tables($dbh);
$table_name = array();
$table_type = array();

while (odbc_fetch_row($table_result))
{
$tn = odbc_result($table_result,"TABLE_NAME");
$tt = odbc_result($table_result,"TABLE_TYPE");

$table_name[] = $tn;
$table_type[] = $tt;
?>

<script language="javascript">
tableArray['<?=$tn?>'] = "";
<?
$column_result = odbc_columns($dbh, $dsn, "", $tn);
while (odbc_fetch_row($column_result))
{
?>
tableArray['<?=$tn?>'] += '<small><?=odbc_result($column_result, "COLUMN_NAME")?></small><br>';
<?
}
?>
</script>

<?
}
?>


<table border=0>
<tr>
<td valign="top">

<b>Tables</b><br>
<select name="tables" id="tables" size="8" onChange="showHide()">

<br>

<?
$table_result = odbc_tables($dbh);
foreach ($table_name as $key => $tn)
{
?>
<option value="<?=$tn?>"><?=$tn?> - <?=$table_type[$key]?></option>
<?
}
?>

</select>

</td>
<td valign="top" style="padding-left:15px;">

<b>Columns</b>
<div id="columns" style="width:500;height:140;overflow:auto;border:1px;border-style: solid;"></div>

</td>
</tr>
</table>


<hr>


<table border=0>
<tr>
<td>


<form method="post" action="mdb_table_data.php">
<table border=0 cellspacing=0 cellpadding=0>
<tr>
<td>
<b>Execute Query:</b><br>
<textarea name="query" id="query" cols="60" rows="8"><?=$query?></textarea><br>
<input type="submit" name="execute_query" value="Execute">
</td>
</tr>
</table>
</form>


</td>

<td valign="top" style="padding-left:15px;">

<b>Saved Queries:</b><br>

<select name="saved_queries" id="saved_queries" size="8" onChange="showSavedQuery()">

<?
foreach ($_SESSION['saved_queries'] as $saved_query)
{
$short_display = substr($saved_query, 0, 40)
?>
<option value="<?=$saved_query?>"><?=$short_display?></option>
<?
}
?>

</select>

</td>

</tr>

</table>


<hr>


<table border="0" cellspacing="0" cellpadding="0">
<?
// execute the query here
if (isset($_REQUEST['query']) && isset($_REQUEST['execute_query']) &&amp; $query != "----------" && $query != "")
{
$res = odbc_prepare($dbh, $query);
odbc_execute($res);

$total_num_of_rows = 0;
$row_num = 0;
$max_rows = 20;


while ($row = odbc_fetch_array($res))
{
$row_num++;
$total_num_of_rows++;
$class_num = $row_num % 2;

if ($row_num == 1)
{
?>
<tr>
<?
foreach ($row as $col_name => $value)
{
?>
<th valign="top" style="padding-top:10px;padding-left:8px;"><?=$col_name?></th>
<?
}
?>
</tr>
<?
}

if ($row_num >= $max_rows)
{
$row_num = 0;
}


?>
<tr>
<?
foreach ($row as $col_name => $value)
{
?>
<td valign="top" class="resultClass<?=$class_num?>">
<?=$value?>
</td>
<?
}
?>
</tr>
<?

}


?>
</table>

<?=$total_num_of_rows?> row(s) matched your query
<?
}
?>
</table>


</body>
</html>

Monday, July 23, 2007

Preventing form spam

I was having problems with form spam on many of the web sites that I've created. I did some research and came across a web site which helps ALOT with preventing form spam. In fact, I haven't had any form spam from the sites that I've enabled this service on. The site is at http://www.projecthoneypot.org.

This site offers the following services
  • Blacklisting lookup service (via dns query) which allows you to look up an IP address and get spam threat scores back from their database. The API is available at http://www.projecthoneypot.org/httpbl_api.php.
  • Set up your own honey pot for each site. I think this is fine since spammers will visit your site anyway. So, you might as well divert them from the contact page (where your form or e-mail addresses are located) and give them a fake e-mail address that will be logged by project honey pot. This page has an FAQ about installing a honey pot on your site.
  • There's more, but the ones above are the ones I use the most.

Thursday, July 12, 2007

PHP function to make a file size human-readable

Problem: You're working in PHP and you have a file size in bytes. You'd like to make it easier to read.

Answer: This quick function I created. It accepts the byte count and returns a human-readable file size string:
// make file size human-readable
function byte_size($bytes)
{
switch(1)
{
case ($bytes < pow(2, 10)): // bytes
$size = number_format($bytes) . ' B';
break;
case ($bytes < pow(2, 20)):
$size = number_format($bytes / pow(2, 10)) . ' kB'; // kilobytes
break;
case ($bytes < pow(2, 30)):
$size = number_format($bytes / pow(2, 20)) . ' MB'; // megabytes
break;
case ($bytes < pow(2,40)):
$size = number_format($bytes / pow(2,30)) . ' GB'; // gigabytes
break;
case ($bytes < pow(2,50)):
$size = number_format($bytes / pow(2,40)) . ' TB'; // terabytes
break;
case ($bytes < pow(2,60)):
$size = number_format($byes / pow(2,50)) . ' PB'; // pedabytes
break;
default: // a famous man once said, "a PC will never need more than 640 kB of RAM"
$size = number_format($bytes) . ' B';
}

return $size;
}

Tuesday, July 10, 2007

PHP Recursive Function to create a directory

Apparently, in PHP versions less than 5.0, you can't recursively create a directory. Here's a little function I wrote to allow this...works on *nix systems:


<?
// set the number of recursions, so we don't get out of control w/ infinite recursions
// like when we don't have file system access to create directories
// or when we try to create a directory w/ incorrect characters in it...like an asterisk (for example)
$num_recursions = 0;

// recursive function to create a directory
function mkdir_recursive($dir)
{
global $num_recursions;
$num_recursions++;

echo "attempting to create $dir\n";
$dir_res = @mkdir($dir);

if ($num_recursions > 100)
{
echo "Cannot create $dir...num_recursions in mkdir_recursive = $num_recursions\n";
exit;
}

if ($dir_res === false)
{
$next_attempt_dir = substr($dir, 0, strrpos(substr($dir, 0, -1), '/'));
echo "dir creation failed...Now attempting to create $next_attempt_dir\n";
mkdir_recursive($next_attempt_dir);

echo "trying again to create $dir\n";
$dir_res = mkdir($dir);
}
else // dir creation successful. Reset the global recursion counter.
{
$num_recursions = 0;
}

}
?>