lime icon

Phosphorus and Lime

A Developer's Broadsheet

This blog has been deprecated. Please visit my new blog at klenwell.com/press.
PHP: micro timer
A simple little routine for timing scripts:

$tx1 = microtime();

$tx2 = microtime();

$tx_in_s = number_format(((substr($tx2,0,9)) + (substr($tx2,-10)) - (substr($tx1,0,9)) - (substr($tx1,-10))),4);


keywords: PHP, timer, microtime, script timer
PHP: trigger_notice()
A little function I put together -- I find it handy for debugging. It would be even handier if it had a shorter name:

/* Fx trigger_notice()
******************************/
function trigger_notice($notice='default', $headline=FALSE, $add_style=TRUE)
{
// *** DATA

# style settings
$color1 = '#336699';
$bg_color = '#fdfefe';
$text_color = $color1;
$border = "2px solid $color1";
$font = "'Courier New',courier,monospace";
$padding = '.4em';
$margin = '.2em .4em';
$border_width = '2px 0';

# define inline style for output
$style = " style=\"background-color:$bg_color; color:$text_color; "
. "font-family:$font; padding:$padding; margin:$margin; border:$border; "
. "border-width:$border_width; clear:both; text-align:left;\"";

# output
$_DIV['head'] = '';
$_DIV['notice'] = '';
$_DIV['foot'] = '';

# return
$html = '';


// *** MANIPULATE

# backtrace vars
$_TRACE = debug_backtrace();
$_file = $_TRACE[0]['file'];
$_line = $_TRACE[0]['line'];

# build headline
if ( strlen($headline) )
{
$_DIV['head'] = strtoupper($headline);
}
else
{
$_DIV['head'] = 'NOTICE';
}

# build footer string
$_info_string = "File: $_file <br />Line: $_line";
$_DIV['foot'] = '<div style="margin:.2em 0; color:green; font-family:monospace; '
. 'font-size:10px; font-weight:bold;">' . $_info_string . '</div>';

# build notice
if ( $notice == 'default' )
{
$_fx_trace = '';
foreach ( $_TRACE as $_level )
{
$_fx_trace .= "fx call: {$_level['function']} on line {$_level['line']} of file {$_level['file']}\n";
}
$_DIV['notice'] = $_fx_trace;
$text_color = '#ccc';
}
# array notice
elseif ( is_array($notice) )
{
$_DIV['notice'] = print_r($notice, TRUE);
}
else
{
$_DIV['notice'] = $notice;
}

# style
if ( $add_style )
{
# define inline style for output
$style = " style=\"background-color:$bg_color; color:$text_color; "
. "font-family:$font; padding:$padding; margin:$margin; border:$border; "
. "border-width:$border_width; clear:both; text-align:left;\"";
}

# build html
$html = <<<NOTICE

<!-- NOTICE -->
<div class="trigger_notice"{$style}>
<h4 style="margin:.4em 0 0">{$_DIV['head']}</h4>
{$_DIV['foot']}
<pre>{$_DIV['notice']}</pre>
</div>
<!-- end NOTICE -->

NOTICE;

// *** RETURN

# echo
echo $html;

# return
return TRUE;

} /* end Fx */
/*****************************/


You can just drop it in your code anywhere you want to see the current state of a variable or array.

Output:

NOTICE

File: c:\path\to\your_file.php
Line: 84
fx call: trigger_notice on line 84 of file c:\path\to\your_file.php 
SQL: left join
An example using PHP variables:

SELECT * FROM $T_primary
LEFT JOIN $T_second ON $T_primary.ID = $T_second.primary_ID
LEFT JOIN $T_third ON $T_primary.ID = $T_third.primary_ID
WHERE $T_primary.ID = $some_value


Not sure if this is the optimal query, but works at something like getting user data spread across tables.
CSS: property values
A helpful page listing possible values from main properties in CSS settings:

CSS values (westciv.com)

This is especially useful for figuring out display changes between screen and print media types:

CSS values: length (westciv.com)

keywords: css, length
CSS: Print Page
Some preliminary research on creating a print page button for a web page. Some helpful links:

CSS Design: Going to Print (A List Apart)

Cross-Browser Print Button (Dynamic Drive)

