Class – Config

<?php	
	
	/*
	Configuration file. This should be added to all PHP scripts to set up commonly used includes, functions, objects, variables and so on.
	*/
	
	$iReqTime 	= $_SERVER['REQUEST_TIME_FLOAT'];
	$cDocroot 	= NULL; //Document root.	
	$oDB		= NULL;	//Database class object.
	$oErr		= NULL;	//Error class object.
	$oMail		= NULL;	//E-Mail handler class object.
	$oSes		= NULL;	//Session handler class object.
	$oUtl		= NULL;	//Utility class object.
	$oFrm		= NULL;	//Forms class object.
		
	/* Get needed includes. */
	require_once("access.php");		//Account based access.
	require_once("constants.php");	//Global constants.
	require_once("database.php");	//Database handler.
	require_once("forms.php");		//Forms handler.
	require_once("error.php");		//Error handler.
	require_once("mail.php");		//Mail handler.
	require_once("sessions.php");	//Session handler.
	require_once("tables.php");		//Table handler.
	require_once("utility.php");	//Utility functions.	
		
	/* Initialize class objects */
	$oUtl	= new class_utility();														//Utility functions.
	$oMail	= new class_mail();															//E-Mail handler.
	$oErr 	= new class_error(array("Mail" => $oMail, "Utl" => $oUtl));					//Error handler.
	$oDB	= new class_db(array("Utl" => $oUtl, "Err" => $oErr));						//Database handler.
	$oSes	= new class_sessions(array("DB" => $oDB));									//Session handler.	
	$oAcc	= new class_access(array("DB" => $oDB, "Ses" => $oSes, "Utl" => $oUtl));	//Account based access.
	$oTbl 	= new class_tables(array("Utl"=>$oUtl));									//Tables handler.
	$oFrm 	= new class_forms(array("DB"=>$oDB));										//Forms handler.
		
	$cDocroot = $oUtl->utl_get_server_value('DOCUMENT_ROOT')."/";
	
	/* Replace default session handler. */
	session_set_save_handler($oSes, true);
	
	/* If session not started, initialize. */
	if(session_status()==PHP_SESSION_NONE)
	{					
		session_start();
	}
?>

Source License

Introduction

This is the license agreement for my source code and other distributions (don’t worry, you’re allowed to use it in your own products, commercial or otherwise).

Note: If you need a non-attribution license for any of my code (for a fee), please see the Using without attribution section below.

The license text is further down this page, and you should only download and use the source code if you agree to the terms in that text. For convenience, though, I’ve put together a human-readable (as opposed to lawyer-readable) non-authoritative interpretation of the license which will hopefully answer any questions you have. Basically, the license says that:

  1. You may use the code in your own products.
  2. You may modify the code as you wish, and use the modified code in your products.
  3. You may redistribute the original, unmodified code, but you have to include or link the full license text below.
  4. You may redistribute the modified code as you wish (without the full license text below).
  5. In all cases, you must include a credit mentioning Damon Caskey as the original author of the source.
  6. I am not liable for anything you do with the code, no matter what. So be sensible.
  7. You can’t use my name or other marks to promote your products based on the code.
  8. If you agree to all of that, go ahead and download the source. Otherwise, don’t.

Compatibility

This license is really just a version of the new BSD license, and should be compatible with that license. If you’d like special permission to use any of my code under another license (like BSD, GPL, etc.), just contact me – I’ll be happy to help.

Use Without Attribution

My source code license agreement requires attribution, but I’m aware that some people need a license agreement which does not require attribution. If you’re in that situation, please feel free to contact me and we can make arrangements.

Suggested Attribution Format

The license requires that you give credit to me, Damon Caskey, as the original author of any of the code that you use. The placement and format of the credit is up to you, but I prefer the credit to be in the software’s “About” window. Alternatively, you could put the credit in the software’s documentation, or on the web page for the product. The suggested format for the attribution is:

Includes “Name of Code” code by Damon Caskey.

