lime icon

Phosphorus and Lime

A Developer's Broadsheet

This blog has been deprecated. Please visit my new blog at klenwell.com/press.
PHP: filepath_to_url()
A filepath_to_url function that should work, though I've only tested it on my local server. Uses my own function to normalize slashes, but not too hard to do within the function itself:

/* fx filepath_to_url
*************************************************/
function filepath_to_url($filepath)
{
// *** DATA

# internal
$_slash = '/';
$_url_rel = '';

# paths
$PATH = array();
$PATH['file'] = normalize_path($filepath, $_slash);
$PATH['www'] = 'http://' . $_SERVER['HTTP_HOST'] . $_slash;

# directory arrays
$_DIRS = array();
$_DIRS['filepath'] = explode($_slash, $PATH['file']);
$_DIRS['doc_root'] = explode($_slash, normalize_path($_SERVER['DOCUMENT_ROOT'],$_slash));
$_DIRS['diff'] = '';

# return
$url = '';

# DEBUG
#trigger_notice($filepath);
#trigger_notice($_DIRS);



// *** MANIPULATE

# path is url
if ( preg_match('%^(http)s?://%i', $PATH['file']) )
{
return $PATH['file'];
}

# compute path differences
$_DIRS['diff'] = array_values(array_diff($_DIRS['filepath'], $_DIRS['doc_root']));

# DEBUG
#trigger_notice($_DIRS);

# shift empty cells
if ( empty($_DIRS['diff'][0]) )
{
array_shift($_DIRS['diff']);
}

# get URL relative path
$_url_rel = implode('/', $_DIRS['diff']);

# build URL
$url = $PATH['www'] . $_url_rel;


// *** RETURN

return $url;

} # end Fx
/*______________________________________________*/


Successful on my local WAMP build and on my remote LAMP (actually, I think it is BSD) host.
PHP: get_absolute_url() [NOTE: flawed]
Note: this does not work for reasons my brain is too addled to explain right now. See this function:

Slow day at work, so I just rewrote my function get_path_url so that it now safely returns paths that are already absolute urls:

/* get_absolute_url
*************************************************/
function get_absolute_url($path = 'default')
{
// *** DATA

// internal vars
$_slash = '/';
$_url_root = "http://".$_SERVER['HTTP_HOST'];
$_host = '';
$_protocol = 'http';
$_port = 80;
$_realpath = '';
$_root = '';
$_url_tail = '';

// return value
$_abs_url = '';


// *** MANIPULATE

// set default path
if ( $path == 'default' )
{
$path = $_SERVER['SCRIPT_FILENAME'];
}

// path is url
if ( preg_match('%^(http)s?://%i', $path) )
{
return $path;
}

// get url root

# get host
if ( !empty($_SERVER['HTTP_HOST']) )
{
list($_host) = explode(':', $_SERVER['HTTP_HOST']);
}
elseif (!empty($_SERVER['SERVER_NAME']))
{
list($_host) = explode(':', $_SERVER['SERVER_NAME']);
}

# protocol
if ( isset($_SERVER['HTTPS']) && !strcasecmp($_SERVER['HTTPS'], 'on') )
{
$_protocol = 'https';
}

# port
if ( isset($_SERVER['SERVER_PORT']) )
{
$_port = $_SERVER['SERVER_PORT'];
}

if ( ($_protocol == 'http' && $_port == 80) || ($_protocol == 'https' && $_port == 443) )
{
unset($_port);
}

# build url root
$_url_root = $_protocol .'://'. $_host . (isset($_port) ? ':'. $_port : '');


// get realpaths

# path
$_realpath = realpath($path);
trigger_notice($_realpath);

# root
$_root = realpath($_SERVER['DOCUMENT_ROOT']) . $_slash;

# add slash back to directories (realpath() trims last slash)
if ( is_dir($path) )
{
$_realpath = $_realpath . $_slash;
}

// normalize paths
$_realpath = trim(str_replace("\\", $_slash, $_realpath));
$_root = trim(str_replace("\\", $_slash, $_root));

// is root in path? (will return 0, so use identical operator (===, !==)
if ( strpos($_realpath, $_root) !== FALSE )
{
# subtract root from path
$_url_tail = str_replace( $_root, '', $_realpath );
$_abs_url = $_url_root . $_slash . $_url_tail;
}
// relative path
elseif ( strlen($_realpath) )
{
$_abs_url = $_url_root . $_slash . $_realpath;
}
else
{
trigger_error("path [$path] url could not be determined", E_USER_WARNING);
$_abs_url = FALSE;
}

// *** RETURN

return $_abs_url;

} # end Fx
/*______________________________________________*/


Note: I was having issues using realpath() -- something to do with realpath() on shared Windows servers. It did work with this realpath alternative in its place, however.

Credit goes out to the open scripts out there I consulted in creating this one. Curiously, the PEAR HTTP:absoluteURI() did not successfully do this for me. Perhaps I wasn't using it as intended. But it did help me figure out how to build the url head.