Doesn't look too complicated -- a javascript button with a print-media stylesheet should do it.

Here's the stylesheet tags:

<style type="text/css" media="print">
</style>


keywords: css, js, print
PHP: Form Wizard Load Stack
// form wizard load stack

# script file (e.g. 'signup.php')

# script file -> include driver file (in stage directory)

# script file controller (set $WIZ['id'], preload config)

# call cx_wizard($WIZ['id'])

# cx_wizard frontend -> sets stage number

# cx_wizard -> include stage file (in stage directory)

# stage
# _review
# _dump
# _backend -> _backend_stack

# cx_wizard backend -> redirect(SELF)


keywords: PHP, AMVC, architecture
PHP: Fuzzy Search Functions
Moving into the hairy territory of fuzzy searching after the person I was supposed to be working with let me down. Three basic functions:

function get_leven_score($string, $compare_string)
{
// *** DATA

# internal
$_leven = 0;

# return
$score = 1000;


// *** MANIPULATE

# get levenshtein distance
$_leven = levenshtein($string, $compare_string);

# convert to percentage score relative to string
$score = ($_leven/strlen($string))*1000;


// *** RETURN

return $score;

} # end Fx


function get_leven_soundex($string, $compare_string)
{
// *** DATA

# internal
$_leven = 0;

# return
$score = 1000;


// *** MANIPULATE

# get soundex values
$_snd1 = soundex($string);
$_snd2 = soundex($compare_string);

# get levenshtein distance
$_leven = levenshtein($_snd1, $_snd2);

# convert to percentage score relative to string
$score = ($_leven/strlen($_snd1))*1000;


// *** RETURN

return $score;

} # end Fx


function get_leven_metaphone($string, $compare_string)
{
// *** DATA

# internal
$_leven = 0;

# return
$score = 1000;


// *** MANIPULATE

# get soundex values
$_snd1 = metaphone($string);
$_snd2 = metaphone($compare_string);

# get levenshtein distance
$_leven = levenshtein($_snd1, $_snd2);

# convert to percentage score relative to string
$score = ($_leven/strlen($_snd1))*1000;


// *** RETURN

return $score;

} # end Fx


The lower the score, the better the match, with 0 being exact. So you can set a limit for matching terms -- a common recommendation seems to be around 500 and lower.

Source: php.net

Keywords: PHP, SEO
PHP: PhpMyBorder
A nifty little class someone created that programmatically uses CSS to create rounded corners for an HTML div.

source: http://phpmyborder.hotserv.dk/index.php

keywords: php, css, html, borders
PHP: poetry
A couple sites of interest that I came across today:

http://www.languageisavirus.com/

http://machinepoetics.com/

keywords: poetry, text, generator
PHP: sound, text, and fuzzy searching
Trying to develop a good rhyming algorithm, which has led me to soundex, metaphone, etc.

Found the following comment on searching interesting:

The soundex 'different letter in front' problem can be solved by using levenshtein() on the soundex codes. in my application, which is searching a database of album names for entries that match a particular user provided string, i do the following:

1. Search the database for the exact name
2. Search the database for entries where the name occurs anyway as a string
3. Search the database for entries where any of the words in the name (if the user has typed in more than one word) is present, except for little words (and, the, of etc)
4. Then, if all this fails, I go to plan b:

- calculate the levenshtein distance (levenshtein()) between the user search term and each of the entries in the database as a percentage of the length of the user search term entered

- calculate the levenshtein distance between the metphone codes of the user search term entered and each field in the database as a percentage of the length of the metaphone code of the user search term entered

- calculate the levenshtein distance between the soundex codes of the user search term entered and each field in the database as a percentage of the length of the soundex code of the original user search term entered

if any of these percentages is less than 50 (means that two soundex codes with different first letters will be accepted!!) then the entry is accepted as a possible match.


source: soundex (php.net)

See also: fuzzy searching

keywords: PHP, soundex, phonetics, text, fuzzy, search
PHP: Caching
Another worthwhile devshed tutorial on cacheing -- something I should check out for the wiki I've set up at work:

Caching Results in PHP

As soon as I have time...

keywords: cache, PHP, wiki
PHP: PHP and Javascript
A Dev Shed tutorial that I found interesting:

PHP and JavaScript: Pooling Your Resources

I haven't applied any of this yet, but could see where it might come in handy..
PHP: backend stack
A routine I'm developing for processing long forms:

// ** 1. DECLARATIONS

// DOCUMENT SHORTHAND
$_iPATH['root'] = realpath($_SERVER['DOCUMENT_ROOT']);
$_iPATH['super'] = dirname($_iPATH['root']);

// ** 2. CHECK FLAG TRIGGER

// ** 3. INSERT/UPDATE DB

// TABLE n : name

# prep data
# package data
# insert data
# verify

// ** 4. SEND MAIL NOTICES

// MAIL NOTICE
if ( $_FLAG['data_inserted'] )
{
# DEBUG
#trigger_notice('data inserted -> trying to send mail');

# set to: address
# set confirm URL
# set message
# send
}

// ** 5. GENERATE FEEDBACK

// ** 6. RESET DATA

// ** 7. REDIRECT

 
CSS: Window-Mac Font Families
note: further updates to this list are available on the klenwell.net wiki. for more information on the use of font-families, see this post on my moshi blog.

Font equivalents for the two systems, in order of my preferences:

Sans-Serif Fonts
Arial, Helvetica, sans-serif
"Trebuchet MS", Helvetica, sans-serif
Verdana, Geneva, sans-serif
"Century Gothic", Futura, Arial, Verdana, sans-serif;
"Lucida Sans Unicode", "Lucida Grande", sans-serif
Tahoma, Geneva, sans-serif
Impact, Charcoal, sans-serif
"Arial Black", Gadget, sans-serif
"MS Sans Serif", Geneva, sans-serif


Serif Fonts
"Palatino Linotype", "Book Antiqua", Palatino, serif
Garamond, Georgia, serif
"MS Serif", "New York", serif
"Times New Roman", Times, serif


Monospace
"Lucida Console", Monaco, monospace
"Courier New", Courier, monospace


Cursive
"Comic Sans MS", cursive
CSS: font settings
I usually set font style with separate declaration -- mostly because I can't remember the order for setting all attributes in a single declaration. This is the attribute order:

font-style   font-variant   font-weight   font-size/line-height   font-family

Example:

// setting all attributes
font: italic small-caps bold 16px/1.2em arial;

// typical setting
font: normal normal normal 1em arial,sans-serif;

// size and setting
font: 12px/1.4em garamond,serif;


source: W3 Schools
PHP: cron job
Some complications running scripts from a cron job -- environmental variables aren't always what you'd expect.

This thread helped: totalchoicehosting.com forum
PHP: filtering words
Looking for a simple way to isolate words in a string. With apostrophes and commas and various other punctuation getting in the way, not as easy as you'd think. This works pretty well if not absolutely perfectly. An example:

# create WORDS array from string
$WORDS = explode(' ', $string);

# tidy up words
foreach ( $WORDS as $_word )
{
$WORD[] = preg_replace("/[^A-Za-z0-9'\-]*/", '', $_word);
}


keywords: regex, preg_replace, words, non-word characters
PHP: parent directory
Question: what's the best method for dynamically obtaining a parent directory, e.g. the parent directory to the document root?

Answer: quite simple

// PARENT DIR: dirname(dirname($path_to_file))

# parent to current file
dirname(dirname(__FILE__))

# parent to document root (outside web tree)
dirname($_SERVER['DOCUMENT_ROOT'])


source: php.net
Google: Google Analytics and Google Base
Two new services this week from Google and each earth-shaking, I suspect, in ways most people will not realize for some time to come:

Google Analytics

Google Base

My first Google Base post:

http://base.google.com/base/items?oid=6628413765027457963

Bye bye, Craig's List.
OSS: OSSwin
Open source windows projects indexed here:

OSSwin [sourceforce]

A couple years ago, I was looking for an user-friendly open source audio editing program. I think I finally found it today:

Audacity
PHP: array_search()
Problem: given the array value where the array is associative, find the key.

I always blank on this. Very simple:

mixed array_search ( mixed needle, array haystack [, bool strict] )


For example:

$key = array_search($value, $ARRAY);

 
PHP: function obscure_string()
Randomly obscures a string -- to be effective, must be used in a session environment where it can be re-displayed. Otherwise, someone could just hit reload until each of the letters was randomly revealed. NOT state-of-the-art security.