where “Name of Code” would obviously be replaced by the name of the specific source-code package you made use of. Where possible, please link the text “Damon Caskey” to the main page of this website, or include the site’s URL (https://www.caskeys.com/dc).

Full Source Code License Text

License Agreement for Source Code provided by Damon Caskey

This software is supplied to you by Damon Caskey in consideration of your agreement to the following terms, and your use, installation, modification or redistribution of this software constitutes acceptance of these terms. If you do not agree with these terms, please do not use, install, modify or redistribute this software.

In consideration of your agreement to abide by the following terms, and subject to these terms, Damon Caskey grants you a personal, non-exclusive license, to use, reproduce, modify and redistribute the software, with or without modifications, in source and/or binary forms; provided that if you redistribute the software in its entirety and without modifications, you must retain a copy of or link to this notice and the following text and disclaimers in all such redistributions of the software, and that in all cases attribution of Damon Caskey as the original author of the source code shall be included in all such resulting software products or distributions. Neither the name, trademarks, service marks or logos of Damon Caskey may be used to endorse or promote products derived from the software without specific prior written permission from Damon Caskey. Except as expressly stated in this notice, no other rights or licenses, express or implied, are granted by Damon Caskey herein, including but not limited to any patent rights that may be infringed by your derivative works or by other works in which the software may be incorporated.

The software is provided by Damon Caskey on an “AS IS” basis. Damon Caskey MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING THE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.

IN NO EVENT SHALL Damon Caskey BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF Damon Caskey HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Other Questions?

If you’ve got any questions about the license, or if you want to discuss any special requirements or licensing, feel free get in touch – you can find my contact details here.

Enjoy using the source!

DC

PHP – E-mail Class

E-mailing is one of the more common and versatile ways for webmasters and their customers to keep abreast of events. Naturally databases and logs are best practice, but as a quick and dirty way to get form submissions, error alerts and so on E-mail is tough to beat. Even with an established database E-mail still has its place as an alert mechanism.

Given the above and the ubiquitous presence of E-mail in general, it only makes sense to simplify the process of sending as much as possible. To that end, this PHP class wraps the PHP Mail function to extend capability in such a way that oft repeated coding and formatting is eliminated. Specific goals are:

  • Eliminate the need to include the webmaster in any “To list”; the webmaster is always sent a Bcc by default.
  • Eliminate need to add headers for HTML layout with an option to remove if needed.
  • Enable the simple organization of those oh so common form submission or list E-mails to be formatted into a table layout without any markup in the initial mail string.
  • Provide defaults so the bare minimum of parameters may be used when calling.

Elements

Requirements

  • PHP 5.3+

Files

Copy the following into your class file.

class class_mail
{    

	/*
	class_mail - https://www.caskeys.com/dc/?p=5031
	Damon Vaughn Caskey
	2012_12_10
	
	Mail handler. 
	*/	
		
	const	c_bWMAlert	= TRUE;										//Send webmaster a blind copy?
	const	c_cEDefMsg	= "...";									//Default message.
	const	c_cEHead	= "MIME-Version: 1.0 \r\nContent-type: text/html; charset=iso-8859-1\r\n";	//Default E-mail headers.
	const	c_cESubject	= "From EHS Web";							//Default outgoing E-mail subject.
	const	c_cEWMIn	= "dvcask2@uky.edu";						//Default webmaster's incoming E-mail address.
	const	c_cEWMOut	= "ehs_noreply@uky.edu";					//Default address when server sends mail.
				
	public function mail_send($cMsg=self::c_cEDefMsg, $cSubject=self::c_cESubject, $cTo=self::c_cEWMIn, $cFrom=self::c_cEWMOut, $cBcc=NULL, $bWMAlert=self::c_bWMAlert, $cHeader=self::c_cEHead, $cParams=NULL)
	{	
		/*
		mail_send
		Damon Vaughn Caskey
		2012_12_28
		
		Send HTML mail with standard defaults.
		
		$cMsg:		Body of E-mail.
		$cSubject:	Subject line.
		$cTo:		Outgoing address list.
		$cFrom:		Return address.
		$cBcc:		Blind carbon copy address list.
		$bWMAlert:	Send Bcc to webmaster.
		$cHeader:	Header information.
		$cParams:	Optional parameters.
		*/
	
		$cBody = NULL;	//Final sting for message body.
	
		/*
		Insert From address to header.
		*/
		$cHeader .= "From: ".$cFrom. "\r\n";		
		
		/* 
		If Webmaster alert is on, insert address into Bcc and add to header. Otherwise just add Bcc to header as is.
		*/
		if($bWMAlert===TRUE)
		{			
			$cHeader .= "Bcc: ".self::c_cEWMIn. ", ".$cBcc."\r\n";	
		}
		else
		{
			$cHeader .= "Bcc: ".$cBcc."\r\n";
		}
		
		$cHeader .="\r\n";
		
		/*
		If message passed as a key array, break into list and output as table layout.
		*/		
		if (is_array($cMsg))
		{
			/*
			Initial html and table markup.
			*/
			$cBody = "<html>
						<head>
						  <title>".$cSubject."</title>
						</head>
						<body>
						  <h1>".$cSubject."</h1>
						  <table cellpadding='3'>";
			
			/*
			Get each item in array and place into two column table row.
			*/
			foreach($cMsg as $key => $value)
			{			
				$cBody .= "<tr><th>".$key.":</th><td>".$value."</td></tr>";			
			}	
			
			/*
			Add closing markup.
			*/
			$cBody .= "</table>
					</body>
					</html>";	
		}
		else
		{
			/*
			Output message as is.
			*/
			$cBody = $cMsg;
		}
			
		/*
		Run mail function.
		*/
		return mail($cTo, $cSubject, $cBody, $cHeader, $cParams);		
	}	
}

Now include the file in your script and declare a class object. You are ready to go. Personally I prefer to place common class declarations in a single config file and use injected dependency to avoid multiple objects.

require_once('mail.php');	//Path to mail class.

$oMail = NULL;				//Initialize class object.

$oMail = new class_mail();	//Class object.

Use

Constants

Adjust the constant settings to suit your needs.

const	c_bWMAlert	= TRUE;										//Send webmaster a blind copy?
const	c_cEDefMsg	= "...";									//Default message.
const	c_cEHead	= "MIME-Version: 1.0 \r\nContent-type: text/html; charset=iso-8859-1\r\n";	//Default E-mail headers.
const	c_cESubject	= "From EHS Web";							//Default outgoing E-mail subject.
const	c_cEWMIn	= "dvcask2@uky.edu";						//Default webmaster's incoming E-mail address.
const	c_cEWMOut	= "ehs_noreply@uky.edu";					//Default address when server sends mail.
  • c_bWMAlert: Default option to always send Webmaster a Bcc of the outgoing mail.
  • c_cEDefMsg: Default message text.
  • c_cEHead: Default headers. Included in the class are the headers required to send E-mail with HTML formatting (tables, title, etc.).
  • c_cESubject: Default E-mail subject.
  • c_cEWMIn: Webmaster’s incoming address. By default a Bcc of every mail will be sent to this address.
  • c_cEWMOut: Default “from” address.

Functions

mail_send

Primary (and as of this writing the only) function. Sends an E-mail; includes an optional tabled layout.

public function mail_send($cMsg=self::c_cEDefMsg, $cSubject=self::c_cESubject, $cTo=self::c_cEWMIn, $cFrom=self::c_cEWMOut, $cBcc=NULL, $bWMAlert=self::c_bWMAlert, $cHeader=self::c_cEHead, $cParams=NULL)
	{	
		/*
		mail_send
		Damon Vaughn Caskey
		2012_12_28
		
		Send HTML mail with standard defaults.
		
		$cMsg:		Body of E-mail.
		$cSubject:	Subject line.
		$cTo:		Outgoing address list.
		$cFrom:		Return address.
		$cBcc:		Blind carbon copy address list.
		$bWMAlert:	Send Bcc to webmaster.
		$cHeader:	Header information.
		$cParams:	Optional parameters.
		*/
	
		$cBody = NULL;	//Final sting for message body.
	
		/*
		Insert From address to header.
		*/
		$cHeader .= "From: ".$cFrom. "\r\n";		
		
		/* 
		If Webmaster alert is on, insert address into Bcc and add to header. Otherwise just add Bcc to header as is.
		*/
		if($bWMAlert===TRUE)
		{			
			$cHeader .= "Bcc: ".self::c_cEWMIn. ", ".$cBcc."\r\n";	
		}
		else
		{
			$cHeader .= "Bcc: ".$cBcc."\r\n";
		}
		
		$cHeader .="\r\n";
		
		/*
		If message passed as a key array, break into list and output as table layout.
		*/		
		if (is_array($cMsg))
		{
			/*
			Initial html and table markup.
			*/
			$cBody = "<html>
						<head>
						  <title>".$cSubject."</title>
						</head>
						<body>
						  <h1>".$cSubject."</h1>
						  <table cellpadding='3'>";
			
			/*
			Get each item in array and place into two column table row.
			*/
			foreach($cMsg as $key => $value)
			{			
				$cBody .= "<tr><th>".$key.":</th><td>".$value."</td></tr>";			
			}	
			
			/*
			Add closing markup.
			*/
			$cBody .= "</table>
					</body>
					</html>";	
		}
		else
		{
			/*
			Output message as is.
			*/
			$cBody = $cMsg;
		}
			
		/*
		Run mail function.
		*/
		return mail($cTo, $cSubject, $cBody, $cHeader, $cParams);		
	}

Parameters

Unless noted, parameters are not required. Class defaults will be used for any missing.

  • $cMsg: The message to send (i.e. the body text). If passed as a keyed array, the listed items will be laid out as a table. See below for details.
  • $cSubject: Mail subject.
  • $cTo: Recipient address(s).
  • $cFrom: Sender address.
  • $cBcc: Blind copy address(s).
  • $bWMAlert: Send a blind copy to webmaster.
  • $cHeader: Header options.
  • $cParams: Optional parameters. See PHP Mail for details.

Examples

Send regular E-mail

This call will send a common E-mail to the designated recipients with the automatic webmaster Bcc turned off:

$cMsg         = "Hello world!";
$cSubject    = "Hi";
$cTo        = "someone@somewhere.com, someoneelse@somewhereelse.com";
$cFrom        = "me@myplace.com";

$oMail->mail_send($cMsg, $cSubject, $cTo, $cFrom, NULL, FALSE);
Send table E-mail

A common task for E-mail is to document errors, alerts, form submissions and other types of keyed data that is far easier to read in table format. It’s certainly possible to do this by manually coding table markup into the message, but also repetitive and time consuming.

Instead, you can pass the message as a keyed array; a simple but elegant table from your data will be created and sent to the recipients. The E-mail’s subject will be added as an attention grabbing header just above the table.

$cMsg 	= NULL;

		$cMsg = array(
			"Time"				=>	$this->cErrTOE,
			"Type"				=>	$this->cErrType,
			"IP"				=>	$this->cIP,
			"Def. Source File"	=>	$this->cSource,
			"Source File"		=>	$this->cErrFile,
			"Line"				=>	$this->cErrLine,
			"State"				=>	$this->cErrState,
			"Code"				=>	$this->cErrCode,
			"Message"			=>	$this->cErrMsg,
			"Details"			=>	$this->cErrDetail
		);

$this->oMail->mail_send($cMsg, "Error Report");
Example output:
In this example, an error alert is sent using table layout.

In this example, an error alert is sent using table layout.

PHP – Global Constants

This set of global constants is a dependency for nearly all other functions and classes I have created with PHP. For obvious security reasons some of the actual values may be removed.

class constants
{    

	/*
	constants
	Damon Vaughn Caskey
	2012_12_18
	~2012_12_30: Local constants moved back to individual class files.
	
	Global constants. 
	*/		
	
	/* Basic values */
	const	c_cAdmin		= "";										//Default "all access" user accounts.
	const	c_cDateF		= "Y-m-d H:i:s";							//Default date format.
	const	c_cWMName		= "Damon V. Caskey";						//Default webmaster's name.
	const	c_cWMEmailIn	= "dvcask2@uky.edu";						//Default webmaster's incoming email address.
	const	c_cVFGuid		= "00000000-0000-0000-0000-000000000000";	//False guid.
					
	/* Media & Icons */
	const	c_cIconExcel	= "<img src='/media/image/icon_excel.png' alt='MS Excel document.' title='MS Excel document.' class='iconS'/>";					//MS Excel icon.
	const	c_cIconPDF		= "<img src='/media/image/icon_pdf.png' alt='PDF document.' title='PDF document.' class='iconS' />";							//PDF icon.
	const	c_cIconPPT		= "<img src='/media/image/icon_powerpoint.png' alt='MS Powerpoint document.' title='MS Powerpoint document.' class='iconS' />";	//MS Powerpoint icon.
	const	c_cIconWord		= "<img src='/media/image/icon_word.png' alt='MS Word document.' title='MS Word document.' class='iconS' />";					//MS Word icon.
	const	c_cPathImage	= "/media/image/";							//Default path for image files.	
}

PHP – PIM (PHP IIS MSSQL) Database Class

PHP

Please Note: This class has long been replaced with a truly object oriented solution that utilizes the sqlsrv driver. I am only leaving it here for posterity (and to embarrass myself). Use at your own peril 🙂

 

This PHP class file is designed to take care of day to day database operations for the rare but not unheard of combination of PHP with IIS and MSSQL.

I’m not a fan of reinventing the wheel, but after extensive searching had been unable to find any existing classes that suited the needs of a WIMP combo. Not much of a surprise considering the majority of PHP use falls under the LAMP model, but it is certainly frustrating.

I hope anyone in a similar situation can find this of use. The goals are simple and straight forward:

  • Reduce repetitive code and increase portability. This is an obvious goal – reusable, portable code not only saves time, but cuts down on human error (typos, misplaced values, etc.).
  • Move to an object oriented model. While a function based model can accomplish many of the listed goals here, and an object oriented coding model carries many other advantages, the discussion of which is beyond the scope of this article.
  • Quick implementation. To reduce clutter in pages and functions utilizing the class, class functions should accomplish common tasks with few calls as possible. To accomplish this goal, functions are created as basic building blocks with a cascading operation order in mind. This allows creation of master functions which can in turn run all of the basic building blocks for a common task with a single call.
  • Block SQL injection. This is achieved by designing for and stressing the use of parameters. Used properly this will effectively stops SQL injection attempts cold.
  • Robust error trapping. In the event of an error, as much information as possible should be collected and sent to webmaster. Additionally, an attempt should be made to log collected information into another remote database for easy dissemination.

Elements

Dependencies

Global Constants

The following values are used from global constants list.

class constants
{
	/*
	constants
	Damon Vaughn Caskey
	2012_12_18

	Global constants.
	*/

	/* Basic values */
	const	c_cAdmin		= &quot;&quot;;										//Default &quot;all access&quot; user accounts.
	const	c_cDateF		= &quot;Y-m-d H:i:s&quot;;							//Default date format.
	const	c_cWMName		= &quot;Damon V. Caskey&quot;;						//Default webmaster name.
	const	c_cWMEmailIn	= &quot;&quot;;										//Default webmaster email address (sending mail to webmaster)
	const	c_cWMEmailOut	= &quot;&quot;;										//Default address when server sends mail.
	const	c_cVFGuid		= &quot;00000000-0000-0000-0000-000000000000&quot;;	//False guid.

	/* Database */
	const 	c_cDBHost		= &quot;&quot;;										//Default DB Host.
	const 	c_cDBLName		= &quot;&quot;;										//Default DB logical name.
	const 	c_cDBUser		= &quot;&quot;;										//Default DB user.
	const 	c_cDBPword		= &quot;&quot;;										//Default DB password.
	const 	c_cDBEHost		= &quot;&quot;;										//Error log DB host.
	const 	c_cDBELName		= &quot;&quot;;										//Error log DB logical name.
	const 	c_cDBEUser		= &quot;&quot;;										//Error log DB user.
	const 	c_cEDBPword		= &quot;&quot;;										//Error log DB password.
	const 	c_cDBEEmailSub	= &quot;Database Failure&quot;;						//Error email subject line.
	const 	c_iDBFetchType	= SQLSRV_FETCH_BOTH;						//Default row array fetch type.

	/* Media &amp; Icons */
	const	c_cIconExcel	= &quot;&quot;;										//MS Excel icon.
	const	c_cIconPDF		= &quot;&quot;;										//PDF icon.
	const	c_cIconPPT		= &quot;&quot;;										//MS Powerpoint icon.
	const	c_cIconWord		= &quot;&quot;;										//MS Word icon.
	const	c_cPathImage	= &quot;&quot;;										//Default path for image files.
}
  • c_cDateF: This is the default format for dates. If you reconfigure this value, make sure it is one that MSSQL date fields will accept; they can get fairly picky.
  • c_cWMEmailIn: This is the webmaster email address. It is where any alerts will be sent, so make sure to include working addresses that won’t flag an alert as spam.
  • c_cWMEmailOut: Address used in the “from” tag of mails sent to webmaster.
  • c_cDBHost: The connection string or IP of your primary database host (or just the one you use most often).
  • c_cDBLName: Your most often used logical database name on your primary database host.
  • c_cDBUser: The user account name to access your primary database host.
  • c_cDBPword: The user account password to access your primary database host.
  • c_cDBEHost: The connection string or IP of on alternate database host to record errors.
  • c_cDBELName: Logical database name where error log table is located on error database host.
  • c_cDBEUser: The user account name to access your error database host.
  • c_cEDBPword: The user account password to access your error database host.
  • c_cDBEEmailSub: The  e-mail subject line of alert mails sent when an error occurs.
  • c_iDBFetchType: The row key fetch type. This determines how the line row array can be accessed. See here for more information.

Next, you will need to initialize the database class in whatever script you would like to use it in. This is fairly simple:

Variables

			
	public	$cDBLine		= NULL;									//Line array.
	public 	$cDBFMeta		= NULL;									//Line metadata array.
	public 	$iDBFCount		= NULL;									//Line field count.
	public	$iDBRowCount	= NULL;									//Table row count.
	public	$iDBRowsAffect	= NULL;									//Number of rows affected by an action query.
	public 	$rDBConn 		= NULL;									//Database connection ID resource.
	public 	$rDBResult		= NULL;									//Database query result ID resource.
	public 	$rDBStatement	= NULL;									//Database prepared query statement ID resource.		

The following public variables are made available upon initialization. These are set by the various function calls and will be the main means of actually extracting values returned from your database.

  • cDBLine: An array of the fields (columns) found in a given table row.
  • cDBFMeta: An array of metadata. This contains information on the table fields themselves (size, name, type, etc.).
  • iDBFCount: Simple count of the number of fields returned from a query.
  • iDBRowCount: How many rows were returned by a select query.
  • iDBRowsAffect: How many rows were affected by an action query.
  • rDBConn: ID of the connection to a database host.
  • rDBResult: ID of the data returned from a query.
  • rDBStatement: ID of a prepared query (SQL string and parameters).

Functions

db_basic_action

function db_basic_action($cQuery, $cParams, $cHost = constants::c_cDBHost, $cDB = constants::c_cDBLName, $cUser = constants::c_cDBUser, $cPword = constants::c_cDBPword)
	{
		/*
		db_basic_action
		Damon Vaughn Caskey
		2012_11_13
		
		Connect and execute an action query with single call.
		
		$cQuery: 	SQL string.
		$cParams:	Parameter array.
		$cHost:		DB Host.
		$cDB:		DB logical name.
		$cUser:		DB user.	
		$cPword:	DB password.
		*/
				
		/* Connect to DB */
		$this-&gt;db_connect($cHost, $cDB, $cUser, $cPword);
		
		/* Execute query. */
		$this-&gt;db_query($cQuery, $cParams);		
		
		/* Set rows affected. */
		$this-&gt;iDBRowsAffect = sqlsrv_rows_affected($this-&gt;rDBResult);		
		
		return $this-&gt;iDBRowsAffect;
	}

This function is designed to run simple action queries with a single call. There is no need to run a separate call to connect, prepare, and query execute. Simply pass the query, parameters and (if necessary) connection values.

Sets and returns iDBRowsAffect.

db_basic_select

function db_basic_select($cQuery, $cParams, $iLine=FALSE, $cHost = constants::c_cDBHost, $cDB = constants::c_cDBLName, $cUser = constants::c_cDBUser, $cPword = constants::c_cDBPword)
	{
		/*
		db_basic_select
		Damon Vaughn Caskey
		2012_11_13
		
		Connect, query and populate common variables from database with a single call.
		
		$cQuery: 	SQL string.
		$cParams:	Parameter array.
		$iLine:		Populate line array with first row?
		$cHost:		DB Host.
		$cDB:		DB logical name.
		$cUser:		DB user.	
		$cPword:	DB password.
		*/
				
		/* Connect to DB */
		$this-&gt;db_connect($cHost, $cDB, $cUser, $cPword);
		
		/* Execute query. */
		$this-&gt;db_query($cQuery, $cParams);
		
		/* Get row count */
		$this-&gt;db_count();
		
		/* Get field count. */
		$this-&gt;db_field_count();
		
		/* Get metadata. */
		$this-&gt;db_field_metadata();	
		
		if($iLine===TRUE)
		{
			$this-&gt;db_line();			
		}
		
		return $this-&gt;cDBLine;
	}

This function is designed to run simple select queries with a single call. There is no need to run a separate call to connect, prepare, and query execute. Simply pass the query, parameters and (if necessary) connection values.

Note the iLine parameter. If this is passed as TRUE, cDBLine will be populated with the first row from your query result. This option is very useful for times when you expect and only need a single row result; one call to this function is all you need. However, you will want to be careful with multiple rows as the row cursor will now be at the next record. This means a subsequent call to db_line() will start at the second record, NOT the first.

Returns cDBLine.

db_close

function db_close()
	{
		/*
		db_close
		Damon Vaughn Caskey
		2012_11_13
		
		Close current conneciton. Normally not needed.
		*/
		
		/* Close DB conneciton. */
		sqlsrv_close($this-&gt;rDBConn);
		
		/* Return TRUE. */
		return TRUE;
	}

Closes connection with rDBConn.

db_connect

function db_connect($cHost = constants::c_cDBHost, $cDB = constants::c_cDBLName, $cUser = constants::c_cDBUser, $cPword = constants::c_cDBPword)
	{		 
		/*
		db_connect
		Damon Vaughn Caskey
		2012_11_13
		
		Connect to database host and store reference to public variable.
		
		$cHost:		DB Host.
		$cDB:		DB logical name.
		$cUser:		DB user.	
		$cPword:	DB password.		
		*/
			
		$db_cred = NULL; //Credentials array.
	
		/* Only bother connecting to DB host if no previous connection is established. */
		if(!$this-&gt;rDBConn)
		{	
			/* Set up credential array. */
			$db_cred = array(&quot;Database&quot;=&gt;$cDB, &quot;UID&quot;=&gt;$cUser, &quot;PWD&quot;=&gt;$cPword);
									
			/* Establish database connection. */
			$this-&gt;rDBConn = sqlsrv_connect($cHost, $db_cred);		
		}
		
		/* False returned. Database connection has failed. */
		if($this-&gt;rDBConn === FALSE)
		{
			/* Stop script and log error. */
			$this-&gt;db_error(&quot;db_connect&quot;, NULL, NULL, TRUE);	
		}	
	}

Opens a connection to database host; defaults to primary host and database using connection pooling.

db_count

function db_count()
	{
		/*
		db_line
		Damon Vaughn Caskey
		2012_11_13
		
		Return number of records from query result.
		*/
		
		/* Get row count. */
		$this-&gt;iDBRowCount = sqlsrv_num_rows($this-&gt;rDBResult);	
		
		$this-&gt;db_error(&quot;db_count&quot;);	
		
		/* Return count. */
		return $this-&gt;iDBRowCount;
	}

Set and return iDBRowCount with record count from last query (rDBResult).

db_error

function db_error($cLocation = NULL, $cSql = NULL, $cParams = NULL, $bFatal = FALSE)
	{
		
		/*
		db_error
		Damon Vaughn Caskey
		2012_06_08
		
		Wrapper for sqlsrv_errors(). Record any errors into an alternate database and send email to webmaster.
		
		$cLocation:	Code location where error trap was called. Aids in dubugging.
		$cSql:		SQL string passed at time of error.
		$cParams:	Parameter array passed at time of error.
		$bFatal:	If error triggers, should process be terminated?
		*/
		
		$cMBody			= NULL;	//Mail message.
		$aErrors		= NULL;	//Errors list array.
		$aError			= NULL;	//Error output array.
		$mysqli			= NULL;	//Connection reference to DB error log.
		$query			= NULL; //Error query string.
		$stmt			= NULL;	//Prepared query reference.
		$val			= NULL;	//Array of error values.
		$cParam			= NULL;	//Individual item from parameter array.
		
		/* Get error collection */
		$aErrors = sqlsrv_errors();
		
		/* Any errors found? */
		if($aErrors)					
		{	
			/* Connect to error log database (obviously this should be an alternate DB from the one that failed). */	
			$mysqli = new mysqli(constants::c_cDBEHost, constants::c_cDBELName, constants::c_cDBEUser, constants::c_cEDBPword);
			
			/* Loop through error collection. */
			foreach($aErrors as $aError)
			{
				/*
				Ignore these codes; they are informational only:
					0:		Cursor type changed.
					5701:	Changed database context.
					5703:	Changed language setting.
				*/
				if($aError['code'] != 0 &amp;&amp; $aError['code'] != 5701 &amp;&amp; $aError['code'] != 5703)
				{
					
					$val[0] = $cLocation;				//Function &amp; Line location. Manually set in execution code to aid debugging; not part of error routine.
					$val[1] = $aError['SQLSTATE'];		//Status of DB host.
					$val[2] = $aError['code'];			//Error code.
					$val[3] = $aError['message'];		//Error message.
					$val[4] = $cSql;					//SQL string (if any) attempting to be executed.
					$val[5] = NULL;						//Parameter array.
					$val[6] = $_SERVER[&quot;PHP_SELF&quot;];		//Calling PHP file.
					$val[7] = $_SERVER['REMOTE_ADDR'];	//Client IP address.
					
					/* Dump parameter array into single string. */
					if(isset($cParams))								//Parameter array passed?
					{
						foreach($cParams as $cParam)				//Loop array collection.
						{
							$val[5] .= $cParam .&quot;, &quot;;				//Add to error parameter string.
						}
					}
					
					/* Build mail body string */
					$cMBody .= 
					&quot;\n Code Location: &quot;.	$val[0]. 
					&quot;\n SQLSTATE: &quot;.		$val[1].
					&quot;\n Code: &quot;.			$val[2].
					&quot;\n Message: &quot;.			$val[3].
					&quot;\n SQL String: &quot;.		$val[4].
					&quot;\n Parameters: &quot;.		$val[5].
					&quot;\n File: &quot;.			$val[6].
					&quot;\n Client IP: &quot;.		$val[7].	
					&quot;\n&quot;;
					
					/* If the error log database connection was successful, insert each error to table. */
					if (!$mysqli-&gt;connect_error) 
					{	
						/* Build query string. */		
						$query = &quot;INSERT INTO tbl_query_errors (codel, state, code, msg, query, params, source, ip) VALUES (?,?,?,?,?,?,?,?)&quot;;
						$stmt = $mysqli-&gt;prepare($query);
						
						/* Bind parameters. */
						$stmt-&gt;bind_param(&quot;ssssssss&quot;, $val[0], $val[1], $val[2], $val[3], $val[4], $val[5], $val[6], $val[7]);
						
						/* Execute and close query. */
						if($stmt != false)
						{							
							/* Execute and close query. */
							$stmt-&gt;execute();
							$stmt-&gt;close();
						}
					}
				}
			}
			
			/* Close DB connection. */
			$mysqli-&gt;close();
			
			/* Send EMail alert. */
			mail(constants::c_cWMEmail, constants::c_cDBEEmailSub, $cMBody, constants::c_cWMEmailOut);
			
			/* If error is fatal, stop PHP execution immediately. */
			if($bFatal)
			{
				die(&quot;A fatal database error has occurred. Please contact the webmaster immediately.&quot;);
			}
			
			return true;
		}
		
		return false;	
	}

Capture, log and return any errors encountered by the various other functions. If errors are found, they will be sent to webmaster via e-mail Additionally an attempt is made to log the errors to another database.

My method is to use the MySQL database in my personal web portal to log various activities from production sites I am responsible for using an INSERT only account. This ensures I am always aware of potential issues and have organized debugging info for problems that arise. For this reason, the error function is written primarily for MySQL. It would be easy enough to alter this for your own needs.

Note the bFatal parameter. If this is set to TRUE, the entire script (i.e. the page being generated) will fail and be replaced with an alert. This is less than user friendly, but in some cases may be a preferable result.

db_execute

function db_execute()
	{
		/*
		db_execute
		Damon Vaughn Caskey
		2012_11_13
		
		Execute prepared query.
		*/
	
		/* Execute statement. */
		$this-&gt;rDBResult = sqlsrv_execute($this-&gt;rDBStatement);
		
		/* Error trapping. */
		$this-&gt;db_error(&quot;db_execute&quot;);
		
		/* Set rows affected. */
		$this-&gt;iDBRowsAffect;
		
		/* Return ID resource. */
		return $this-&gt;rDBResult;		
	}

Executes rDBStatement, then populates and returns rDBResult with the results. Also sets iDBRowsAffect with the number of rows affected by execution. Useful for efficiently running a single action query where only the parameters (if anything) change.

db_field_count

function db_field_count()
	{
		/*
		db_field_count
		Damon Vaughn Caskey
		2012_11_13
		
		Get number of fields from query result.
		*/
		
		/* Get field count. */
		$this-&gt;iDBFCount = sqlsrv_num_fields($this-&gt;rDBResult);
		
		/* Error trapping. */
		$this-&gt;db_error(&quot;db_field_count&quot;);
		
		/* Return field count. */
		return $this-&gt;iDBFCount;
	}

Sets and returns iDBFCount with the number of fields returned by rDBResult.

db_field_metadata

function db_field_metadata()
	{
		/*
		db_field_metadata
		Damon Vaughn Caskey
		2012_11_13
		
		Fetch table rows metadata array (column names, types, etc.).
		*/
		
		/* Get metadata array. */
		$this-&gt;cDBMeta = sqlsrv_field_metadata($this-&gt;rDBResult);
		
		/* Error trapping. */
		$this-&gt;db_error(&quot;db_field_metadata&quot;);
		
		/* Return metadata array. */
		return $this-&gt;cDBMeta;
	}

Sets and returns cDBMeta with field meta data from rDBResult.

db_line

function db_line($iFetchType = constants::c_iDBFetchType)
	{
		/*
		db_line
		Damon Vaughn Caskey
		2012_11_13
		
		Fetch line array from table rows.
		
		$iFetchType: Row key fetch type
		*/
		
		/* Get line array. */
		$this-&gt;cDBLine = sqlsrv_fetch_array($this-&gt;rDBResult, $iFetchType);		
				
		/* Error trapping. */
		$this-&gt;db_error(&quot;db_line&quot;);
		
		/* Return line array. */
		return $this-&gt;cDBLine;
	}

Sets and returns cDBLine with row array data from rDBResult. This is the function you would place inside of a while loop to fetch the entire row list from a record set.

db_prepare

function db_prepare($cQuery, $cParams, $cOptions = array(&quot;Scrollable&quot; =&gt; SQLSRV_CURSOR_STATIC))
	{
		/*
		db_prepare
		Damon Vaughn Caskey
		2012_11_13
		
		Prepare query statement.
		
		$cQuery: 	Basic SQL statement to execute.
		$cParams:	Parameters to pass with query (prevents SQL injection).
		$cOptions:	Options for cursor array, etc.
		*/
	
		/* Execute query. */
		$this-&gt;rDBStatement = sqlsrv_prepare($this-&gt;rDBConn, $cQuery, $cParams, $cOptions);
		
		/* Error trapping. */
		$this-&gt;db_error(&quot;db_prepare&quot;, $cQuery, $cParams);
		
		/* Return query ID resource. */
		return $this-&gt;rDBStatement;		
	}

Prepare a query statement from SQL string and parameters, then place into rDBStatement. Use this function to prepare action queries you need to execute repeatedly.

db_query

function db_query($cQuery, $cParams, $cOptions = array(&quot;Scrollable&quot; =&gt; SQLSRV_CURSOR_STATIC))
	{
		/*
		db_query
		Damon Vaughn Caskey
		2012_11_13
		
		Prepare and execute query.
		
		$cQuery: 	Basic SQL statement to execute.
		$cParams:	Parameters to pass with query (prevents SQL injection).
		$cOptions:	Options for cursor array, etc.
		*/
	
		/* Execute query. */
		$this-&gt;rDBResult = sqlsrv_query($this-&gt;rDBConn, $cQuery, $cParams, $cOptions);
		
		/* Error trapping. */
		$this-&gt;db_error(&quot;db_query&quot;, $cQuery, $cParams);
		
		/* Return query ID resource. */
		return $this-&gt;rDBResult;		
	}

Prepare a query statement from SQL string and parameters, then execute immediately. Populates and returns rDBResult with result. This function is useful when you want to run a single query with no functional add-ons.

Wig Wag

PHP

This super simple function will output alternating values as the input numeric increments. Handy for server side table styling, progress bars, and other minor elements where an alternating visual style is desirable.

License

Use

During any loop statement where row outputs are created, pass the loop or row count to this function. The resulting output should then be used as your style argument.

Source Code

// 	Damon Vaughn Caskey
//	2012-10-18
//	Output alternating values for even/odd input. 
//
// $i Number to evaluate.
// $even: Output if $i is an even number. 
// $odd: Output if $i is an odd number.
function wig_wag($i, $even = "#DDDDFF", $odd = "#CECEFF") 
{ 
	$result = NULL; // Final result.
	 
	if($i%2) //Even number? 
	{		
		$result = $even; // Set even value. 
	} 
	else 
	{ 
		$result = $odd; // Set odd value. 
	}
	
	// Output result.
	return $result;
}

Bluegrass Mud Run

I’ve always loved fitness, exploration and outdoor adventure. Even so, I haven’t strapped on numbers and participated in an organized sporting event since high school. It was high time to change that, and The Inaugural Bluegrass Mud Run was a perfect opportunity.

In my usual fashion I lost track of dates and almost missed it until a friend reminded me they too were participating – I just managed to get signed up a day before the event. It was a blast from start to finish, and the entry fee going to support local charities makes the whole thing even better.

Naturally, the GoPro camera came along, and with it a full POV. Want to see what it’s like to run a military inspired obstacle course without getting yourself dirty? Well, here you are…

DC & Double D

It’s been a while since I logged any adventure in my adventure section hasn’t it? Far too long I think. Of course, it’s a bit difficult to record things on a broken blog, and boy was it. That is now fixed. The next step is to actually have something to add. Problem is I’m not really all that great at getting “backlogged” adventures up, and for a couple of weeks I haven’t had anything new to contribute.

As it happens some wackiness a few weeks ago (that I’ll hopefully get posted, but probably not :P) resulted in someone asking me nicely to “be more careful with myself” as it were, which in turn really puts a damper on random exploration. Believe it or not I didn’t mind a bit; it was probably the first time anyone had shown me honest concern instead of some smarmy “don’t go die!” derision. The whole thing came from WAY out of left field, but I still found it heart warming and so was willing to comply. Ultimately though it turns out said concern (along with many other things) was a complete farce. Obviously when I figured that out any agreement was immediately null and void. Depressing to say the least, and not something I want to divulge all the details about publicly. But hey, at least I’m free to do my thing again right? Edit: Or not? Time will tell, but perhaps I made a hasty assumption. Communication is key.

Sooooo, blog fixed, freedom restored. Nothing left but to recover my full strength and find something to do with it. 🙂

That something took the form of a second trip up the Dix River to get better photographs of the dam apparatus. On my previous trip I did not have the necessary camera equipment needed to get worthwhile photos. A little high def GoPro video augmented by some 8MP still shots would fix that right up. Or at least, it would have if I could learn to leave on time. I didn’t get to the dam until well after dark, and as anyone else who uses a GoPro can tell you, the one flaw they have is needing an abundance of light. Ahh well, at least I still got to see it for myself. As an added bonus, the darkness gave me an opportunity to climb around for some up close & personal looks at the pen-stocks, dam structure and a few other nick knacks.

Sadly I did not run into Dan this time, making it just a Dam, & Dix trip. Would have liked to chat with him again, but since I still need photos I’ll be back soon enough. Maybe next time.

Here is the footage I did take, along with a route plot. The video runs from put in to just about the first rapid, at which point I turned the camera off since it was obviously not going to record much else from that point. Just for extra fun, the sensors in my GPS went awry a bit (just a tiny bit) sending my plot on a 21,000+ mile detour; averaging over 5000kph! Now THAT’S some paddling!

 

 

Welcome to ADHD

Here is a somewhat self-pitying but still quite insightful article on the experience of ADHD by one Dr. Edward M. Hallowell. This was originally linked by Ty Brown on Facebook, and quickly caught my attention (no pun intended).

As my peers are aware, I was diagnosed in 7th grade, before calling every other kid ADHD was in vogue. For a short while I was even on the then new drug Ritalin, and it was quite effective (interesting note, Ritalin itself makes a workable if somewhat scary diagnostic tool. It has the intended calming effect on actual ADHD subjects, while simply giving “normal” individuals a variable euphoric high).

Due to side effects on my digestive system and the simple fact neither me nor the family liked the idea of my being on a pill my dosage was discontinued. Bad grades and (in some people’s eyes) a minor thrill seeking complex aside I have gotten along just fine without it.

Here is the actual article, also block quoted below should the link go dead.

Enjoy,

DC

What is it like to have ADHD? What is the feel of the syndrome? Attention Deficit Hyperactivity Disorder. First of all, I resent the term. As far as I’m concerned, most people have Attention Surplus Disorder. I mean, life being what it is, who can pay attention to anything for very long? Is it really a sign of mental health to be able to balance your checkbook, sit still in your chair, and never speak out of turn? But anyway, be that as it may, there is this syndrome called ADD or ADHD, depending on what book you read. So what’s it like to have it?

Some people say the so-called syndrome doesn’t even exist, but believe me, it does. Many metaphors come to mind to describe it. It’s like driving in the rain with bad windshield wipers. Everything is smudged and blurred and you’re speeding along, and it’s really frustrating not being able to see very well. Or it’s like listening to a radio station with a lot of static and you have to strain to hear what’s going on. Or, it’s like trying to build a house of cards in a dust storm. You have to build a structure to protect yourself from the wind before you can even start on the cards.

In other ways it’s like being supercharged all the time. You get one idea and you have to act on it, and then, what do you know, but you’ve got another idea before you’ve finished up with the first one, and so you go for that one, but of course a third idea intercepts the second, and you just have to follow that one, and pretty soon people are calling you disorganized and impulsive and all sorts of impolite words that miss the point completely. Because you’re trying really hard. It’s just that you have all these invisible vectors pulling you this way and that, which makes it really hard to stay on task. Plus, you’re spilling over all the time. You’re drumming your fingers, tapping your feet, humming a song, looking here, looking there, stretching, doodling, and people think you’re not paying attention or that you’re not interested, but all you’re doing is spilling over so that you can pay attention. I can pay a lot better attention when I’m taking a walk or listening to music or even when I’m in a crowded, noisy room than when I’m still and surrounded by silence.

What is it like to have ADHD? Buzzing. Being here and there and everywhere. Someone once said, “Time is the thing that keeps everything from happening all at once.” Time parcels moments out into separate bits so that we can do one thing at a time. In ADHD, this does not happen. In ADHD, time collapses. Time becomes a black hole. To the person with ADHD it feels as if everything is happening all at once. This creates a sense of inner turmoil or even panic. The individual loses perspective and the ability to prioritize. He or she is always on the go, trying to keep the world from caving in on top.

Lines. I’m almost incapable of waiting in lines. I just can’t wait, you see. That’s the agony of it. Impulse leads to action. I’m very short on what you might call the intermediate reflective step between impulse and action. That’s why I, like so many people with ADHD, lack tact. Tact is entirely dependent on the ability to consider one’s words before uttering them. We ADHD types don’t do this so well.

Many of us with ADHD crave high-stimulus situations. In my case, I love casinos, the high-intensity crucible of doing psychotherapy and having lots of people around. High stim situations can get you into trouble, which is why ADHD is high among criminals and self-destructive risk-takers. It is also high among so-called Type A personalities, as well as among manic-depressives, sociopaths and drug users. But it is also high among creative and intuitive people in all fields, and among highly-energetic, highly-productive people. Which is to say there is a positive side to all this. Usually the positive doesn’t get mentioned when people speak about ADHD because there is a natural tendency to focus on what goes wrong, or at least on what has to be somehow controlled. But often once the ADHD has been diagnosed, and the individual, with the help of teachers, parents and colleagues, has learned how to cope with it, an untapped realm of the brain swims into view. Suddenly the radio station is tuned in, the windshield is clear, the sand storm has died down. And the child or adult, who had been such a problem, such a nudge, such a general pain in the neck, starts doing things he’d never been able to do before. He surprises everyone around him, and he surprises himself. I use the male pronoun, but it could just as easily be she, as we are seeing more and more ADHD among females as we are looking for it.

Often these people are highly imaginative and intuitive. They have a “feel” for things, a way of seeing right into the heart of matters while others have to reason their way along methodically. This is the person who can’t explain how he thought of the solution, or where the idea for the story came from, or why suddenly he produced such a painting, or how he knew the short cut to the answer, but all he can say is he just knew it, he could feel it. This is the man or woman who makes million-dollar deals in a catnap and pulls them off the next day. This is the child who, having been reprimanded for blurting something out, is then praised for having blurted out something brilliant. These are the people who learn and know and do and go by touch and feel.

These people can feel a lot. In places where most of us are blind they can, if not see the light, at least feel the light, and they can produce answers apparently out of the dark. It is important for others to be sensitive to this “sixth sense” many ADHD people have, and to nurture it. If the environment insists on rational, linear thinking and “good” behavior from these people all the time, then they may never develop their intuitive style to the point where they can use it profitably. It can be exasperating to listen to people talk. They can sound so vague or rambling. But if you take them seriously and grope along with them, often you will find they are on the brink of startling conclusions or surprising solutions.

What I am saying is that their cognitive style is qualitatively different from most people’s, and what may seem impaired, with patience and encouragement may become gifted. The thing to remember is that if the diagnosis can be made, then most of the bad stuff associated with ADHD can be avoided or contained. The diagnosis can be liberating, particularly for people who have been stuck with labels like “lazy,” “stubborn,” “willful,” “disruptive,” “impossible,” “tyrannical,” “a space shot,” “brain damaged,” “stupid,” or just plain “bad.” Making the diagnosis of ADHD can take the case from the court of moral judgment to the clinic of neuropsychiatric treatment.

What is the treatment all about? Anything that turns down the noise. Just making the diagnosis helps turn down the noise of guilt and self-recrimination. Building certain kinds of structure into one’s life can help a lot. Working in small spurts rather than long hauls. Breaking tasks down into smaller tasks. Making lists. Getting help where you need it. Maybe applying external limits on your impulses. Or getting enough exercise to work off some of the noise inside. Finding support. Getting someone in your corner to coach you, to keep you on track. Medication can help a great deal too, but it is far from the whole solution. The good news is that treatment can really help.

We who have ADHD need your help and understanding. We may make mess-piles wherever we go, but with your help, those mess-piles can be turned into realms of reason and art. So, if you know someone like me who’s acting up and daydreaming and forgetting this or that and just not getting with the program, consider ADHD before he starts believing all the bad things people are saying about him and it’s too late.

We’re Back!

After thoroughly breaking DC Current with a botched bit of custom code to the point my database was in need of a rebuild, I had put off fixing everything for quite a while. But today I finally buckled down and got everything back online.

Unfortunately it meant blowing away all the customization and feature adds I had done prior, so now it’s time to get started reinstalling the plug-ins, themes, widgets, etc. Ugh…

DC

Batmobile

Holy nerdgasm Batman!

On Friday 2012/04/13 the original 1966 series Batmobile was parked in front of UK’s Joe Craft Center, just outside my office. How’s that for a Friday the 13th surprise? Way too awesome to banter on about, that’s what! Let’s get right to the pictures instead. See you next time. 🙂

DC

 

West Liberty Relief

This is what's left of West Liberty.

This is what's left of West Liberty.

As I’m sure most of you are aware, several towns in Eastern Kentucky suffered severe damage from storms Friday evening. West Liberty was hit particularly hard, having been almost completely destroyed by an EF3 tornado. After assisting there on Saturday I can personally attest the situation is absolutely horrific and the people can use all the help they can get.

To aid in the relief efforts, Caskey’s Inc. will be sending our box truck with supplies on as many runs as necessary. We are currently soliciting donations for any of the following:

  • Non-perishable food items
  • Bottled water
  • Bedding (sheets, quilts, blankets, etc.)
  • Basic tools
  • Building supplies (lumber, plywood and heavy plastic in particular)
  • Generators (will be returned to owners)

If you are interested, drop offs can be made in my office at 252 East Maxwell Street Lexington KY, or contact Cindy Caskey at 606-784-2782.

In addition, I will be returning Saturday to offer direct assistance with clean-up efforts. If anyone would like to come along and get a good day’s work in, please contact me at 859-257-3241 or 606-776-4914.

Thanks,
DC

Let’s Explore: The Gorge – 2012-01-15

This has to be one of the worst winters I can remember. Not once has there been a reasonable snow, and aside from some some very short lived exceptions the temperature has hovered at 50′ or more since late November. So when a small clipper system dropped a bit of the white stuff in Eastern Kentucky this weekend, I just had to get out and enjoy it. And where else to enjoy a fresh snowfall than Red River Gorge?

Going out meant I had to miss the Packers playing New York, but I already knew how that one was going to pan out (though I had no idea just how bad). It also meant delaying the Cumberland River section of my mapping project, but I’m pretty sure those rivers won’t be going anywhere for a while.

In short, a no brainier. Strap on the field kit, grab Cammy and away we went for a brisk day of winter walking. Surprisingly enough dogs can’t solo climb, so I had to leave some of my favorite places off the list – Half Moon arch in particular. Still, we hit quite a few landmarks before the day was through. Chimney Rock, Half Moon (just not to the top), Sky Bridge, Angel Windows, Eagles Nest, and of course the Nada Tunnel.

Cammy seemed to love it, and I for one was happy to finally have some company!

 

Cumberland River Headwaters Area – 2011-12-27

One of my personal projects is to map out and survey the major rivers in Eastern & Central Kentucky, in particular, their headwaters. Eastern Kentucky is drained by three main rivers; Big Sandy, Licking, and the Cumberland. Each of these rivers runs a course quite distinct from the others, though their headwaters reside within a few dozen miles and all are tributaries of the Ohio. Central Kentucky is in turn drained by the Kentucky River, whose headwaters are also in the same vicinity.

Licking River

The Licking river runs through my hometown of Morehead and beyond forming Cave Run Lake it attracts little attention. It has a powerful flow year round, but few rapids and runs mostly through private farms. Its headwaters are located in Magoffin County in a difficult to access area around route 7. Unlike the others in this project, the Licking River retains the same identity end to end. It does have two “forks”, but these are in name only. Both are simply downstream tributaries, although locals along the South Fork often mistake it to be the main stem. The Licking is personally notorious to me because every time I go near it, mishaps surly follow. One in particular probably should have killed me, but instead just left a minor scar. Sometimes it’s better to be lucky than good. Rivers have a personality, and as I am learning, the Licking doesn’t seem to like me very much. I’ll probably do this one next.

Big Sandy River

Second to the Cumberland in historical significance, the Big Sandy proper is barley 30 miles in length, otherwise divided into Tug Fork and the dangerous Levisa Fork. Because of the distance involved, I will likely save this river for last, and conduct most of the mapping during kayaking trips.

Kentucky River

The Kentucky itself is easily assessable, but its three forks are somewhat dispersed. I plan to take this after finishing up the Licking.

Cumberland River

Of these four rivers, the Cumberland is by far the largest, most unique in course, and historically significant. It also has the most physically accessible headwaters areas, though perhaps the most isolated. For these reasons it was my first choice. Like many large rivers, there is some debate to this day what exactly constitutes the Cumberland headwaters. In name the Cumberland begins in Harlan Kentucky, where the Martin’s Fork, Clover Fork, and Poor Fork converge. This spot is quite easily accessible; it literally forms the back boundary of a Dairy Queen parking lot. From a hydrological standpoint, each river contributes about an equal share of water volume, so in effect there really isn’t a single headwaters, not on a human scale anyway – it’s more accurate to say the Cumberland’s source is Harlan County itself.

That all said, the very definition of “headwaters” is the most remote source of a given watercourse, even if insignificant by volume. Since the Poor Fork is the longest contributing stream, that means its source is also that of the Cumberland. All there is to be done is trace the Poor Fork until it’s nothing more than a ditch. To do this I left for Harlan KY on 2011/12/27. Apparently I wasn’t supposed to go. Out of the whole week, I picked the one day with blowing rain, sleet and fog. Then I didn’t even make it out of the house before I took a nail through my foot, but if I let that stop me I wouldn’t deserve to lace up my explorer’s gloves. Anyway, the plan was simple enough. Get to the confluence in Harlan, follow Poor Fork to its source, draw out a mental map, and take lots of pictures or video along the way. Naturally there were distractions, but that’s the point of an exploration trip, yes? These are the results:

Success:

One of two main sources of Poor Fork. Marked by a VW Bug.

Poor Fork’s ultimate source is a slight bowl shaped depression at the top of Pine Mountain along hwy 932 that collects water from numerous gulleys and puddles into two small streams. These streams converge roadside, forming the Poor Fork, which continues for some 30 miles back to the confluence at Harlan. Both streams are on private property. I was unable to get permission to explore the larger one (no one answered), but the other was in a front lawn and easily photographed. I wonder if the owner has any idea that a mud puddle under his VW Bug is the primary water source for a 680+ mile river that discharges over 225,000 gallons of per second at its terminus. I would like to Map the Martin’s Fork and Clover fork as well, but for now, mission accomplished.

Videos

Checking out the culvert where Watts Creek passes under Highway 119 along Seven Sisters Road in Bell County. Nice scenery at the far end. Also saw an interesting little cave, but it was water filled. I’ll have to come back with swimming gear and underwater lights to have a better look. Part of a personal project to survey the headwaters of Cumberland River.

Accidentally left the camera on while scouting this boat ramp access path along the Cumberland River. Figured what the heck and tossed it up.

Scouting for a picture, this where Clover, Martin’s and Poor Fork converge to form the Cumberland.

Pictures:

Various pictures taken along the way:

Let’s Explore: Old Slate Furnace, Owingsville KY – 2011_12_25

Old Slate was a road side park park located in Bath County; it’s one of the many places my grandfather would take me as part of trying to instill a sense of curiosity and adventure. Unfortunately the park is a now shadow of its former self, clearly abandoned to the elements and teenage revelers.

The furnace itself is now a graffiti muse, and all that remains of a once well kept playground/park area are some rotting picnic tables. Even so the sense of antiquity and isolation is still there, in some strange way perhaps more so. Only an occasionally passing car and soft rippling from nearby Slate Creek break the silence, both oblivious to this small piece of history they continually witness.

 

Function: ldap_verify_0001

Running this function in a given page will verify via session variables if the user is currently logged in using their Active Directory account (referred to as Link Blue by UK), and part of an authorized group. At the time of writing, I do not have access to the necessary ou containers, so groups are passed through an array parameter in the function call. Not exactly Fort Knox security, but is enough to squash spammers and stop curious onlookers. More importantly, internal customers are no longer able to skip or fudge registration information on various forms and training materials.

Action Flow

  • User in session.
    • No authorized list provided.
    • User name is found in authorized list.
      • Page loads normally.
    • User is not part of authorized list.
      • Rejection message is prepared; user is then sent to sign in page and given message.
  • User not in session.
    • Message with URL to return is prepared. user is sent to sign in page page and will be given message on successful log in.

Download

2011_11_10

Hovercraft (DCHC)

Project notes for a hovercraft/moving floor design:

Intro

It is common knowledge that almost any household appliance can perform seemingly amazing feats when properly harnessed. Who here doesn’t remember the pictures in our elementary science books of a car lift consisting of nothing more than an Electrolux ‘sausage’ vacuum and some trash bags? It’s eye opening at first, but mathematically speaking, really not hard to conceive at all. The principal is very similar to common torque multiplication; or in simpler terms, spreading out the load. So when I found myself in need of a moving floor, that very text book came to mind (Heath Science, 3rd grade, for anyone who didn’t attend Tilden Hogge in the 80’s). Grab some bags and a vacuum, plug it in and go, right? Wrong. Right off the bat I ran into some issues:

  1. How to reset? The floor needs to settle back to the original position quickly. The only escape for air in a fully sealed system as in the basic lift experiment is back through the vacuum itself. Most likely the vacuum’s blower would act as a kind of check value and make the return very slow, if at all.
  2. Exactly how were the bags connected in the first place? A single trash bag certainly wouldn’t do the job, and I simply could not fathom how multiple bags were interconnected.
  3. Multiple use. To work as I need it, the floor lift will have to be reliable; not a single function demonstrator. Again, daisy chained trash bags would be inadequate.
  4. Pressure relief. In addition to self-resetting, the floor must also be self-regulating. During work phase, the vacuum will be unattended and continue to supply air that must be bled off. Once again trash bags are not adequate; the vacuum blower will eventually fill them to bursting. Finding a bladder strong enough to withstand and ultimately block further inflow from the vacuum is also untenable. Most household vacuums use a portion of their blower’s airstream for cooling. If airflow is blocked by a full bladder apparatus, the vacuum motor will quickly overheat and fail.

As far as I know, the “car lifter” experiment deals with none of those issues, and if it does there is (or rather was) certainly no explanation. Google to the rescue!! Except, not so much. I couldn’t find anything on the specific experiment, and while there were some designs here and there, none of them suit my needs. In the end, I was left to come up with a design of my own. The biggest problem was still a check valve system. After some thought, I more or less landed on an epiphany; why not allow the air to escape from a series of holes in the bladder, using an O ring to center them in a dome shape? As the dome inflated, the holes would be sealed against the ground, giving maximum lifting strength. Afterward the whole unit would sit on a cushion of air, allowing (and requiring) a constant inflow to maintain pressure balance. It would be fully self-checking and self-resetting, just like I needed. It was only afterward I realized the design is literally a hovercraft. Duh! As an extra bonus, I had never even noticed my old shop-vac converts to a blower, not only giving me slightly more power than a common house vacuum, but also less worry about cooling, since the shop-vac’s motor has a separate cooling fan (though the hovercraft design mostly resolves cooling anyway). All that was left was to test the concept, get a design, gather the parts together and start building.

2011_09_24 – Test I, Concept

The first model is intended to and will only lift; it has no means of locomotive propulsion. It will serve as a prototype for a self propelled iteration in the future. Absolute lifting capacity is a given; what I am worried about is speed. The idea is to lift a human adult about 12cm within a few seconds of start-up. For this experiment I used the ballast bladders from my Kayak, a simple piece of wood, my own weight, and my hands as a check valve. It worked beautifully. Even with the tiny volume of air that could get through the bladder’s filler hose and nothing but my hands acting as a seal, the bag filled to capacity under 10 seconds, lifting me well off the ground in the process.

2011_09_27 – Parts

Plans Drawn, parts on the way. I should be able to get started in the next week or so. I guess it needs a name. I’ll call it the DCHC Model 1. 🙂

2011_10_18 – Model I, No Dice

DCHC Model 1 constructed, tested and… absolute failure. The skirt attachment (staples + tape) simply cannot withstand enough air pressure to lift significant weight. The center spire underneath also failed. Not such a big thing and easily fixed, but the skirt failure is an obvious deal breaker.

The first design just didn't have what it takes.

The first design just didn't have what it takes.

2011_10_23 – Model II, Final Test

Improved design with following modifications:

  • Plastic lid stapled to bottom with pencil holes replaced by cut tin disks mounted with eight screws each, ringed by six large air vents.
  • Skirt attached and sealed with combination of staples, hot glue and taping.
  • Addition of a 6cm plywood sheet mounted atop the primary deck board. This is to create a kind of sandwich effect, forming an impregnable seal to hold the skirt in place. It also has unplanned benefits of protecting the skirt assembly from tears while walking on the craft, freeing up deck space and improving the aesthetics a bit.

Testing of this second design (DCHC Model 2) proved far more successful. A minor flaw is a bit too much air escaping toward the back of the craft compared to other areas. I apparently mis-measured and cut the skirt a bit short in that area. Still, it works as intended. The craft itself weighs around 18kg and will easily lift my 90kg body weight. I’d estimate the maximum total operating capacity is around 135kg.

More to come…

DC