keywords: php, url, path, absolute
JS: field focus revisited
A simple javascript function for setting focus to field of your choice. It requires knowing form name and field name:

<script type="text/javascript">
function focus_field(form_name, field_name)
{
document.form_name.field_name.focus();
document.form_name.field_name.selectionStart=0;
document.form_name.field_name.selectionEnd=0;
}
</script>


Then in body tag:

<body onload="focus_field(form_name, field_name)">


reference: houseoffusion.com
PHP: pphlogger login problem
Not sure how many people out there use pphlogger -- I've been pretty satisfied with it. (In fact, I think I'm using it on this site.) However, today, all of the sudden, I couldn't log in. This seems to have solved the problem:

replace HTTP_*_VARS arrays with super globals ($_SERVER, $_POST, etc.)

1 login.php - line 37 - change $HTTP_POST_VARS to $_POST

2 login.php - line 49/50 - change $HTTP_SESSION_VARS to $_SESSION

3 defines.lib.php (directory "libraries") - line 94/95 - change $HTTP_SERVER_VARS to $_SERVER

4 htmlMimeMail.php (directory "modules") - line 131-134 - change $GLOBALS["HTTP_SERVER_VARS"] to $_SERVER


source: http://forum.phpee.com/

keywords: pphlogger, troubleshooting, php
Google Discovers Last Google
Received the following email yesterday from Google regarding http://lastgoogle.com/:

Hello,

While reviewing your account, we noticed that you are currently displaying Google ads on a site that uses a Google trademark in the domain name. As this is a violation of our policies, we've disabled ad serving to http://lastgoogle.com/.

Your AdSense account remains active. However, we recommend that publishers review the important guidelines found here: https://www.google.com/support/adsense/bin/answer.py?answer=23921&ctx=en.

Please also note that publishers are not permitted to use Google Brand Features, which include Google trademarks, logos, web pages, screen shots, or other distinctive features on sites without prior consent from Google.

Sincerely,

The Google AdSense Team


Can't display Google ads on a site that uses Google in the domain name -- I guess that rules out Adwords on bitemegoogle.com. But where does it leave google.com? Sounds like a fatal flaw in the whole business model.

My email in response:

Thank you for your letter regarding http://lastgoogle.com/.

I don't believe that I am using "Google trademarks, logos, web pages, screen shots" per se. Obviously, my site parodies the Google look. (I'm counting on somebody at Google has a sense of humor.) But I've worked up the code, imagery, and stylesheets myself and it is all done primarily in a spirit of fun. The Google Adwords help complete the theme and also offer the hope of some potential (though I regret to say that there is none yet) return on my investment.

But given the fact of your letter, may I have your written consent to use whatever features currently in place that might be construed as Google brand features? Should I include some kind of "not affiliated with Google" disclaimer (though I think it would be pretty obvious to anyone skilled enough to operate a browser.)

Also, may I apply to have Google Adwords reinstated on my site?

And may I have the name and email of an individual whom I might personally contact with questions regarding my account?

Thank you,

Tom Atwell


At present, no response, auto-generated or otherwise.