function obscure_string($string, $freq=4)
{
// *** DATA

# internal
$_strlen = strlen($string);
$_i = 0;
$_NEW = array();

# return
$new_string = '';


// *** MANIPULATE

# traverse string
while ( $_i < $_strlen )
{
# randomly reveal char
if ( mt_rand(1,$freq) % $freq == 0 )
{
$_NEW[$_i] = $string[$_i];
}
# obscure
else
{
$_NEW[$_i] = '*';
}

# increment index
$_i++;
}

# implode new string
$new_string = implode($_NEW);


// *** RETURN

return $new_string;
}

 
CSS: line wrap
Code to wrap long lines in styled blocks -- used in my code-styling classes:

white-space: pre-wrap; /* CSS2.1 compliant */
white-space: -moz-pre-wrap; /* Mozilla-based browsers */
white-space: -o-pre-wrap; /* Opera 7+ */

 
Design: Fab Labs
This is sort of mind-blowing.

NPR Science Friday Piece: The Making of a Personal Lab
MIT Center for Bits and Atoms Website: FabLabs
MySQL: Generic Create Table
A template for creating a MyISAM table in MySQL:

DROP TABLE IF EXISTS `GENERIC`;
CREATE TABLE IF NOT EXISTS `GENERIC`
(
`ID` int(11) NOT NULL auto_increment,
`varchar` varchar(40) NOT NULL default '',
`int` int(11) NOT NULL default '0',
`tiny_int` tinyint(4) NOT NULL default '0',
`text` text,
`datetime` datetime NOT NULL default '0000-00-00 00:00:00',
`timestamp` int(11) NOT NULL default '0',
PRIMARY KEY (`ID`)
)
TYPE=MyISAM
AUTO_INCREMENT=1 ;


see also: MySQL Reference Manual
PHP: New System Driver
Got rid of a lot of junk DNA in my code. Simpler, though you might not know if by looking at it.

<?php

/*
AMVC Project Driver

File: project_driver.inc.php
Version: 0.6.3
Last Update: Nov 2005
Author: Tom Atwell (klenwell@gmail.com)

NOTES:

for load sequence, see bottom

*/


// 1. Project Settings

$_PROJECT['name'] = 'Test';
$_PROJECT['dirname'] = $_PROJECT['name'];
$_PROJECT['live_host'] = 'www.yoururlhere.com';
$_PROJECT['alpha_host'] = 'www.yoururlhere.com';
$_PROJECT['webmaster'] = 'youremail@address.com';


// 2. Start-Up
require_once('_engine/startup.inc.php');

# 2.1. register project name and driver path (must wait until SESSION is opened in startup)
$_SESSION['active_project']['name'] = $_PROJECT['name'];
$_SESSION['active_project']['driver'] = __FILE__; # must be in this file

# 2.2. silent notice
echo "<!-- {$_SESSION['active_project']['name']} buffer open / session started -->\n";


// 3. Driver Stack (support libraries)

$_AMVC['req_pack'] = array
(
'security' => 'security_pack/_driver.inc.php',
'file' => 'file_pack/_driver.inc.php',
'form' => 'form_pack/_driver.inc.php',
'html' => 'html_pack/_driver.inc.php',
'database' => 'dba_pack/_driver.inc.php',
'uas' => 'uas_pack/_driver.inc.php',
'mail' => 'mail_pack/_driver.inc.php',
'graphics' => 'graphics_pack/_driver.inc.php',
'diagnostic' => 'dx_pack/_driver.inc.php'
);


// 4. Load AMVC Hard Config Data and Version
require_once('_engine/version_config.inc.php');


// 5. Auto-Override Configuration
require_once('_engine/auto_override.inc.php');

# NOTE: before loading this driver, assign config file path to : $OVERRIDE['AMVC']['session_config']


/* 6. LOCAL OVERRIDE CONFIGURATION
*******************************/

// LOCAL settings
if ( $_version == 'local' )
{
# dba override
$CONFIG['DB']['deploy'] = 'quick';

# dba quick deploy
$qdb = 'amvc_test';
#$qdbu = '';
#$qdbp = '';
#$qdbs = 'localhost';

# path corrections
$_URL['AGE'] = 'http://' . $_SERVER['HTTP_HOST'] . '/AMVC/__ROOT_AGE/';
#$_URL['img_bin'] = $_URL['root'] . 'AMVC/__ROOT_img_bin/';
#$_URL['css_bin'] = $_URL['root'] . 'AMVC/__ROOT_css_bin/';
#$_PATH['log_bin'] = $_PATH['AMVC'] . '__ROOT_log_bin' . $_slash;
}


// ALPHA settings
elseif ( $_version == 'alpha' )
{
# DBA override

# path corrections
}


// BETA settings
elseif ( $_version == 'beta' )
{
}


// LIVE settings
elseif ( $_version == 'live' )
{
# echo live visitor
$_live_ip = $_SERVER['REMOTE_ADDR'];
$_live_timestap = gmdate('Y-m-d H:i:s', $_AMVC['META']['session_start']);
echo "<!-- $_live_ip @ $_live_timestap GMT -->\n";
}
/******************************/


// 7. Define Site Constants

# version
define('VERSION', $_version);

# root paths
define('ROOT', $_PATH['root']);
define('DOC_ROOT', $_PATH['root']);
define('PROJECT_ROOT', $_PATH['project_root']);
define('AMVC_ROOT', $_PATH['AMVC']);
define('SUPER_ROOT', $_PATH['super']);

# root urls
define('URL_ROOT', $_URL['root']);
define('AGE_URL', $_URL['AGE']);

# bin directories
define('IMG_BIN', $_URL['img_bin']);
define('CSS_BIN', $_URL['css_bin']);
define('LOG_BIN', $_PATH['log_bin']);

# shorthand syntax
define('EOL', $_eol);
define('INC', $_inc);
define('SLASH', $_slash);

# project
define('PROJECT_TITLE', $_PROJECT['name']);
define('WEBMASTER', $webmaster);

# status codes
define('OK', 1);
define('EDIT', 0);
define('BAD', -1);
define('HACK', -9);
define('EVIL', -666);


// 8. Load Support Library

# configured in : _engine/driver_stack.inc.php

# cycle through drivers
foreach ( $_AMVC['req_pack'] as $_req_file )
{
require_once($_req_file);
}

# load flag
$_AMVC['META']['driver_loaded'] = TRUE;

# silent notice
echo "<!-- AMVC project driver loaded at {$_AMVC['META']['session_start']} A.U. (Anno Unixis) -->\n";



/*
AMVC Project Driver Notes

LOAD SEQUENCE:

1. *Project Settings
2. Start-Up
3. AMVC Meta Settings
4. Load AMVC Hard Config File and Set Version Paths
5. Auto Override
6. *Override Config
7. Define Constants
8. Load Support Library

* Editable section -- i.e., this data will vary between projects. The rest
should not.


at present, all rights reserved

*/
?>

 
Design: Icons
Revamping my SDK tonight and the issue of favicons came up. I was looking for a public domain default favicon setting and decided to check out the state of California website. Sure enough, it has a lovely favicon on the state seal. Only problem was I couldn't locate it. Searched the source code, scanned the headers -- no luck. Anyway, one thing led to another and ended up on this site, which was kinda fun:

MpP Favicon Gallery

Included a link to this site, which prompted me to record this entry:

300 Images

Ha! What do you know? Another link, peerbot, help me catch the butterfly I was after, after all:

CA icon

This is also a good default icon:

firefox icon