(And why am I still required to do the CAPTCHA thing for my posts to this blog? It's making me a bit paranoid.)
PHP: random numbers
Been requiring a lot of random numbers lately. Some simple routines I find useful for games of chance:

// virtual coin toss
$coinflip = mt_rand(1,2);


// actual virtual coin toss
if ( mt_rand(1,2) % 2 == 0 )
{
$flip = 'heads';
}
else
{
$flip = 'tails';
}


// roll the bones
$roll = mt_rand(1,6);

 
Linux: Taking the Leap
I'm so ready. It's a New Year's Resolution -- one I'm actually getting out in front of. Still want to give Puppy Linux a spin, but Ubuntu seems to be the consensus recommendation for newbs. I'm not a proficient bittorrent user and hate downloading big files and burning ISOs and all, so I ordered free CDs off the website.

Then today, while browsing I came across this Google video:

Ubuntu Linux / Windows Dual Boot Instructional Video

So once my CDs arrive, I'm so there.
PHP: sort array by one field in array
There's probably a PHP function that does this, but I haven't been able to find it, so I rolled my own. First procedurally:

# ingredients
# $ARRAY : array or arrays to be sorted
# $sortby_index : index/column to be sorted on
# $key_index : equivalent to primary key column in SQL array

# get ordering array
foreach ( $ARRAY as $_DATA )
{
$_key = $_DATA[$key_index];
$ORDERING[$_key] = $_DATA[$sortby_index];
}

# sort ordering array
asort($ORDERING);

# DEBUG
#trigger_notice($ORDERING);

# map ARRAY back to ordering array
foreach ( $ORDERING as $_key => $_sort_col_val )
{
# get index for ARRAY where ARRAY[][$key_index] == $_key
foreach ($ARRAY as $_i => $_DATA)
{
if ( $_key == $_DATA[$key_index] )
{
$SORTED[] = $ARRAY[$_i];
continue;
}
}
}


Now as a function

function sort_array_of_arrays($ARRAY, $sortby_index, $key_index)
{
// *** NOTES
/*
requires array of associative arrays -- not checked within array
*/

// *** DATA

# order array
$ORDERING = array();

# return
$SORTED = array();

# internal
$_DATA = array();
$_key = '';
$_sort_col_val = '';
$_i = 0;


// *** MANIPULATE

# get ordering array
foreach ( $ARRAY as $_DATA )
{
$_key = $_DATA[$key_index];
$ORDERING[$_key] = $_DATA[$sortby_index];
}

# sort ordering array
asort($ORDERING);

# DEBUG
#trigger_notice($ORDERING);

# map ARRAY back to ordering array
foreach ( $ORDERING as $_key => $_sort_col_val )
{
# get index for ARRAY where ARRAY[][$key_index] == $_key
foreach ($ARRAY as $_i => $_DATA)
{
if ( $_key == $_DATA[$key_index] )
{
$SORTED[] = $ARRAY[$_i];
continue;
}
}
}

// *** RETURN

return $SORTED;

} # end Fx


Assumes asort will sort matters for you. Function will not work if you have to do some calculations on the sort index before sorting. But easily adapted.

keywords: PHP, array, sort
CSS: Stylesheet Constants using PHP
Probably fancier than I need, but I like the idea of defining constants for commonly used color settings. Example:

// source: http://perhapstga.blogspot.com/2001/01/favourite-colours.html

define('CLR_PARCHMENT', '#f3f1eb');
define('CLR_COFFEE_STAIN', '#b5ad95');
define('CLR_PARCHMENT_BLUE', '#6F7DA2');


Then I would just use something like this for internal or inline stylesheets:

.style1
{
color: <?php echo CLR_PARCHMENT; ?>;
}


But, this is a much more versatile method for using external style sheets.

keywords: css, php, colors
Grace Murray Hopper
I remember seeing this woman on the old Letterman Show years ago. (Actually, I think it was a Letterman clip show.) Anyway, though I always forget her name, she's been a (rare) inspiration to me. After a few minutes googling permutations of 'navy pioneer computers females letterman', I tracked this down:

Grace Hopper Murray (Wikipedia)
PHP: MVC Demo
A framework I've come up for relatively fast, structured deploys of small dynamic websites or page suites. It can be used freely, but is intended more as a model or inspiration for others:

<?php

// start page time
$tx1 = microtime();

/* FILE INFO

MVC Demo

File: index.php
Last Update: Dec 2005
Author: Tom Atwell (klenwell@gmail.com)

NOTES:

This model makes use of a couple other files and function I've created:

FILE: build_navbar.inc.php
FX: rollover_menubar()

WARNING : without content files (meant to hold html) in a content directory on the
same directory level as this page, page will generate a warning.


/*______________________________________________*/

/* 1. LOCAL DRIVER ******************************/

// DOCUMENT SHORTHAND
define('iEOL', "\n");
define('iSEP', DIRECTORY_SEPARATOR);

// LITE VERSIONING
$_iSET['local_dir'] = 'DIRNAME';
$_iSET['beta_server_name'] = 'www.YOURBETAHOST.com';
$_iSET['live_server_name'] = 'www.YOURLIVEHOST.com';

// VERSION TREE - set document root path ($_iPATH['root'])
# local or beta
if ( $_SERVER['SERVER_NAME'] == 'localhost' || $_SERVER['SERVER_NAME'] == $_iSET['beta_server_name'] )
{
$_iPATH['root'] = $_SERVER['DOCUMENT_ROOT'] . iSEP . $_iSET['local_dir'] . iSEP;
}
# live
elseif ( $_SERVER['SERVER_NAME'] == $_iSET['live_server_name'] )
{
$_iPATH['root'] = $_SERVER['DOCUMENT_ROOT'] .iSEP;
}
# catch
else
{
die('Invalid version -- server environment not clear. Check LITE VERSIONING settings');
}

// PATHS
$_iPATH['self'] = $_SERVER['PHP_SELF'];
$_iPATH['abs_self'] = __FILE__;
$_iPATH['super'] = dirname($_iPATH['root']) . iSEP;
$_iPATH['content_dir'] = $_iPATH['root'] . 'content' . iSEP;

// INCLUDE LIST
#require_once('project_driver.inc.php');
#require_once($_iPATH['root'] . '_engine/build_navbar.inc.php');
#require_once($_iPATH['root'] . '_engine/form_package.inc.php');
#require_once($_iPATH['root'] . '_engine/mail_package.inc.php');

/*______________________________________________*/


/* 2. MODEL (Data) ******************************/

// PUBLIC VARIABLES (configurable)

# HEADER
$page_title = 'TITLE_ON_PAGE';
$head_title = "HEAD_TITLE";
#$css = $_iPATH['root'] . 'css_bin/FILENAME.css';

# HTML
$_HTML['menubar'] = '';


// PRIVATE VARIABLES

# internal
$_serve = 'home';

// HEAD

# document settings
$_charset = 'ISO-8859-1';
$_favicon = 'http://firefox.no/favicon.ico';
$_title = $_PROJECT['name'];
$_keywords = 'Allied Portals and Engines,PHP,MySQL,internet,web,application,progressive,design';
$_description = 'This page was developed by Allied Portals and Engines. For more information, visit www.alliedportalsandengines.com';
$_css = 'http://localhost/AMVC/graphics_pack/css_bin/amvc_basic/_basic.css';

# HEAD settings
$_HEAD['doctype'] = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"' . "\n" . '"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">';
$_HEAD['open_tag'] = "<html lang=\"en\">\n<head>";
$_HEAD['content_type'] = '<meta http-equiv="Content-Type" content="text/html; charset=' . $_charset . '" />';
$_HEAD['title'] = '<title>' . $head_title . '</title>';
$_HEAD['keywords'] = '<meta name="Keywords" content="' . $_keywords . '" />';
$_HEAD['description'] = '<meta name="Description" content="' . $_description . '" />';
$_HEAD['fav_icon'] = '<link rel="shortcut icon" href="' . $_favicon . '" type="image/x-icon" />';
$_HEAD['css'] = '<link href="' . $_css . '" type="text/css" rel="stylesheet" />';
$_HEAD['close_tag'] = '</head>';


// INCLUDE ARRAY

$_CONTENT_FILES = array
(
# GET ref -> file name
'home' => 'home',
'how to help' => 'help',
'contact us' => 'contact'
);

$_MENU = array
(
'home' => $_iPATH['self'] . '?serve=home',
'how to help' => $_iPATH['self'] . '?serve=help',
'contact us' => $_iPATH['self'] . '?serve=contact'
);

/*______________________________________________*/


/* 3. CONTROLLER ********************************/

// *** GET HANDLER

# empty or invalid GET
if ( !$_GET['serve'] || !in_array($_GET['serve'], $_CONTENT_FILES) )
{
$_serve = 'home';
}
# valid GET
else
{
$_serve = $_GET['show'];
}

# add path
$_iPATH['content_file'] = $_iPATH['content_dir'] . $_serve . '.inc.php';

# get navbar label
$_nav_label = array_search($_iPATH['self'] . "?serve=$_serve", $_MENU);

# build navbar
#$_HTML['menubar'] = rollover_menubar($_MENU, $_nav_label, 'menubar');


/*______________________________________________*/


/* 4. VIEWER ************************************/

echo $_HEAD['doctype'] . iEOL;
echo $_HEAD['open_tag'] . iEOL;
echo $_HEAD['content_type'] . iEOL;
echo $_HEAD['keywords'] . iEOL;
echo $_HEAD['description'] . iEOL;
echo $_HEAD['title'] . iEOL;
echo $_HEAD['fav_icon'] . iEOL;
echo $_HEAD['css'] . iEOL;

?>

<!-- Local Style Sheet -->
<style type="text/css">
<!--
body
{
background:#666;
font:1em Palatino Linotype, Book Antiqua, Palatino, serif;
}
#masthead
{
padding:20px 25px 10px;
border-bottom:1px solid #ccc;
}
#page
{
width:96%;
margin:0 auto;
border:8px solid #ccc;
border-width:0 8px;
background:white;
padding:1% 1% 0;
}
#footer
{
text-align:center;
font:11px/1.4em Verdana, Geneva, sans-serif;
border-top:1px solid #ccc;
padding:1em;
}

a { color:orange; }
a:hover { color:lime; }

#masthead h1
{
margin:0;
font-size:2.4em;
}
#masthead h4
{
margin:0 0 8px;
position:relative; top:-10px;
}

#content_table
{
width:100%;
}
#content_table td
{
vertical-align:top;
}
#content_left
{
text-align:right;
border-right:thin solid #ccc;
padding:1em 1em 1em 0;
width:22%;
}
#content_left
{
}
td#content_right
{
padding:1em;
}

#menubar
{
width:100%;
text-align:center;
}
#menubar a
{
color:black;
font:1.1em/2em Lucida Sans Unicode, Lucida Grande, sans-serif;
}
#menubar a:hover, a#current
{
color:orange;
text-decoration:none;
}
.rollover_menubar
{
width: 100%;
}
.rollover_menubar ul
{
margin-left: 0;
padding-left: 0;
list-style-type: none;
}

#home
{
font-size:1.2em;
margin:1em .5em;
text-align:justify;
}

#help h2
{
font-family: Lucida Sans Unicode, Lucida Grande, sans-serif;
margin:0 0 8px;
}
#help h4
{
font-family:arial, sans-serif;
margin:0 0 4px;
}
#moreinfo
{
margin-top:15px; padding-top:8px;
border-top:1px solid #667041;
}

.entry
{
margin:0 0 16px;
padding:10px;
background:#f7f8f3;
border-bottom:1px solid #667041;
}
.entry h4
{
font-family:Trebuchet MS, Helvetica, sans-serif;
margin:0 0 6px;
}

.contacts
{
font-size:1em;
margin:2px 0 12px;
}
.contacts h4
{
font-size:1.1em;
font-family:Trebuchet MS, Helvetica, sans-serif;
margin:0;
}
.contacts h5
{
font-size:.9em;
font-family:arial, sans-serif;
margin:-2px 0 0;
}

#contact_form_panel
{
width:40%;
float:right;
margin:0px 10px 10px 10px;
padding:5px 10px;
text-align:left;
background:#f7f8f3;
border:1px solid #667041;
font:.85em/1.5em arial,sans-serif;
}
#contact_form_panel h3
{
margin:4px 0 0;
}
#contact_form_panel #meta_prompt
{
font-size:.9em;
line-height:1.2em;
margin:2px 0 6px;
color:#985950;
}
#contact_form_panel form
{
margin:0;
}
#contact_form_panel .form_row
{
margin:4px 0;
}
#contact_form_panel textarea
{
width:100%;
}
#moreinfo
{
clear:both;
}

-->
</style>

<?php echo $_HEAD['close_tag'] . iEOL; ?>

<!-- *** END DOCUMENT HEAD *** -->


<body>

<!-- PAGE DIV -->
<div id="page">

<!-- MASTHEAD -->
<div id="masthead">
<h1><?php echo $page_title; ?></h1>
<h4>subtitle</h4>
</div>

<!-- CONTENT -->
<div id="content">

<table id="content_table"><tr>

<!-- NAVBAR -->
<td id="content_left">
<?php echo $_HTML['menubar']; ?>
</td>

<!-- INSERT -->
<td id="content_right">
<?php include_once($_iPATH['content_file']); ?>
</td>

</tr></table>

</div>
<!-- end CONTENT div -->

<!-- FOOTER -->
<?php
// calculate page load time
$tx2 = microtime();
$tx_in_s = number_format(((substr($tx2,0,9)) + (substr($tx2,-10)) - (substr($tx1,0,9)) - (substr($tx1,-10))),4);
?>

<div id="footer">
last update : <?php echo date("F j, Y", filemtime(__FILE__)); ?><br />
page loaded in <?php echo $tx_in_s; ?> s
</div>

</div> <!-- end PAGE div-->

<?php

/*__end VIEWER__________________________________*/



/* 5. DIAGNOSTICS *******************************/

// SCRIPT TIMER
# stage_timer('end page');

// SESSION DUMP
# session_dump();

/*______________________________________________*/

?>

<!-- Close HTML -->
</body>
</html>

<?php

/* 6. POSTSCRIPTS *******************************/

// Flush All
while (ob_get_level() > 0)
{
ob_end_flush();
}
flush();
echo '<!-- Buffer Dumped at ' . date("m/d/Y G:i:s") . ' -->';

// Pseudo-Daemon
#log_session();

/*______________________________________________*/

?>


keywords: PHP, template, MVC, framework

P.S. Why the hell is Blogger requiring me to input the word verification? That is, how is this site being confused with a splog site?
PHP: matrix walk
As for a proximity search where values are laid out on a 2-dimensional grid:

$steps = ceil(( abs($VAL1[0]-$VAL2[0]) + abs($VAL1[1]-$VAL2[1]) ) / 2)


keywords: PHP, search, fuzzy, grid, walk
PHP: proximity loop
What do I mean by that? Say you want to figure out the proximity of months where Jan = 1 and Dec = 12. Can't just subtract the values. So need to do something like this:

$diff = abs($month1 - $month2) > 6 ? 12 - abs($month1 - $month2) : abs($month1 - $month2);


keywords: month, cycle, difference, proximity
Banned on Blogger
I was just banned on Blogger for the first time. What's funny is first I got blacklisted as spam -- which didn't entirely surprise me. It is spam of a sort. Not your crass commercial spam, necessarily -- more of your Monty Python-type spam.

Anyway, I got a message from Blogger offering me a chance to appeal. Fair enough. So I appealed and, lo, a couple days later, much to my pleasant surprise, I was taken off the spam list. But then less than three hours later I got the following message:

We'd like to inform you that we've received a complaint that your blog (imaginarycensus.blogspot.com) contains confidential information. Please note that our Terms of Service prohibit posting confidential items on your blog. Accordingly, we have had to remove the content in question.

Please refer to our Terms of Service for more details:
http://www.blogger.com/terms.g

Thank you for your understanding.

Sincerely,
Blogger Support


Now I could accept being banned as spam. But Blogger's going to try to tell me it's against their terms of service to post confidential information? Ha! And, besides, how can you ban imaginary information as being confidential? This is worse than the Chinese government!

At any rate, it's no great loss to the culture. And an interesting insight into Blogger's censorship practices (which I mostly endorse.) Besides, I took a snapshot of the site after it was flagged the first time. Here it was as last seen on blogspot (well, without the big goofy label):

Imaginary Census
HTML: Special Characters
The little wingdings and doodles that most html natively supports and I'm always forgetting:

•   ⇒   &#8226;   &bull;

some sources:

bigbaer.com

wdvl.internet.com

webmonkey
PHP: New Page Template
See notes in file

<?php

/* FILE INFO

Allied Portals MVC PHP Template

File: __MVC_template_ind.inc.php
Last Update: Dec 2005
Author: Tom Atwell (klenwell@gmail.com)

NOTES:

This page models the processing and style template for web page developed
in PHP independently of an established framework.

________________________________________________*/


/* 1. LOCAL DRIVER ******************************/

// SCRIPT TIMER

$_tx1 = microtime();

// DOCUMENT SHORTHAND

# syntax
define('iEOL', "\n");

# path
$_iPATH['file'] = realpath(__FILE__);
$_iPATH['script'] = realpath($_SERVER['SCRIPT_FILENAME']);
$_iPATH['self'] = realpath($_SERVER['PHP_SELF']);
$_iPATH['root'] = realpath($_SERVER['DOCUMENT_ROOT']);
$_iPATH['super'] = dirname($_iPATH['root']);

# meta
$_iMETA['uri'] = $_SERVER['REQUEST_URI'];
$_iMETA['computer'] = $_ENV['COMPUTERNAME'];

// AMVC DRIVER

# AMVC Timer
#require_once($_iPATH['super'] . '/AMVC/_tx.inc.php');
#stage_timer('start timer');

# Include Stack
#require_once('project_driver.inc.php');

# UAS Turnkey
#uas_lock_page();

/*______________________________________________*/



/* 2. MODEL (Data) ******************************/

// PUBLIC VARIABLES

# Global
#global $MASTER;

# Initialize
$_SET = array();

# Document Head
$_SET['doc_title'] = 'TOOTH View Template';
$_SET['page_title'] = $_SET['doc_title'];
$_SET['keywords'] = 'PHP,Firefox,Open Source';
$_SET['description'] = 'AMVC Framework Page';
$_SET['charset'] = 'ISO-8859-1';
$_SET['css_path'] = '';
$_SET['js_path'] = '';
$_SET['icon_path'] = 'http://firefox.no/favicon.ico';

# Labels
$_LABEL['rights'] = 'some rights reserved, &#169;' . date('Y');
$_LABEL['firefox'] = '<a href="http://www.spreadfirefox.com/?q=affiliates&amp;id=151890&amp;t=85"><img border="0" alt="Get Firefox!" title="Get Firefox!" src="http://sfx-images.mozilla.org/affiliates/Buttons/80x15/firefox_80x15.png"/></a>';


// PRIVATE VARIABLES

# Internal

# Head Tags
$_HEAD['doctype'] = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"' . "\n" . '"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">';
$_HEAD['open_tag'] = "<html lang=\"en\">\n<head>";
$_HEAD['title'] = '<title>' . $_SET['doc_title'] . '</title>';
$_HEAD['keywords'] = '<meta name="Keywords" content="' . $_SET['keywords'] . '" />';
$_HEAD['description'] = '<meta name="Description" content="' . $_SET['description'] . '" />';
$_HEAD['charset'] = '<meta http-equiv="Content-Type" content="text/html; charset=' . $_SET['charset'] . '" />';
$_HEAD['fav_icon'] = '<link rel="shortcut icon" href="' . $_SET['icon_path'] . '" type="image/x-icon" />';
#$_HEAD['css'] = '<link href="' . $_SET['css_path'] . '" type="text/css" rel="stylesheet">';
#$_HEAD['js'] = '<script type="text/javascript" src="' . $_SET['js_path'] . '"></script>';

/*______________________________________________*/



/* 3. CONTROLLER ********************************/


/*______________________________________________*/



/* 4. VIEWER ************************************/

echo $_HEAD['doctype'] . iEOL;
echo $_HEAD['open_tag'] . iEOL;
echo $_HEAD['charset'] . iEOL;
echo $_HEAD['keywords'] . iEOL;
echo $_HEAD['description'] . iEOL;
echo $_HEAD['title'] . iEOL;
echo $_HEAD['fav_icon'] . iEOL;
echo $_HEAD['css'] . iEOL;
echo $_HEAD['js'] . iEOL;

?>

<!-- Local Style Sheet -->
<style type="text/css">
<!--
body
{
font-family:Lucida Sans Unicode, Lucida Grande, sans-serif;
margin:0; padding:0;
}
#page
{
width:750px;
margin:0 auto;
}
#masthead
{
margin-top:10px;
padding:10px;
}
#trunk
{
}
.trunk_stent
{
height:200px;
float:right;
width:1px;
}
.minheight_clear
{
clear:both;
height:1px;
overflow:hidden;
}
#footer
{
font:11px/1.4em Verdana, Geneva, sans-serif;
text-align:center;
}

-->
</style>

<?php echo $_HEAD['close_tag'] . iEOL; ?>

<!-- *** END DOCUMENT HEAD *** -->


<body>

<!-- PAGE -->
<div id="page">

<!-- MASTHEAD -->
<div id="masthead">
<h1><?php echo $_SET['page_title'] ?></h1>
</div>
<!-- end MASTHEAD -->

<!-- TRUNK -->
<div id="trunk">
<div class="trunk_stent"></div>

<div class="minheight_clear"></div>
</div>
<!-- end TRUNK -->

<!-- FOOTER -->
<div id="footer">
<?php echo $_LABEL['rights']; ?>
<br />
<?php echo $_LABEL['firefox']; ?>
</div>
<!-- end FOOTER -->

</div>
<!-- end PAGE -->

<?php

/*__end VIEWER__________________________________*/



/* 5. DIAGNOSTICS *******************************/

// SCRIPT TIMER
# stage_timer('end page');

// SESSION DUMP
# amvc_snapdot();

/*______________________________________________*/

?>

<!-- Close HTML -->
</body>
</html>

<?php

/* 6. POSTSCRIPTS *******************************/

// Flush
while (ob_get_level() > 0)
{
ob_end_flush();
}
flush();
echo "\n<!-- Buffer Dumped at " . date('r') . " -->\n";

// Pseudo-Daemon

# timer
$_tx2 = microtime();
$_tx3 = number_format(((substr($_tx2,0,9)) + (substr($_tx2,-10)) - (substr($_tx1,0,9)) - (substr($_tx1,-10))),4);
echo "\n<!-- generated in $_tx3 s -->";

/*______________________________________________*/

?>


Keywords: PHP, HTML, CSS, AMVC, template
PHP: Server API
Recommended reading:

PHP Server API Differences (SitePoint)

Predefined Variables (php.net)

keywords: $_SERVER, DOCUMENT_ROOT, PHP_SELF, root
HTML: filler text
That old war horse: lorum ipsum

When I need some filler:
PHP: input filters
A procedural approach to the problem.

An excellent object-oriented approach can be found here: cyberai.com (I used it as a reference.)

<?php

/* FILE INFO

Form Package

File: form_package.inc.php
Last Update: Dec 2005
Author: Tom Atwell (klenwell@gmail.com)

FUNCTIONS:


NOTES:

/*______________________________________________*/


// *** GLOBAL SETTINGS

// bad tag attributes
$THIS_FORM['bad_atts'] = 'src\s*=\s*java|action|background|codebase|dynsrc|lowsrc|'.
'onAbort|onActivate|onAfterPrint|onAfterUpdate|onBeforeActivate|'.
'onBeforeCopy|onBeforeCut|onBeforeDeactivate|onBeforeEditFocus|'.
'onBeforePaste|onBeforePrint|onBeforeUnload|onBlur|onBounce|'.
'onCellChange|onChange|onClick|onContextMenu|onControlSelect|onCopy|'.
'onCut|onDataAvailible|onDataSetChanged|onDataSetComplete|onDblClick|'.
'onDeactivate|onDrag|onDragEnd|onDragLeave|onDragEnter|onDragOver|'.
'onDragDrop|onDrop|onError|onErrorUpdate|onExit|onFilterChange|'.
'onFinish|onFocus|onFocusIn|onFocusOut|onHelp|onKeyDown|onKeyPress|'.
'onKeyUp|onLayoutComplete|onLoad|onLoseCapture|onMouseDown|'.
'onMouseEnter|onMouseLeave|onMouseMove|onMouseOut|onMouseOver|'.
'onMouseUp|onMouseWheel|onMove|onMoveEnd|onMoveStart|onPaste|'.
'onProgress|onPropertyChange|onReadyStateChange|onReset|onResize|'.
'onResizeEnd|onResizeStart|onRowEnter|onRowExit|onRowDelete|'.
'onRowInserted|onScroll|onSelect|onSelectionChange|onSelectStart|'.
'onStart|onStop|onSubmit|onUnload';


/* fx validate_textarea
*************************************************/
function validate_textarea($text, $required=TRUE, $max_words=250, $min_words=0, $allowed_tags=FALSE)
{
// *** DATA

# internal
$_prompt = '';
$_word_num = 0;
$_word_label = 'word';

# return
$is_valid = 0;
$prompt = '';
$text_out = $text;

$REPORT = array();


// *** MANIPULATE

# required
if ( $required && empty($text) )
{
$is_valid = 0;
$prompt = 'Please fill in box';
$REPORT = array( 'is_valid' => $is_valid, 'prompt' => $prompt, 'text_out' => '' );
return $REPORT;
}

# sanitize
$text_out = sanitize_string($text, $allowed_tags);

# get prompt verbage

# get word num
$_word_num = str_word_count(strip_tags($text_out));

# get word label
if ( $_word_num > 1 )
{
$_word_label = 'words';
}

# get word descrip
$_word_descrip = "$_word_num $_word_label";


# minimum length
if ( $_word_num < $min_words )
{
$is_valid = 0;
$prompt = "Too short. Your submission must be at least $min_words $_word_descrip long.";
$REPORT = array( 'is_valid' => $is_valid, 'prompt' => $prompt, 'text_out' => $text_out );
return $REPORT;
}

# maximum length
if ( $_word_num > $max_words )
{
$is_valid = 0;
$prompt = "Too long. Your submission must be no more than $max_words $_word_descrip long.";
$REPORT = array( 'is_valid' => $is_valid, 'prompt' => $prompt, 'text_out' => $text_out );
return $REPORT;
}

# passed
$is_valid = 1;
$prompt = 'validated';

# build REPORT
$REPORT = array( 'is_valid' => $is_valid, 'prompt' => $prompt, 'text_out' => $text_out );


// *** RETURN

return $REPORT;

} # end Fx
/*______________________________________________*/



/* fx sanitize_string
*************************************************/
function sanitize_string($string, $allowed_tags=FALSE) {

// *** DATA

# default allowed tags
$good_tags = '<a><blockquote><br><br /><b><div><em><h1><h2><h3><h4><h5><h6><i>'
. '<img><li><ol><p><pre><span><strong><table><tr><td><th><u><ul>';

# regex
$_regex = '/<(.*?)>/ie';

# return
$clean_string = '';


// *** MANIPULATE

# default allowed tags
if ( empty($allowed_tags) )
{
$allowed_tags = $good_tags;
}

# magic quotes
if ( get_magic_quotes_gpc() )
{
$string = stripslashes($string);
}

# strip tags
$string = strip_tags($string, $allowed_tags);

# sanitize string
$clean_string = preg_replace($_regex, "'<'.strip_attributes('\\1').'>'", $string);


// *** RETURN

return $clean_string;

} // end Fx
/*______________________________________________*/



/* fx strip_attributes
*************************************************/
function strip_attributes($string)
{
// *** DATA

# globals
global $THIS_FORM;

# regex
$_regex = '/(' . $THIS_FORM['bad_atts'] . ')/ie';

# internal
$_replace = 'xxx' . substr(md5(uniqid()),-3) . '_';

# return
$stripped_string = '';


// *** MANIPULATE

# strip unwanted tag markup
$stripped_string = preg_replace($_regex, $_replace, $string);


// *** RETURN

return $stripped_string;

} # end Fx
/*______________________________________________*/

?>


I'm going to try to post it to Googlebase when I have a chance and will continue refining it.

The following script can be used to test it:

// TEST
$wicked_string = 'I like <div good="blah" onContextMenu=blah>php</div> and <span style="color:red;">certain tags like &lt;span&gt; <b>&lt;b&gt;</b></span> but not <br> XSS <img src=javascript:alert(\'bad!\')>';
$wicked_string_esc = htmlspecialchars($wicked_string);

echo "wicked_string:<br /> $wicked_string <br /><br /><br />";
echo "wicked_string_esc:<br /> $wicked_string_esc <br /><br /><br />";
$REPORT = validate_textarea($wicked_string);
print_r($REPORT);
$cleaned = $REPORT['text_out'];
$cleaned_esc = htmlspecialchars($cleaned);
echo "<br /><br /><br />cleaned:<br /> $cleaned <br /><br /><br />";
echo "cleaned_esc:<br /> $cleaned_esc";


Test Example:

wicked_string:
I like
php
and certain tags like <span> <b> but not
XSS


wicked_string_esc:
I like <div good="blah" onContextMenu=blah>php</div> and <span style="color:red;">certain tags like &lt;span&gt; <b>&lt;b&gt;</b></span> but not <br> XSS <img src=javascript:alert('bad!')>


Array ( [is_valid] => 1 [prompt] => validated [text_out] => I like
php
and certain tags like <span> <b> but not
XSS )


cleaned:
I like
php
and certain tags like <span> <b> but not
XSS


cleaned_esc:
I like <div good=\"blah\" xxx916_=blah>php</div> and <span style=\"color:red;\">certain tags like &lt;span&gt; <b>&lt;b&gt;</b></span> but not <br> XSS <img xxx6b3_script:alert('bad!')>


keywords: PHP, MySQL, XSS, form, sanitize, security
DBA: address data
A couple useful links I stumbled across today for putting together an address database:

Zipbase (cfdynamics.com)

List of ZIP Codes in the United States (wikipedia)

keywords: database, data, MySQL, zip
HTML: Form Field Focus
How to preset a form field and have it change when clicked on:

<input onfocus="this.value='';" type="text" name="textfield" value="enter text here">


Example:



Just learned this. Simple.

keywords: html, css, form, input, textfield, focus, onfocus