<link rel="shortcut icon" href="http://firefox.no/favicon.ico" type="image/x-icon" />

 
sysop: cron job
Just noticed my hosting service offers cron jobs (that's lewd.) (Actually, it can be worse than lewd. In the right hands, it can be quite an annoyance!)

Anyway, always wanted to set one of these up. Wasn't much documentation, but with a little Googling, I was able to figure out what to do. This site was helpful:

Using cron to automate tasks (4webhelp.net)

With the interface provided by my host, this is all the syntax I needed to run my file 'cron_test.php':

/usr/bin/php -q /usr/home/USERNAME/cron_test.php

 
PHP: cheat sheet wallpaper
I was in the process of putting together a PHP cheat sheet when I discovered this nicely organized little primer. (For comparison tables, see this.)

I took it and created the following desktop background:



With the date formatting and fx argument order, I refer to it rather frequently. You can download it yourself here:

PHP Alma-Tadema Wallpaper
Spam: sploggerz gone wild
This is what happens to old blogs that don't watch their comments -- infested:

http://antibogon.org/archives/000020.html
JS: focus first field
Need a simple javascript function to focus a form on the first (text) field. Here's how Google does it:

function sf(){document.f.q.focus();}


Then, in the body tag:

<body bgcolor=#ffffff text=#000000 link=#0000cc vlink=#551a8b
alink=#ff0000 onLoad=sf() topmargin=3 marginheight=3>


But their form is simplicity itself. With my wizard, it's not possible to refer to a document object by name as Google does.

A number of different function already out there to choose from. I settled on a hybrid of two different functions.

This one required the form be passed by name as an argument. It then cycles through the fields of the form and applies focus to the first field that is not hidden, disabled, or read-only:

function f_setfocus( aForm )
{
if( aForm.elements[0]!=null) {
var i;
var max = aForm.length;
for( i = 0; i < max; i++ ) {
if( aForm.elements[ i ].type != "hidden" &&
!aForm.elements[ i ].disabled &&
!aForm.elements[ i ].readOnly ) {
aForm.elements[ i ].focus();
break;
}
}
}
}


The problem is the argument. I want it to be argument-free and simply take the first qualified form field on the page -- even if there are multiple forms.

This one finds the first editable text, textarea, or s* (submit?) field in a form on the page:

function placeFocus() {
if (document.forms.length > 0) {
var field = document.forms[0];
for (i = 0; i < field.length; i++) {
if ((field.elements[i].type == "text") || (field.elements[i].type == "textarea") || (field.elements[i].type.toString().charAt(0) == "s")) {
document.forms[0].elements[i].focus();
break;
}
}
}
}


But it assumes that it will be the first form on the page (and thus would miss if the first form did not have an editable field.)

So I adopted what I thought were the advantages of each function and rolled my own:

<script type="text/javascript">
<!--
function select_first_field()
{
// *** DATA

var focus_is_set = false;
var num_forms = document.forms.length;
var i, j;

// *** MANIPULATE

// sanity check
if ( num_forms < 1 )
{
return;
}

// cycle forms
for ( i = 0; i < num_forms; i++ )
{
var this_form = document.forms[i];

// cycle fields
for ( j = 0; j < this_form.length; j++ )
{
// skip hidden, disabled, read-only fields

// verify text, textfield, s*
if ( (this_form.elements[j].type == "text" ) || ( this_form.elements[j].type == "textarea" ) || ( this_form.elements[j].type.toString().charAt(0) == "s" ) )
{
// skip disabled, read-only
if ( !this_form.elements[j].disabled && !this_form.elements[j].readOnly )
{
focus_is_set = true;
document.forms[i].elements[j].select();
break;
}
}
}

// check focus flag
if ( focus_is_set == true )
{
break;
}
}

// *** RETURN

return;

} // end fx
// -->
</script>


Viola! Finds the first text field that is not disabled, etc., in a form and selects it. Not extensively tested, but worked on the first page I threw it on.

A more sophisticated function that account for slow-loading pages can be found here:

Man in Blue's 78-line javascript focus function


(Fresh off the presses!) However, I don't anticipate any of my pages being that slow.
PHP: Spam Filters
I'm in the (free open source) market for a spam filter for PHP -- and here's the catch -- not tailored to Word Press. There is not any pressing need at this time for it -- but I anticipate needing it shortly for a couple projects I'm working on.

I've found a couple scripts that look promising:

Bad Behavior
- download
- installation guide

I've only had a chance to browse the code, but from the write-up this sounds like just what I'm looking for and easily ported

Spam Karma
- download
- wiki

This is tailored to Word Press but looks like it could be portable

At a glance, it appears as though they take slightly different tacts with BB comparing header requests against a blacklist of bad agents and SK2 comparing submitted content against a blacklist of terms. But I'd have to look more closely at the code to really understand their respective logics.
Gallery: LKGR
Finally put together a label for lastgoogle:



Still need to add a remote form for the blog.