Fax Alert, Baseball Weather

  • Fax machines.
  • Margret
  • Baseball in Texas
  • Baseball in KY, Flemming County.
  • Lightning
  • Funnel over the hill
  • Sink holes in mud, girl, thinking of Scene in The Rescuers
  • Glass, box spring gate
  • Building maze
  • Gloves
  • Tornado

 

Found myself in an cubicle farm somewhere in Texas, with computers and Fax machines everywhere broken down and several people all shouting with angry voices at me to fix them. I set to work, frantically taking machines apart, and putting them together, mostly successful until I came upon one particular model that wouldn’t respond to my attempts. For whatever reason the entirety of that office depended on getting that one machine to work, and nothing I tried would get it working.

Finally some unidentified person said “why don’t you just get another one.” Made sense, so I stepped outside. Turns out the office was right on a Vegas like strip with blaring lights and signs. Several of these signs were about Baseball. A woman next to me remarked that no one loves their baseball like people in Texas. When I turned to look, this person as Marget Moore (Tom Moore’s mother, who is still alive and kicking at 90+ in the real world). I responded with, I don’t know, we love it an awful lot in Kentucky too…

…instantly I was at the far end of an old farm in Flemming County that belonged to Cody’s grandmother. The farm is very real and sits on a small flat halfway up the north hillside of a long east/west valley. For the most part its geography was consistent in the dream. A storm was approaching but there was a baseball game in progress. Most of the players were children, with a few adults. All were strangers to me except the catcher. In the dream I knew the catcher as a friendly acquaintance, but he doesn’t match up to anyone from real life.

As if to answer Marget’s statement about Texans loving baseball, this person said we play no matter what. Right on cue, he was nearly struck by lighting from the storm, singing his cap. He laughed it off and said nothing short of a tornado would stop their game. Sure enough, I got an eerie feeling – there wasn’t a visual cue of danger, but the air smelled wrong. After a couple of minutes checking the sky, I finally saw a funnel was beginning to form on the opposite side of the valley. It hadn’t yet materialized, but I knew we were in big trouble.

I called for my friend’s attention, and he immediately agreed we had to get everyone to a safe spot. We shouted warnings and everyone started heading for the pig sty. Along the way we had to pass through a kind of quicksand. large holes would open up randomly, and we had to carefully skip from rock to rock in order to avoid them. In the dream this seemed perfectly normal. A particularly large on opened in front of me that required skirting the fence line around its edge to get by. One of the girls told me “That one always happens to you”. I joked “yeah”, and remember thinking the hole reminded me of the tide pool hole in The Rescuers. No one had any real problems though, and we got them inside.

Once in the building, my friend and I remarked it wasn’t really going to help much, but we both knew it had a cellar that would do the trick, if we could just find the entrance. He suggested the very far end where a big pile of stuff lay. He set to getting a big pane of glass out of the way, while I laid down to get leverage to shove a set of box springs that was jammed in the space. It only took a moment for both of us. He got the glass cleared, and I was able to force the box springs forward, but doing so knocked out parts of the far wall and exposed us. It didn’t matter though, because we’d uncovered a small hole – this was the entrance and at that point everyone was going to be safe.

My friend went to go everyone gathered, and I looked down to realize I was wearing my full compliment of exploration and emergency gear, with only my gloves missing. I don’t know why, but I thought it simply wouldn’t do to not have them, and also knew my truck was parked nearby. I didn’t bother to say anything to anyone since they were safe now, and leaped outside through the collapsed wall.

The wind was horrible and there was a fog that made visibility nearly zero. Also, several other buildings were laid out in such a way that I had to maneuver around them and couldn’t see the driveway until I came round a corner. When I did, there, not 10′ in front of me was the tornado. It was no wider than a car and this seemed normal, but still stretched ground to sky like a real tornado would. As soon as I saw it I realized my life was over; there was no escape. I simply knew this.

I remember being annoyed that I was now fully isolated and alone after being around people not seconds ago. I also remember thinking I would at least take this on my own terms and tried to move forward. I couldn’t though. I’d been afflicted with that weird ream paralysis. Not only could I not get away, I couldn’t budge myself at all. I struggled to take just one step but my legs simply wouldn’t obey.

The tornado for its part was moving closer, but in circles, taking it toward then away from me. I was upset more at the total loss of dignity than anything else. I could barely even speak but after some struggle I did manage to mutter a challenge (quote): “Come on you bastard, come and get me.” It was the only defiance I could produce – no other part of my body would respond.

The funnel kept getting closer, and I kept trying to move for what seemed like several minutes. Finally it was within just a couple of feet and at that point stopped circling and started moving directly toward me. I still couldn’t move my legs, but with a last effort I was able to just lean forward and swat at it. I recall some smug satisfaction that no matter how futile my efforts (swatting at a tornado, lol), at least I wasn’t 100% helpless after all. It enveloped me immediately after and the dream ceased.

Analysis

ADHD much? This dream is clearly the result of random thoughts and interests. It is well beyond analysis, at least for an amateur such as myself.

 

Food Memior Events List

  1. First visit to Druther’s.
  2. Learn to love.
  3. Immunization/broken trust.
  4. Comfort, attachment.
  5. Separation.
  6. Reintroduction to Druther’s.
  7. Evaluation.

 

3, 1, 4, 2, 5, 7, 6

1, 2, 3, 7, 5, 4, 6 – Possible, but not “true”.

7, 6, 5, 4, 3, 2, 1 – Write thoughts first,t hen step back through order of story in reverse narrative. Could work with effort.

 

Food Memior Intoduction Workshop

Review of Food Memoir Introduction.

Look over your peer’s comments. Write a short reflection on what you plan to do in your next draft.

Both of my group members commented on my use of language and diction, or rather overuse of it. It appears I will need to tone down the level of wording used. This may prove difficult as my use of strong diction is a natural inclination, not a conscious decision.

An undercurrent was that the reading should be tailored more for a general audience.

Are your peers comments helpful? Why or why or not.

The comments themselves were well thought. Whether or not they will prove helpful hinges on my ability to follow properly.

Food Memoir

Download

2014-09-29

Caskey, Damon V
Ms. Casero, Courtney
WRD 110-038
2013-09-29

Still Rather Go to Druther’s

To you dear reader, I will start this memoir with a fair warning. If you are expecting a lengthy pontification on the joys of a specific bit of culinary delight, you are going to be disappointed. Oh there will be some gushing about the greasy breaded fowl and equally triglyceride spiking side dishes, but for the most part this is a story of trust and disappointment. Nostalgia vs. reality. Desire and progress. Or perhaps just a bit of overly dramatic exposition on of tasty fast food from a regional franchise no one outside of Kentucky likely ever heard of? I shall leave quandary that to you.

The memory of my first Druther’s exposure is nebulous at best, but I do remember it wasn’t even a Druthers’ yet. I was perhaps three years of age at my young mother’s side visiting Aunt Sanchia at the “Burger Queen”. At the time I recall finding the concept amusing. Thanks to the ubiquity of advertising, I knew of Burger King – so it only made since there would be a wife, yes? Soon after Druther’s would become Druther’s, and I would be introduced to a brand of low brow cuisine that my unrefined but discerning taste still craves to this day. I’d like to tell you more of when and how this happened, but alas the memory has been lost to a timeless ether. When I say I’ve loved Druther’s longer than I can remember, I mean it!

Alas, the innocence of youth must give away to education and progress does it not? You aren’t likely to get far in this world without a lengthy tryst in school, and you won’t certainly won’t get in the door without the dreaded immunizations. I’ve never heard of a child who didn’t shudder at the thought of needles, and I sad to say took this to new heights. My mother was a clever sort though. She knew the typical child bribes would not suffice. Candy? Ice Cream? Sure, I enjoyed those things – but if you wanted to bribe me good and proper, you had to appeal to my budding carnivore nature. The simple promise of a Druther’s Chicken dinner afterward was all it took to get me sitting stoically subdued while Dr. Caudill performed her roughshod but well-practiced exam. All was going well, and my fears were quieted by the assurance they would informed me of every step before it transpired. Unfortunately, the PA on duty (Suzie, I name I shall never forget) must have had a different idea of “informed” than I did. I will never forget the sudden searing pain in my right arm that came without sight, sound, or warning of any kind. To my everlasting shame I screamed aloud like the panicked child I was, though I did manage presence of mind not to jerk away and risk more injury. What remained of my mental faculties after processing those sensations was to be spent on one thought: I had been right all along. No one in the medical profession was to be trusted. Ever. The years since, rather than calm my suspicious, have instead provided me with a far more robust frame and acerbic jocularity to enforce them. To wit, I am a polite but less than fun patient to get stuck attending to. Fair? Maybe not, but I didn’t care then and have no plans to start any time soon. Anyone with the misfortunate of tending my wounds and calamites may thank Ms. Suzie for your troubles.

Now then, weren’t we talking about a reward of the culinary sort? With bedside manor burned and lesson learned the promise of regional pseudo fast food goodness was filled less than an hour later. Truly, I lack the appellations needed to describe the sublime experience of each bite, nor am I sufficiently adroit describing psychology subtleties to fully explain the obvious correlation of comfort vs. true taste. What I can say is the meal was and remains one of the best I ever had the privilege to sit in front of. I may have solidified a distrust for doctors, but I also learned that if you save the reward for later, any unwanted task can be turned around. Even now as I write this, I look forward to rewarding myself with this evening’s meal. Holding off until the work is complete will make it all the sweeter, just as facing the ultimately well founded fears of an immunization visit first transformed a simple meal into a grand reward.

Alas again, youth gives way once more, and so it goes like onion layers until I found myself an adult. Well, at least chronologically, even if lacking the maturity to back it up. Sadly, I had to count Druther’s as one of the many things lost along the way to that nebulous mecca of adulthood. Only a few short years after the traumatic needle stick incident, Druther’s began selling their franchises to Dairy Queen. Those that did not convert simply shuttered outright. It was a travesty of the highest order I tell you! Or so I believed. As it happens, there is still as I write this one Druther’s remaining. Cursory google searches revealed that several franchise owners in Central Kentucky knew a good thing when they had it. They purchased rights to operate with the former Druther’s name and formula, and continued their taste bud teasing operations as usual. But even these holdouts gradually dwindled, until as of today, 2014-09-29 only one remains. Situated in Campbellsville KY, it is the last Mecca for Druther’s lovers everywhere.

No sooner did I discover these facts had I made the decision to seek out and satisfy my subdued but still intense craving for Burger Queen’s spawn. It was only a two hour trip from my Lexington area domicile. Certainly nothing all that far out of the way. Yet time once again proved herself a cruel mistress. Activities and responsibilities continuous coalesced to delay my intended pilgrimage for over two years. But one cold and rainy late fall afternoon I found time and purpose enough to set forth. What better way to travel and enjoy comfort food? I love the rain and cold weather, especially when seeking out a nice meal. Somehow the verisimilitude of warm luxury inside and what most consider unwelcome weather makes any food taste better. The trip was pleasant enough; while the truck’s electronic brain futility struggled to bring economy into a two ton metal box and its three hundred horse power plant, my less binary calculations swirled around Druther’s centric childhood memories. Silly one shot moments like a cheesy “Chilly? Chilli!” sign in the window, or the literal fryolator scrapings they had the nerve to market as “Crispens” mixed and mingled with childhood nostalgia to whet the anticipation even more.

Finally, the moment arrived! I walked in the door, greeted by a comely red haired lass who identified me as a “tourist” on site. Turns out I was but one of many who wanted a little taste of Kentucky’s own take on 80’s fast food. Order was taken, and I even got a visit from the manager who liked hearing stories from visitors. Everything was perfect, just like the day I had my unsuspecting arms pierced and pumped full of chemicals I couldn’t hope to annunciate. Then I took a bite. It was good, and little else. I cannot recall being more disappointed in a meal. In my comforting nostalgia I had expected to indulge in what could only be described as salt, grease, virgin purity and the coo of white dives. Instead it was just… good.

The lesson I took from this is that even when you are aware of human frailties like nostalgia – they will take hold anyway. I knew well as anyone building up an experience too much might result in a letdown, but I did so anyway. Don’t get me wrong, it was good. Perhaps more so than I realized. That is the true failing of over anticipation. You may in fact be so disappointed or disgusted you don’t realize the thing was in fact a wonder you should be filing as a present memory rather than comparing it to the past.

Don’t even lose sight of your childhood, but nor should you allow it color your life’s perceptions as an adult. Whether old or new, see every experience for what it is rather than what you wish it to be, and you might be pleasantly surprised. I intend to go back to Druther’s soon, and next time I’ll be better prepared for the uncultured greatness that awaits me.

 


 

2014-09-20
Food Memoir First Draft

To you dear reader, I will start this memoir with a fair warning. If you are expecting a lengthy pontification on the joys of a specific bit of culinary delight, you are going to be disappointed. Oh there will be some gushing about the greasy breaded fowl and equally triglyceride spiking side dishes, but for the most part this is a story of trust and disappointment. Nostalgia vs. reality. Desire and progress.

I don’t really recall the first time I was exposed to Druther’s, but I do remember it wasn’t even a Druthers’ yet. I was maybe three years of age, on my young mother’s side visiting Aunt Sanchia at the “Burger Queen”. At the time I recall finding the concept amusing. Thanks to the ubiquity of advertising, I knew of Burger King – so it only made since there would be a wife right? Soon after Druther’s would become Druther’s, and I would be introduced to a brand of low brow cuisine that my unrefined but discerning taste still craves to this day.

Alas, the innocence of youth must give away to education and progress does it not? You aren’t likely to get far in this world without a lengthy tryst in school, and you won’t get in the door without the dreaded immunizations. I’ve never heard of a child who didn’t shudder at the thought of needles, and I sad to say took this to new heights. My mother was a clever sort though. She knew the typical child bribes would not suffice. Candy? Ice Cream? Sure, I enjoyed those things – but if you wanted to bribe me, you had to appeal to my budding carnivore nature. The simple promise of a Druther’s Chicken dinner afterward was all it took to get me sitting stoically subdued while Dr. Caudill performed her roughshod but well-practiced exam. All was going well, and my fears were quieted by the assurance they would be me informed of everything before it happened. Unfortunately, the PA on duty must have a different idea of informed than I do. I will never forget the sudden searing pain in my right arm that came without sight, sound, or warning of any kind. To my everlasting shame I screamed aloud like the panicked child I was, though I did manage presence of mind not to jerk away and risk more injury. What remained of my mental faculties after processing those sensations was to be spent on one thought: I had been right all along. No one in the medical profession was to be trusted. Ever. Fair? Maybe not, but I didn’t care then and have no plans to start any time soon.

With this bridge burned and lesson learned the promise of regional pseudo fast food goodness was filled less than an hour later. Truly, I lack the appellations needed to describe the sublime experience of each bite, nor am I sufficiently adroit describing psychology subtleties to fully explain the obvious correlation of comfort vs. true taste. What I can say is the meal was and remains one of the best I ever had the privilege to sit in front of. I may have solidified a distrust for doctors, but I also learned that if you save the reward for later, any unwanted task can be turned around. Even now as I write this, I look forward to rewarding myself with this evening’s meal. Holding off until the work is complete will make it all the sweeter, just as facing the ultimately well founded fears of an immunization visit first transformed a simple meal into a grand reward.

Alas again, youth gives way once more, and so it goes like onion layers until I found myself an adult. Well, at least chronologically, even if lacking the maturity to back it up. Sadly, I had to count Druther’s as one of the many things lost along the way to that nebulous mecca of adulthood. Or so I believed. As it happens, there is still as I write this one Druther’s remaining. No sooner did I discover this fact I had made the decision to seek them out and satisfy my subdued but still intense craving for Burger Queen’s spawn. It was only a two hour trip. Certainly nothing all that far out of the way. Yet time once again proved herself a cruel mistress. Activities and responsibilities continuous coalesced to delay my intended pilgrimage for over two years. But one cold and rainy late fall afternoon I left the comfot of my home and set forth. What better way to travel and enjoy comfort food? I love the rain and cold weather, especially when seeking out a nice meal. Somehow the verisimilitude of warm comfort inside and what most consider “unpleasant” makes any food taste better. The trip was pleasant enough; while the truck’s electronic brain futility struggled to bring economy into a two ton metal box and its three hundred horse power plant, my less binary calculations swirled around Druther’s centric childhood memories. Silly one shot moments like a cheesy “Chilly? Chilli!” sign in the window, or the literal fryolator scrapings they had the nerve to market as “Crispens” mixed and mingled with childhood nostalgia to whet the anticipation even more.

Finally, the moment arrived! I walked in the door, greeted by a comely red haired lass who identified me as a “tourist” on site. Turns out I was but one of many who wanted a little taste of Kentucky’s own take on 80’s fast food. Order was taken, and I even got a visit from the manager who liked hearing stories from visitors. Everything was perfect. Just like the day I had my unsuspecting arms pierced and pumped full of chemicals I couldn’t hope to annunciate. Then I took a bite. It was good. I cannot recall being more disappointed in a meal. In my comforting nostalgia I had expected to bite into what could only be described as salt, grease, virgin’s blood and the coo of a white dive. Instead it was just… good.

The lesson I took from this is that even when you are aware of human frailties like nostalgia – they will take hold anyway. I knew well as anyone building up an experience too much might result in a letdown, but I did so anyway. Don’t get me wrong, it was good. Perhaps more so that I realize. That is the true failing of over anticipation. You may in fact be so disappointed or disgusted you don’t realize the thing was in fact a wonder you should be filing as a present memory rather than comparing it to the past.

Don’t even lose sight of your childhood, but don’t like it color your life as an adult. Whether old or new, see every experience for what it is rather than what you wish it to be, and you might be pleasantly surprised. I intended to go back to Druther’s soon, and next time I’ll be better prepared for waiting greatness.

 

PHP Object Oriented Request Data

PHP

This article assumes LAMP or other PHP based web layout, and basic proficiency with Object Oriented PHP scripting.

Have you ever found yourself wanting to use OOP methods in PHP but found it frustrating due to the rather bolted on nature of object support? In particular, dealing with outside data arrays like $_POST and $_GET?

Since the advent of OOP support in PHP, it doesn’t take long to get spoiled by the type hinting and name space advantages OOP offers (I’ll leave the other benefits to be debated by the ever on going Procedural vs OOP soldiers still at war out there).

The problems come when you have to start processing uncontrolled outside data, and as mentioned above, one of the biggest offenders is request data from the client. The moment this occurs – pretty much the moment you build any website, your nice clean OOP concept goes right out the window. Type hinting and automated error checking quickly follow suit. How do we fix this? Let’s start with our goals:

  • Type hinting. Without type hinting, powerful IDEs like Dreamweaver are little more than very expensive text editors.
  • Deal with missing variables. Even with validation, there are times, perhaps by design when some incoming variables might not have a value assigned.
  • Avoiding repetition. Re typing array keys over and over isn’t just inconvenient. You’re practically begging to insert hard to locate typo bugs in the code.

 

Now with those objectives in mind, it’s easy to see the first two could be solved by grouping our variables into an object. The real question is how to get them there and avoid repetitious code.

For a working example let’s assume we have an incoming form post with the following fields:

  • First Name
  • Last Name
  • E-mail
  • Phone

 

We’ll use the HTML5 required attribute and JavaScript validation to make sure most of the fields are filled out, but we want “Phone” to be optional. This is all well and good, but as any experienced developer is aware, you can never, EVER trust client side validation. So even without an optionally blank field, we’re going to have to ensure missing variables are initialized on post.

Let’s try a couple of solutions and evaluate them vs. our criteria. For this article, we’re going to use $_REQUEST. If you aren’t familiar, $_REQUEST is a handy single command that acquires all values you’d normally get from $_GET, $_POST and $_COOKIE.

 Standard Object

// Initialize standard object with request array.
$request = object($_REQUEST);

// Do stuff...

 

On the surface this is a beautifully elegant solution. The PHP Standard Object initializes with $_REQUEST in a single line, and any $_REQUEST vars are now available as data members.

Unfortunately, this method has two serious drawbacks.

  1. Firstly, Standard Object has no methods for our members. All we’ve really accomplished is shifting a bunch of data from one global space to another with no validation or protection. Might be quick and easy, but it’s nothing close to an object oriented solution and will inevitably bite us in the butt at some point.
  2. Any missing $_REQUEST vars stay missing. The Standard Object can’t include what isn’t there to begin with. To solve that issue you might try this:
// If any post vars are missing, populate them with NULL.
if(!isset($_REQUEST['name_f']))     $_REQUEST['name_f']     = NULL;
if(!isset($_REQUEST['name_l']))     $_REQUEST['name_l']     = NULL;
if(!isset($_REQUEST['mail']))       $_REQUEST['mail']       = NULL;
if(!isset($_REQUEST['phone']))      $_REQUEST['phone']      = NULL;

// Initialize standard object with post array.
$post = object(<a title="$_REQUEST" href="http://php.net/manual/en/reserved.variables.request.php" target="_blank"><em>$_REQUEST</em></a>);

// Do stuff...

 

With this technique we insert blank values into $_REQUEST before initializing Standard Object, and solve the missing variable issue. Unfortunately we’ve exchanged one problem for another: Now we have to repeat every key twice. Lastly, we’ve also done nothing about type hinting. Conclusion? Not with the hassle.

Custom Class, Populate Members Individually In Constructor

class request
{
    private
        $name_f    = NULL, // First name.
        $name_l = NULL, // Last name.
        $mail    = NULL, // Email.
        $phone  = NULL; // Phone number.
    
    // Class constructor
    public function __construct()
    {
        $this->populate_members();
    }
    
    private function populate_members()
    {
        if(isset($_REQUEST['name_f']))    $this->name_f    = $_REQUEST['name_f'];
        if(isset($_REQUEST['name_l']))    $this->name_l    = $_REQUEST['name_l'];
        if(isset($_REQUEST['mail']))      $this->mail      = $_REQUEST['mail'];
        if(isset($_REQUEST['phone']))     $this->phone     = $_REQUEST['phone'];
    }
    
    // Accessors
    public function get_name_f()
    {
        $return $this->name_f;
    }
    ...
    
    // Mutators 
    public function set_name_f($value)
    {
        $this->name_f = $value;
    }
    ...
}

// Initialize class object.
$post = new post();

// Do stuff...

 

This is a little better. By writing our own class and running a function that populates piecemeal in the constructor, we get type hinting from our IDE and all of our variable instantiate work is packaged up. One problem remains – we still have to type every identifier three times at minimum. That’s a bug just waiting to happen. It’s a good start though, so let’s build on it a bit with the method below:

Custom Class, Dynamic Population

class request
{
    private
        $name_f    = NULL, // First name.
        $name_l = NULL, // Last name.
        $mail    = NULL, // Email.
        $phone  = NULL; // Phone number.
    
    // Class constructor
    public function __construct()
    {
        $this->populate_members();
    }
    
    private function populate_members()
    {
        // Iterate through each class variable.
        foreach($this as $key => $value)
        {            
            // If we can find a matching a post var with key matching
            // key of current object var, set object var to the post value.
            if(isset($_POST[$key]))
            {                    
                $this->$key = $_POST[$key];                                   
            }
        } 
    }
    
    // Accessors
    public function get_name_f()
    {
        $return $this->name_f;
    }
    ...
    
    // Mutators 
    public function set_name_f($value)
    {
        $this->name_f = $value;
    }
    ...
}

// Initialize object.
$post = new post();

// Do stuff...

 

Now we’re in business! This might look a bit complex at first glance, but it’s really the simplest of all attempts thus far. More importantly it provides everything we asked for and then some.

Let’s look closer at the populate_members() method and see what’s going on:

foreach($this as $key => $value)

 

PHP allows us to loop through all the data members of an object just as if it were an array (this has other uses elsewhere, more on that in another article). We can even key the data member’s name as a string just as if it were an array key, and that’s what we’re leveraging for a dynamic data member population. FYI, we really don’t care about $value here, it’s just a necessary filler syntax.

if(isset($_REQUEST[$key]))
{                    
    $this->$key = $_POST[$key];                                   
}

 

Now in each loop we use the value of $key as an string array key for $_POST and evaluate it with isset(). If isset() returns TRUE, we know the value exists. All that’s needed is to populate the corresponding data member with that $_POST value. Again, PHP helps us out; it is perfectly legal to pass string variables as a data member id at run time.

Once the loop is completed, all $_REQUEST keys that have a matching data member will have been located and the data members populated. Any missing $_REQUEST values are simply ignored; we already established a default value for their corresponding data members.

At this point all conditions have been met. Your IDE will provide type hinting and error checking. Variables are only entered once as data member names. Missing $_REQUEST values are dealt with elegantly. No helper code outside of the class is needed. Best of all, this concept isn’t limited to $_REQUEST at all. Any array array is also fair game.

We could stop right here, but unfortunately there’s just one little flaw remaining. Elegant as it is, this solution fully bypasses the object’s mutator methods, and in the process throws best practice data validation right out the window. There’s nothing stopping you from putting some data validation into the loop (or ignoring best practice), but with just a little more front end work, you can leverage your mutators and keep all of the data validation encapsulated.

Custom Class, Dynamic Mutation

 

class request
{
    private
        $name_f    = NULL, // First name.
        $name_l = NULL, // Last name.
        $mail    = NULL, // Email.
        $phone  = NULL; // Phone number.
    
    // Class constructor
    public function __construct()
    {
        $this->populate_members();
    }
    
    private function populate_members()
    {
        // Interate through each class variable.
	foreach($this as $key => $value) 
	{			
		// If we can find a matching a post var with key matching
		// key of current object var, set object var to the post value. 
		if(isset($_REQUEST[$key]))
		{
			// Add 'set_' prefix so member name is now a mutator method name.
			$method = 'set_'.$key;
				
			// If a mutator method by the current name exists, run it and
			// pass current request value. 
			if(method_exists($this, $method)=== TRUE)
			{										
				$this->$method($_REQUEST[$key]);
			}
		}
	} 
    }
    
    // Accessors
    public function get_name_f()
    {
        $return $this->name_f;
    }
    ...
    
    // Mutators 
    public function set_name_f($value)
    {
        $this->name_f = $value;
    }
    ...
}

 

This looks and works very similar to the above method, but instead of populating members directly, values are routed through the object’s mutator methods. This does double duty of encapsulating validation and providing a secondary gateway to control just which members you want populated at all.

The secret is that PHP allows you to reference methods by string at run time just it it does members. First, we use a bit of string manipulation to get a member name from our $_REQUEST name. I use a prefix of “set_” for my mutators, so it’s a simple matter of tacking that on to a placeholder variable.

// Add 'set_' prefix so member name is now a mutator method name.
$method = 'set_'.$key;

Next, we will need to make sure the method exists. PHP will immediately halt the script and throw a fatal error if an attempt is made to call non-existent methods, so this check is vital. If the check passes, we use the string to call out mutate method and pass it our $_REQUEST value. Notice how the member’s signature is NOT part of the string – treat it exactly as you would any hard coded member’s signature.

// If a mutator method by the current name exists, run it and
// pass current request value. 
if(method_exists($this, $method)=== TRUE)
{										
	$this->$method($_REQUEST[$key]);
}

Now we truly are ready. All of our $_REQUEST data is packaged into a fully encapsulated object with elegant evaluation and gateways. Our IDE will now provide us with type hinting and error checking, plus all of the code is reusable and double keying has been kept to the bare minimum. No more hidden typos, mystery variables, and annoying PHP notice errors!

Give it a try, season to taste and enjoy.

Until next time!
DC

Define Food Memoir

Q: Based off of your reading of Foer’s Storytelling, what is a food memoir? 

It’s hardly a clever conclusion to draw, but in reading Jonathan Foer’s work, I found the so-called “food memoir” functions less as a strict genre and more as a storytelling framework used to explore broader ideas. Food, in this case, feels more like a vessel than a theme. It becomes a subject through which the author delivers philosophical, emotional, and ethical commentary.

In my view, you could replace food with children, cars, religion, or nearly any other personally meaningful topic, and the structure of the narrative – even much of its tone – would remain intact. That suggests the story isn’t truly about food alone. It’s about belief, identity, and internal conflict. Food just happens to be the chosen lens.

Definition

A food memoir is a general memoir in which food serves as the narrative entry point – not necessarily the defining focus. It is one of many interchangeable subjects used to explore deeper personal or cultural themes.

Reading Response – Critiquing Eating Animals

WRD 110 – Reading Response

Almost immediately upon starting the assigned reading from Eating Animals, I found myself waiting for the inevitable payoff – the explosive thought bomb. It’s a common narrative device: begin with what seems like a non-sequitur, let the reader’s curiosity simmer, then deliver a sudden pivot meant to jolt the audience into a new frame of mind. The tactic worked. The opening tale circles around to a hard-hitting line – “If nothing matters, there’s nothing to save” – intended to anchor the reader emotionally. While I agree with the sentiment, I couldn’t help but feel it was also a pointed nudge – a soft coercion toward accepting the author’s moral authority.

That moral authority, while never overtly declared, is unmistakable: eating animals is wrong. Foer insists the work is not meant to convert or judge. Yet throughout the essay, the problems with eating meat are detailed with care, while the arguments in favor of it are barely addressed or brushed aside. What is presented as introspection often reads as confession. Foer’s tone is that of a man striving for an ideal he already accepts as correct – vegetarianism. His struggle is not about whether the ideal is valid, but about whether he can live up to it. What I find troubling is that the premise itself – that abstaining from animal consumption is morally superior – is never actually questioned. It is simply treated as a moral default, a virtue one must aspire to. This leaves little space for open dialogue.

Rather than challenge that ideal with personal narrative, I’ll instead lean into what matters most in effective communication: knowing your audience. Our class is diverse, and opinions about food – particularly ethical food choices – vary widely. Some students strongly support Foer’s conclusions. Others, myself included, are less convinced. This isn’t a simple discussion, and to unpack the full debate would go well beyond the scope of a single response. Instead, I would encourage a close and critical reading of the piece and invite you to consider the following:

  • Did you find the work pragmatically informative, emotionally persuasive, or both?
  • What types of evidence were offered to support the author’s point of view?
  • If you were to communicate the same message, what changes – if any – would you make to improve its reception across a broader audience?

Thank you for taking the time to consider this response.

Salary Rec System

Following notes taken from http://www.caskeys.com/db_salary_rec_system_001.html (page now deleted).

The Salary Rec System is an application designed and built by Damon Vaughn Caskey at the request of Roxie Alison. It’s primary purpose is to assist in submitting salary approval requests to HR.

  • Live as of 03/01/2007.
  • Architecture consists of local self contained MS Access 2003 .mdb file connected to MS SQL database via ODBC file dsn (See below).
  • As of 07/23/2007, all documentation and relevant files can be located at: file://internalmed/ooc/db/salary_rec

Front End:       

  • All functions are VB based; included macros are for startup and testing only.
  • MS 2003 .mdb file format.

Back End:

  • MSSQL 2000
  • Stemsoft server
  • ODBC file dsn

GoPro Desktop Mount

A seemingly simple but often annoying configuring issue is mounting cameras to record a desktop project. One example would be drawings such as this sketch series.

Integrated laptop cams make an OK substitute, but there are times when better resolution is needed. My GorPro cam would be perfect, as it records in standard 1080p and is much more suited to long sequences than a phone, but the included outfitting is of little use for any sort of table mounting. In short, I needed a simple and stable way to mount the GoPro camera for desktop projects. Obviously I wanted to ensure the camera stayed readily available ready for its intended purpose (outdoor excursions), so it was imperative to allow instant snap in and removal with absolutely no modifications to the unit or its factory mounts.

I found a solution in some old Capsella parts I got for Christmas a few years ago. A quick bit of tinkering gave me this little tripodal platform. It’s stable, mobile and easily adjustable for different angles. I don’t have to dissemble anything to mount or remove – the camera simply slides right in and while mounted all controls/ports are fully accessible.

Perhaps the best part? It’s Capsella. I mean come on! A nerd-rigged mount to record nerd projects? Yes please!

mount_0001 mount_0002

Let’s Explore – Druther’s Restaurant

Pop quiz, what’s the best way to bribe a normally well behaved but cripplingly trypanophobic youth into cooperating with immunizations?

Candy?

Ice Cream?

Toys?

Yeah right. I can proudly say my wants were not so provincial, even then. Oh but I did have my weakness, and my mother knew it all too well. A chicken dinner from Druthers? SOLD.

Fast forward a few years, and I bet most of my contemporaries from Morehead will have similar memories to my own – like walking over from middle school to grab some “Crispens” for $0.59. Not even Long John Silver’s had the audacity to charge you half a dollar for leftover grease scraped out of the fryolator. No, only Druther’s could be so bold.

Unfortunately all good things must come to an end. Starting in 1989 and continuing through 1992 nearly every Druther’s restaurant was converted to Dairy Queen or shut down outright, and at least for most of us Druther’s disappeared off the map. An interesting note is that the Druther’s holding company (Druther’s Systems Inc.) never went anywhere and in fact retained ownership of most converted locations until the mid nighties.

In any case, a few of the franchise owners (mostly in central/western Kentucky) purchased their respective locations from Druther’s Systems and continued to operate. Sadly though, only one of these independent operations remains: The Campbellsville Druther’s.

After learning all of this, I had long decided a pilgrimage should be made, and today seemed good as any. I’d just as soon forget the last few weeks, and what better to clear one’s mind than a road trip?

What I found was a throwback that isn’t just holding on, but going strong. The staff was openly amused by my touristy antics, and as I sat down to eat the manager even came out to meet me – he was quite curious to hear my “Druther’s Story”. He went on to explain that quite a few people come from far off places just to visit the last Druther’s hold out. How cool is that? It also makes one wonder why Druther’s Systems was so willing to throw a great business model away. By all appearances it had worked fine all the way back to the days of Burger Queen (Druther’s original name FYI). Guess we’ll never know.

For those who have never been to a Druther’s, I lack the writing acumen to really bring such an oddity to life. Instead I would best describe it as a bizarre melding of your favorite breakfast spot, a local greasy spoon, and KFC. It’s neither sit down nor fast food, occupying an odd niche in between. Throwing out the nostalgia filter, is it really worth a two-hour trip? For most people I’d probably say no. Still, the food was good, the service excellent and were a Druther’s nearby I would certainly frequent it often. It’s definitely worth a one time visit for memory sake, or to try something unique on a weekend afternoon. They will certainly be seeing more of me. Two thumbs up for simple pleasures!

Druhter’s Restaurant
101 North Columbia Ave.
Campbellsville Ky 42718

Lists and PHP Range

PHP

This article assumes LAMP or other PHP based web layout, and basic proficiency with PHP scripting.

Imagine you’ve just finished one of those simple but massive and often tedious alphabetical link lists or tables all of us in the web business are called upon to assemble at some point. You know the customer will appreciate the convenience of anchors and bookmark links. On the surface it would appear you have the less than fun choices of cobbling together a cumbersome loop to generate your links, or to type and double check each one by hand. Fortunately as of PHP version 4.0 there is a better option: Range.

Range is an oft overlooked and very useful function that will accept two bookends and return an array containing the in between values in order (bookends included).

For an example, to get the set of letter bookmark links at the top of this page, we could do it the hard way:

<a href="#A">A</a>
<a href="#B">B</a>
<a href="#C">C</a>

We could also write some home grown functions, probably involving a nested loop or two. But why do either when we could get the same result like this?

$markup = NULL;     // List markup.
$letter = NULL;     // Letter placeholder.
$range  = array();  // Range array.
 
// Get range array, A to Z.
$range = range('A', 'Z');
 
// Loop range array.
foreach ($range as $letter)
{
    // Build link list markup.
    $markup .= '<a href="#'.$letter.'">'.$letter.'</a> '; 
} 
// Output markup 
echo $list; 

Simple, elegant, reusable, and best of all it’s far less prone to human error. Either the whole list works or none of it will, in which case you will know right away without the need to check each link individually.

Try your own experiments with range; it is quite versatile and extremely powerful in the right hands. It’s nothing you couldn’t do piecemeal or with custom solutions, but will most certainly simplify the process – freeing up your efforts for far more worthy causes.

Until next time!
DC

Page – Main

<?php require_once($_SERVER['DOCUMENT_ROOT']."/libraries/php/classes/config.php"); //Basic configuration file. ?>


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>UK - Environmental Health And Safety</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<link rel="stylesheet" href="libraries/css/style.css" type="text/css" />
<link rel="stylesheet" href="libraries/css/print.css" type="text/css" media="print" />
</head>

<body>

<div id="container">
	<div id="mainNavigation">
		<?php include($cDocroot."libraries/includes/inc_mainnav_0001.php"); ?>
	</div>
	<div id="subContainer">
		<?php include("a_banner_0001.php"); ?>
		<div id="subNavigation">
		 	<?php include("a_subnav_0001.php"); ?> 
		</div>
		<div id="content">
			<p class="header">Welcome</p>
		  <p>Welcome to the University of Kentucky's Environmental Health And Safety Division. UK safety begins with you!</p>
		  <p class="sub_header">OUR MISSION</p>
		  <p>The EHS Division supports   the University's teaching, research, and public service mission by   promoting a safe, healthful, clean, and accessible campus environment.</p>
		  <p>The Division's   programs are intended to provide safe and healthy conditions for work   and study, protect the environment, and comply with applicable laws and   regulations.  The Division serves the University community by providing   technical services, education and training, periodic audits, and   compliance assistance.</p>
		 
	      <?php include($cDocroot."libraries/includes/inc_updates_0001.php"); ?>
	  </div>       
	</div>    
		<div id="sidePanel">		
			<?php include($cDocroot."a_sidepanel_0001.php"); ?>		
		</div>
	<div id="footer">
		<?php include($cDocroot."libraries/includes/inc_footer_0001.php"); ?>		
	</div>
</div>

<div id="footerPad">
<?php include($cDocroot."libraries/includes/inc_footerpad_0001.php"); ?>
</div>
</body>
</html>

Class – Utility

<?php 

class class_utility {

	/*
	Utility
	Damon Vaughn Caskey
	2013-01-09
	
	Miscellaneous utility functions.
	*/
	
	public function utl_color_alternation($i, $cColorEven="#DDDDFF", $cColorOdd="#CECEFF")
	{		
		/*
		back_alt_0001 - https://www.caskeys.com/dc/?p=4900
		Damon Vaughn Caskey
		2012-10-18
		
		Output alternating background colors for even/odd rows in tables or other types of layouts.
		
		$i:				Current row/location/count. 
		$cColorEven:	Color to output if $i is an even number.
		$cColorEven:	Color to output if $i is an odd number.
		*/
		
		if($i%2)				//Even number?
		{				
			return $cColorEven;	//Return even color.
		}
		else
		{	
			return $cColorOdd;	//Return odd color.
		}
	}
	
	public function utl_get_get($cID, $cDefault=NULL)
	{
		/*
		utl_get_get
		Damon Vaughn Caskey
		2013-01-01
		
		Wrapper to obtain get value.
		
		$cID:		Index.
		$cDefault:	Default on not set.
		*/
		
		return $this->utl_validate_isset($_GET[$cID], $cDefault);
	}
	
	public function utl_get_post($cID, $cDefault=NULL)
	{
		/*
		utl_get_post
		Damon Vaughn Caskey
		2013-01-01
		
		Wrapper to obtain post value.
		
		$cID:		Index.
		$cDefault:	Default on not set.
		*/
		//echo $_POST[$cID];
		
		return $this->utl_validate_isset($_POST[$cID], $cDefault);
	}
	
	public function utl_get_server_value($cID, $cDefault=NULL)
	{
		/*
		utl_get_server_value
		Damon Vaughn Caskey
		2013-01-01
		
		Wrapper to obtain server value.
		
		$cID:		Index.
		$cDefault:	Default on not set.
		*/
		
		return $this->utl_validate_isset($_SERVER[$cID], $cDefault);
	}
	
	public function utl_str_to_array($cList=NULL, $cDel=",")
	{	
		/*
		str_to_array
		Damon Vaughn Caskey
		2013-01-09
		
		Break string into indexed array with no spaces.
		
		$cList:	List array to break up.
		$cDel:	Delimiter.
		*/
	
		/*
		If list is populated remove spaces and break into array.
		*/
		if($cList)									//List populated?								
		{
			$cList = str_replace (" ", "", $cList);	//Remove spaces.
			$cList = explode($cDel, $cList);		//Break into array.
		}
		
		/*
		Return end result.
		*/
		return $cList;
	}
	
	public function utl_redirect($cURL=NULL)
	{	
		/*
		utl_redirect
		Damon Vaughn Caskey
		2013-01-09
		
		Send header that redirects client to new page.
		
		$cURL:	Target address.
		*/

		/*
		If headers haven't been sent, redirect user to an error page. Otherwise we'll just have to die and settle for a plain text message.
		*/
		
		if(headers_sent())
		{ 
			/*
			Good coding will always avoid attempting to resend headers, but let's make sure to catch them here before PHP throws a nasty error.
			*/			
		}
		else
		{			
			header('Location: '.$cURL);
			return TRUE;
		}
		
		/*
		Return end result.
		*/
		return FALSE;
	}
	
	public function utl_validate_email(&$cValue, $cDefault=NULL)
	{
		/*
		utl_validate_email
		Damon Vaughn Caskey
		2013_01_01
		
		Validate email variable.
		
		$cValue:	Email value.
		$cDefault:	Default on fail.
		*/
				
		if(filter_var($cValue, FILTER_VALIDATE_EMAIL)) 
		{			
			list($user,$domaine)=explode("@", $cValue, 2);
			
			if(!checkdnsrr($domaine, "MX")&& !checkdnsrr($domaine, "A"))
			{
				/*
				Bad domain.
				*/
				$cValue = FALSE;
			}
			else 
			{
				//Domain OK.
			}
		}
		else 
		{		
			/*
			Bad address.
			*/	
			$cValue = FALSE;
		} 
		
		if($cValue == FALSE)
		{
			$cValue = $cDefault;
		}
		
		return $cValue;
	}
	
	public function utl_validate_ip(&$cValue, $cDefault=NULL)
	{
		/*
		utl_validate_ip
		Damon Vaughn Caskey
		2013-01-01
		
		Validate ip variable.
		
		$cValue:	ip value.
		$cDefault:	Default on fail.
		*/
		
		$cValue = filter_var($cValue, FILTER_VALIDATE_IP);		
		
		if($cValue == FALSE)
		{
			$cValue = $cDefault;
		}
		
		return $cValue;
	}
	
	public function utl_validate_isset(&$cValue, $cDefault=NULL)
	{
		/*
		utl_validate_isset
		Damon Vaughn Caskey
		2013-01-01
		
		Return default if variable is not set.
		
		$cValue:	Value.
		$cDefault:	Default on not set.
		*/
		
		if(!isset($cValue))
		{
			$cValue = $cDefault;
		}
		
		return $cValue;
	}
	
	public function utl_if_exists($cValue, $cValPrefix=NULL, $cValCadence=NULL, $cAlt=NULL)
	{
		/*
		utl_
		Damon Vaughn Caskey
		2013-01-01
		
		Return self if self has a value, or $cAlt if $cValue is empty or null. Reduces need to retype and 
		potentiality mix up variable names or array keys twice in common "echo <X> if it has a value" situations.

		Preconditions:
			$cValue: Value to test and return if it exists.
			$cValPrefix: Add to front of $cValue on return.
			$cValCadence: Add to end of $cValue on return.
			$cAlt: Value to return if $cValue is NULL.
		*/
		
		/* Vaiables */
		$cReturn = $cAlt;	//Final value to return.
		
		/* Value exists? */
		if($cValue)
		{
			/* Tack on additions and return value. */			
			$cReturn = $cValPrefix.$cValue.$cValCadence;
		}
		
		return $cReturn;		
	}
}
?>



Class – Training

<?php

class class_training
{    

	/*
	constants
	Damon Vaughn Caskey
	2012_12_18
	
	Global constants. 
	*/		
		
	private	$oDB		= NULL;	//Class object: Database.
	private $oDBA		= NULL;	//Class object: Database (answers).
	private $oSes		= NULL;	//Class object: Session.
	private	$oUtl		= NULL;	//Class object: Filter.
	private	$oErr		= NULL;	//Class object: Error.
	private $oFrm		= NULL;	//Class object: Forms. 		
	private $cQuery		= NULL;
	private $cParams	= NULL;
	private $cTVarsTD	= NULL;	//Class variable ID array.
	private $cTVars		= NULL;
	
	function __construct($oDep)
	{
		/*
		Constructor
		Damon Vaughn Caskey
		2012_12_29
		
		Class constructor.
		*/
		
		/* Import object dependencies. */
		$this->oSes	= $oDep['Ses'];
		$this->oDB 	= $oDep['DB'];
		$this->oFrm	= $oDep['Frm'];
		$this->oFil	= $oDep['Fil'];
		$this->oErr	= $oDep['Err'];
		$this->oDBA	= new class_db(array('Utl' => $oDep['Utl'], 'Err' => $oDep['Err']));
				
		/* Verify object dependencies. */
		if(!$this->oDBA)	trigger_error("Missing object dependency: Database (Ans).", E_USER_ERROR);
		if(!$this->oDB)		trigger_error("Missing object dependency: Database.", E_USER_ERROR);
		if(!$this->oSes)	trigger_error("Missing object dependency: Session.", E_USER_ERROR);	
		if(!$this->oFrm)	trigger_error("Missing object dependency: Forms.", E_USER_ERROR);	
		if(!$this->oFil)	trigger_error("Missing object dependency: Filter.", E_USER_ERROR);		
		if(!$this->oErr)	trigger_error("Missing object dependency: Error.", E_USER_ERROR);		
	}
	
	public function training_quiz_grade($cQuizID)
	{
		$cQuestionCount = NULL;
		$cQuestionRight = NULL;	
		$val			= NULL;	
		$iQueCnt		= 0;
		$cResponse		= NULL;
		$cQuizGradeStr	= NULL;
		$ans			= 0;
		$cPercentage	= 0;
								
		$cQuestionCount = $this->oSes->session_get('quiz_question_count');
		$cQuestionRight = $this->oSes->session_get('quiz_answer_right');
		
		$cQuestionRight = str_replace (" ", "", $cQuestionRight);	//Remove spaces.
		$cQuestionRight = explode(",", $cQuestionRight);			//Break into array.
		
		foreach($cQuestionRight as $val)				//Loop array collection.
		{		
			/* Increment counter. */
			$iQueCnt++;					
			
			/* Get question response */
			$cResponse = $this->oFil->utl_get_post("Q".$iQueCnt);
							
			$cQuizGradeStr.= "Question ".$iQueCnt." response: ";	
			
			if (!$cResponse)
			{
				$cQuizGradeStr.= "No answer.<br/>";
			}
			else				
			{
				if ($cResponse == $val)
				{
					$cQuizGradeStr.= $cResponse." - Correct.<br/>";
					$ans++;
				}
				else
				{
					$cQuizGradeStr.= $cResponse." - Incorrect.<br/>";					
				}	
			}							
		}
		
		$cPercentage	= round(($ans / $iQueCnt)*100);
			
		$cQuizGradeStr.= "<br />You answered ".$ans. " of ".$iQueCnt. " correctly (".$cPercentage."%).<br /><br />";
					
		$array["ans"] 			= $ans;
		$array["percentage"] 	= $cPercentage;
        $array["text"] 			= $cQuizGradeStr;
        			
		return $array;		
		
	}
		
	public function training_quiz_questions($cQuizID, $cOrder=NULL, $cQuantity=NULL)
	{
		/*
		training_quiz_questions
		Damon V. Caskey
		2011_11_29
		~2012_12_23: DB Class.
		
		Populate question list and possible answers from database from Quiz ID.
		
		$cQuizID:	Quiz ID to get quiz questions from. 
		*/		
  					
		$cQuizStr 			= NULL;								//Final output string to be placed into page.
		$QuestionID			= NULL;								//Current question ID in question loop.	
		$cQuestionCount		= 0;								//Include ID into question header.		
		$cQuestionRight		= NULL;								
				
		if(!$cOrder)
		{
			$cOrder = NULL;	//Order in table.	
		}
		else if($cOrder == 1)
		{
			$cOrder = "ORDER BY	question_order";	//User specified order.
		}
		else if($cOrder == 2)
		{
			$cOrder = "ORDER BY	newid()";	//Random order	
		}
		
		$cQuantity = $cQuantity ? "TOP ".$cQuantity : NULL;
		
		/* Construct questions query string. */
		$this->cQuery = "SELECT "
			.$cQuantity
			." *
			FROM 		tbl_class_train_questions
			WHERE		fk_tbl_class_train_parameters_guid_id = ? "
			.$cOrder;	
		
		/* Apply parameters. */
		$this->cParams = array(&$cQuizID);
		
		/* Execute questions query. */
		$this->oDB->db_basic_select($this->cQuery, $this->cParams);
		
		/* Construct answers query string. */
		$this->cQuery = "SELECT 
			* 
			FROM 	tbl_class_train_answers
			WHERE	fk_tbl_class_train_questions_guid_id = ?
			ORDER BY answer_order, value";
		
		/* Apply parameters. */
		$this->cParams = array(&$QuestionID);
		
		while($this->oDB->db_line())
		{
			$QuestionID = $this->oDB->cDBLine["guid_id"];
			
			/*	Get answer set matching current question ID. */
			$this->cParams = array(&$QuestionID);
			
			/*Record answer array. First element will be blank. ( ", A, C, B, A, etc.") */
			if($cQuestionRight)
			{
				$cQuestionRight .= ", " .$this->oDB->cDBLine["right_answer"];
			}
			else
			{
				$cQuestionRight = $this->oDB->cDBLine["right_answer"];
			}
			
			/* Build question string. */
			$cQuizStr 	.="<p><span class='TrainQuestionHeader'>"
						."Question ".++$cQuestionCount			
						."</span><br />"
						."<span class='TrainQuestionText'>"			
						.$this->oDB->cDBLine["question"]		
						."</span><br />";			
			
			/* Execute answers query. */
			$this->oDBA->db_basic_select($this->cQuery, $this->cParams);
			
			while ($this->oDBA->db_line())
    		{			
				$cQuizStr	.=	"<input type='radio' name='Q"					
							.$cQuestionCount							
							."' value='"	
							.$this->oDBA->cDBLine["value"]	
							."' />"
							."<span class='TrainQuestionAnswerHeader'>"									
							.$this->oDBA->cDBLine["value"]
							.")</span> "
							."<span class='TrainQuestionAnswerText'>"										
							.$this->oDBA->cDBLine["text"]
							."</span><br />";							
			}						
		}			
		
		if(!$cQuizStr)
		{
			$cQuizStr = "<h2><span class='alert'>No questions available.</span></h2>";
		}
		
		$this->oSes->session_set('quiz_answer_right', $cQuestionRight);
		$this->oSes->session_set('quiz_question_count', $cQuestionCount);
				
		return $cQuizStr;
	}
	
	public function training_quiz_questions_setup($cQuizID, $cOrder=NULL, $cQuantity=NULL)
	{		
		/*
		class_quiz_questions_0003
		Damon V. Caskey
		2012_10_04
		
		Create form to modifiy questions and answers.
		
		$cQuizID:	Quiz ID to get quiz questions from. 
		*/		
  			
		$cQuizStr 			= NULL;								//Final output string to be placed into page.
		$cQuery				= NULL;								//Query string.
		$cParams			= NULL;								//Parameter array.
		$oDBA				= NULL;								//Database class object (answers). 
		$QuestionID			= NULL;								//Current question ID in question loop.	
		$cOrderLst			= NULL;								//Droplist values for question order.
		$cAnswerValLst		= NULL;
		
		/* Initialize database class objects. */
		$oDBA	= new class_db(array("Utl" => $oUtl, "Err" => $oErr));					//Database class object (Answers).
		
		/* Prepare answer dropdown list values */
		$cAnswerValLst 		= array_merge(array("-" => "-"), range('A', 'Z'));
				
		/* Construct questions query. */
		$cQuery = "SELECT "
			.$cQuantity
			." *
			FROM 		tbl_class_train_questions
			WHERE		fk_tbl_class_train_parameters_guid_id = ? 
			ORDER BY	question_order";	
						
		/* Apply question parameters. */
		$cParams = array(&$cQuizID);
		
		/* Execute questions query */
		$oDB->db_basic_select($cQuery, $cParams);						
		
		$cQuery = "SELECT 
						* 
						FROM 	tbl_class_train_answers
						WHERE	fk_tbl_class_train_questions_guid_id = ?
						ORDER BY answer_order, value";
		
		/* Apply answer parameters. */
		$cParams = array(&$QuestionID);
		
		/* Prepare question order dropdown list values */
		$cOrderLst = range(1, $oDB->iDBRowCount);
			
		while($oDB->db_line())
		{
			$QuestionID = $oDB->cDBLine["guid_id"];						
			$cAnswers = NULL;					  
												
			$oDBA->db_basic_select($cQuery, $cParams);
			
			while($oDBA->db_line())
			{			
				$cAnswers .= "  
					
					<form name='frm_answer_update' id='frm_answer_update_".$oDBA->cDBLine["guid_id"]."' method='post' action='".$_SERVER['PHP_SELF']."#a_question_".$oDB->cDBLine["question_order"]."'>
						<input type='hidden' name='EditMode' value='1'  />
						<input type='hidden' name='id_guid' value='".$oDBA->cDBLine["guid_id"]."' />
						  <table width='100%' border='0' cellspacing='0' cellpadding='2' bgcolor='#DDDDFF'>
							<tr>
							  <td width='10%'>
								  <select name='frm_lst_answer_val' id='frm_lst_answer_val_".$oDBA->cDBLine["guid_id"]."'>"
									.$this->oFrm->forms_select_options($cAnswerValLst, NULL, $oDBA->cDBLine["value"], FALSE).
								  "</select>
							  </td>
							  <td width='70%'><textarea name='frm_ta_answer_text' id='frm_ta_answer_text_".$oDBA->cDBLine["guid_id"]."' cols='35' rows='1'>".$oDBA->cDBLine["text"]."</textarea></td>
							  <td width='10%' align='center'><input type='image' src='/media/image/icon_save_0001.png' name='frm_btn_ans_save' id='frm_btn_save_ans_".$oDBA->cDBLine["guid_id"]."' value='Save' /></td>
							  <td width='10%' align='center'><input type='image' src='/media/image/icon_delete_0001.png' name='frm_btn_ans_delete' id='frm_btn_delete_ans_".$oDBA->cDBLine["guid_id"]."' value='Delete' /></td>
							</tr>
						  </table>
					</form><br />";									
										
			}				  
		  
			$cAnswers .= "<div id='new_answer_".$oDB->cDBLine["guid_id"]."'>

		  	<form name='frm_answer_new' id='frm_answer_new_".$oDB->cDBLine["guid_id"]."' method='post' action='".$_SERVER['PHP_SELF']."#a_question_".$oDB->cDBLine["question_order"]."'>
					<input type='hidden' name='EditMode' value='1'  />
					<input type='hidden' name='id_guid' value='".$oDB->cDBLine["guid_id"]."' />
					  <table width='100%' border='0' cellspacing='0' cellpadding='2' bgcolor='#DDDDFF'>
						<tr>
						  <td width='10%'>                          
							  <select name='frm_lst_answer_val' id='frm_lst_answer_val_".$oDB->cDBLine["guid_id"]."' >"
							   .$this->oFrm->forms_select_options($cAnswerValLst, NULL, "-", FALSE). 
							  "</select>
						  </td>
						  <td width='70%'><textarea name='frm_ta_answer_text' id='frm_ta_answer_text_".$oDB->cDBLine["guid_id"]."' cols='35' rows='1'></textarea></td>
						  <td width='20%' align='center'><input type='image' src='/media/image/icon_save_0001.png' name='frm_btn_ans_add' id='frm_btn_ans_add_".$oDB->cDBLine["guid_id"]."' value='Add' /></td>
						</tr>
					  </table>
				</form></div>";
		  
			  $cQuizStr 	.= "
			  <br />
			  <div id='question_".$oDB->cDBLine["guid_id"]."'>
			  <table width='100%' border='0' cellspacing='0' cellpadding='0' bgcolor='#F0F0FF'>
				<tr>
				  <td>
				  
					  <a name='a_question_".$oDB->cDBLine["question_order"]."' id='a_question_".$oDB->cDBLine["question_order"]."'></a>
					  <form name='frm_question_update' id='frm_question_update_".$oDB->cDBLine["guid_id"]."'  method='post' action='".$_SERVER['PHP_SELF']."#a_question_".$oDB->cDBLine["question_order"]."'>							  
					  <input type='hidden' name='EditMode' value='1'  />
					  <input type='hidden' name='id_guid' value='".$oDB->cDBLine["guid_id"]."' />
						<table width='100%' border='0' cellspacing='0' cellpadding='1' >
						  <tr>
							<th colspan='2'><table width='100%' border='0' cellspacing='0' cellpadding='0'>
							  <tr>
								<td width='77%' align='left'>Question
								  <select name='frm_lst_order' id='frm_lst_order_".$oDB->cDBLine["guid_id"]."'>"
									.$this->oFrm->forms_select_options($cOrderLst, NULL, $oDB->cDBLine["question_order"], FALSE).
								  "</select>
								  
								  </td>
								<td width='11%'><input type='submit' name='frm_btn_que_save' id='frm_btn_que_save_".$oDB->cDBLine["guid_id"]."' value='Save' /></td>
								<td width='12%'><input type='submit' name='frm_btn_que_delete' id='frm_btn_que_delete_".$oDB->cDBLine["guid_id"]."' value='Delete' onclick='return confirmSubmit()' /></td>
							  </tr>
							</table></th>
						  </tr>
						  <tr>
							<td><label for='frm_ta_question_val'>Question Text</label></td>
							<td><textarea name='frm_ta_question_val' id='frm_ta_question_".$oDB->cDBLine["guid_id"]."' cols='45' rows='5'>".$oDB->cDBLine["question"]."</textarea></td>
						  </tr>
						  <tr>
							<td><label for='frm_lst_right_answer'>Correct Response</label></td>
							<td><select name='frm_lst_right_answer' id='frm_lst_right_answer_".$oDB->cDBLine["guid_id"]."' >"
							  .$this->oFrm->forms_select_options($cAnswerValLst, NULL, $oDB->cDBLine["right_answer"], FALSE).
							"</select></td>
						  </tr>
						</table>
					  </form><br />"
					  
					  ."<div id='answers_".$oDB->cDBLine["guid_id"]."'>"
					  .$cAnswers
																 
				  ."</div></td>
				</tr>
			  </table></div>";			
								
		}	
		
			$cOrderLst[$oDB->iDBRowCount+1] = $oDB->iDBRowCount+1; //Add one more to the order list.
		
			$cQuizStr .= "<br />
					  <div id='question_new'>
					  <table width='100%' border='0' cellspacing='0' cellpadding='0' bgcolor='#F0F0FF'>
						<tr>
						  <td>						  
							  <a name='a_question_".($oDB->iDBRowCount+1)."' id='a_question_".($oDB->iDBRowCount+1)."'></a>
							  <form name='frm_question_new' id='frm_question_new'  method='post' action='".$_SERVER['PHP_SELF']."#a_question_".($oDB->iDBRowCount+1)."'>
							  <input type='hidden' name='trigger_type' value='question_add'  />
							  <input type='hidden' name='id_guid' value='".$oDBA->cDBLine["guid_id"]."' />
							  <input type='hidden' name='EditMode' value='1'  />
							  	<table width='100%' border='0' cellspacing='0' cellpadding='1' >
								  <tr>
									<th colspan='2'><table width='100%' border='0' cellspacing='0' cellpadding='0'>
									  <tr>
										<td width='77%' align='left'>Question
										  <select name='frm_lst_order' id='frm_lst_order_".$oDB->cDBLine["guid_id"]."'>"
											.$this->oFrm->forms_select_options($cOrderLst, NULL, ($oDB->iDBRowCount+1), FALSE).
										  "</select>
										  
										  </td>
										<td width='11%'><input type='submit' name='frm_btn_que_add' id='frm_btn_que_add' value='Add' /></td>
									  </tr>
									</table></th>
								  </tr>
								  <tr>
									<td><label for='frm_ta_question_val'>Question Text</label></td>
									<td><textarea name='frm_ta_question_val' id='frm_ta_question_val' cols='45' rows='5'></textarea></td>
								  </tr>
								  <tr>
									<td><label for='frm_lst_right_answer'>Correct Response</label></td>
									<td><select name='frm_lst_right_answer' id='frm_lst_right_answer' >"
									  .$this->oFrm->forms_select_options($cAnswerValLst, NULL, NULL, FALSE).
									"</select></td>
								  </tr>
								</table>
							  </form>
							</td>
						</tr>
					  </table></div>";
		
		if(!$cQuizStr)
		{
			$cQuizStr = "<h2><span class='alert'>No questions available.</span></h2>";
		}
			
		return $cQuizStr;
	}
	
	public function training_class_record($cTrainingParams)
	{		
		/*
		training_class_record_0001
		Damon Vaughn Caskey
		2013-03-27 (Converted to function class_record_0001 include)
		
		Inserts user variables into class participant database.	
		*/
		
		$cQuery		= NULL;	//Query string.
		$cParams	= NULL;	//Parameter array.
		$cClassID	= NULL;	//Class ID.
		$p_id		= NULL;	//Participant ID.
		$listing_id	= NULL;	//Class listing ID.
		
		/* Build query string. */
		$cQuery ="MERGE INTO tbl_class_participant
		USING 
			(SELECT ? AS Search_Col) AS SRC
		ON 
			tbl_class_participant.account = SRC.Search_Col
		WHEN MATCHED THEN
			UPDATE SET
				name_l				= ?,
				name_f				= ?,									
				room				= ?,
				status				= ?,
				phone				= ?,									
				department			= ?,
				supervisor_name_f	= ?,
				supervisor_name_l	= ?
		WHEN NOT MATCHED THEN
			INSERT (account, name_l, name_f, room, status, phone, department, supervisor_name_f, supervisor_name_l)
			VALUES (SRC.Search_Col, ?, ?, ?, ?, ?, ?, ?, ?)
			OUTPUT INSERTED.id_int;";		
		
		/* Apply parameters. */
		$cParams = array(&$cTrainingParams['account'],
						&$cTrainingParams['name_l'],
						&$cTrainingParams['name_f'],
						&$cTrainingParams['room'],
						&$cTrainingParams['status'],
						&$cTrainingParams['phone'],
						&$cTrainingParams['department'],
						&$cTrainingParams['supervisor_name_f'],
						&$cTrainingParams['supervisor_name_l'],
						&$cTrainingParams['name_l'],
						&$cTrainingParams['name_f'],
						&$cTrainingParams['room'],
						&$cTrainingParams['status'],
						&$cTrainingParams['phone'],
						&$cTrainingParams['department'],
						&$cTrainingParams['supervisor_name_f'],
						&$cTrainingParams['supervisor_name_l']);	
		
		/* Execute query. */	
		$this->oDB->db_basic_action($cQuery, $cParams, TRUE);
		
		/* Get ID of created/updated record. */
		$p_id = $this->oDB->cDBLine["id_int"];
		
		/* 	User demographics have now been found or inserted. Now we will deal with class type, instructor and time. */		
		$cQuery = "INSERT INTO	tbl_class
		
								(class_type,
								trainer_id,
								class_date)
					OUTPUT INSERTED.class_id
								VALUES	(?, ?, ?)";	
		
		$cParams = array(&$cTrainingParams['class'],
			&$cTrainingParams['trainer'],
			&$cTrainingParams['taken']);
						
		/* Execute query. */	
		$this->oDB->db_basic_action($cQuery, $cParams, TRUE);
		
		/* Get ID of new record. */		
		$cClassID = $this->oDB->cDBLine["class_id"];
					
		/* Insert newly created id and participant id to class listing table. */		
		$cQuery = "INSERT INTO tbl_class_listing
		
								(participant_id,
								class_id)
					OUTPUT INSERTED.id_int
								VALUES (?, ?)";	
		
		$cParams = array(&$p_id,
						&$cClassID);
						
		/* Execute query. */	
		$this->oDB->db_basic_action($cQuery, $cParams, TRUE);
		
		/* Get ID of new record. */		
		return $this->oDB->cDBLine["id_int"];			  
	}
	
	public function training_vars_get()
	{
		//foreach ($this->cClassVars as $key => $val)
		//{
		//	$this 		
		//}
	}
}



Class – Tables

<?php 

class class_tables {

	/*
	Tables
	Damon Vaughn Caskey
	2013-03-21
	
	Miscellaneous table functions.
	*/
	
	public 	$cMarkup 		= NULL;	//Resulting markup output. Typically a table.
	private $oUtl			= NULL;	//Utility class object.
	
	function __construct($oDep)
	{
		/*
		Constructor
		Damon Vaughn Caskey
		2013_01_21
		
		Class constructor.
		*/
		
		/* Import object dependencies. */
		$this->oUtl = $oDep['Utl'];
						
		/* Verify object dependencies. */
		if(!$this->oUtl)	trigger_error("Missing object dependency: Utility.", E_USER_ERROR);		
	}
	
	public function tables_db_output($oDB, $bRowCount = TRUE, $cFieldSkip = NULL, $cAuxLink = array("Header" => NULL, "Link" => NULL, "Target" => "_blank", "Text" => "Go"), $cAuxLinkFields = NULL, $cRowStyle = NULL)
	{	
		/*
		tables_db_output
		Damon Vaughn Caskey
		2013-03-20
		
		Create complete table markup from database query.
		
		Preconditions:
			Executed database query.
			$oDB: Object with object variables populated by query.
			$bRowCount: True = Display a row count preceding table.
			$cFieldSkip['<fieldname>', ...]: Array of fields from query to skip when creating table.
			$cAuxLink['Link', 'Text', 'Target']: Adds action link to end of table.
				Link: Page name.
				Target: Page target (_new, _blank, etc.)
				Text: Text to display.				
			$cAuxLinkFields['<fieldname>', ...]: Fields to pass as part of action link.
			$cRowStyle[even, odd]: Array to override default alternate row style.
				
		Postconditions:
			Populate and return $cMarkup with table markup string.
		*/
		
		$i						= NULL;	//Working counter.
		$iRowCount 				= NULL;	//Count of records retrieved by query.
		$cOutput				= NULL;	//Output string.
		$cFieldMetadata			= NULL;	//Metadata collection (field name, type, etc.) for database columns.
		$cFieldMetaDataName 	= NULL; //Individual item name from metadata colelction.
		$cFieldMetaDataValue	= NULL;	//Individual item value from metadata collection.
		$iFields				= NULL;	//Field counter/index.
		$cFieldName				= NULL; //Field name array.
		$cName					= NULL;	//Table markup write in: Field name.
		$cValue 				= NULL;	//Table markup write in: Field value.
		$cLink 					= NULL;	//Table markup write in: Action link.
		
		/* Add extra markup if cAuxLink has a value, otherwise leave NULL. " */
		
		if($cAuxLink["Link"] != NULL)
		{			
			$cAuxLink["Link"] .= "?";
			$cAuxLink["Header"] = $cAuxLink["Header"] != NULL ? "<th>".$cAuxLink["Header"]."</th>" : "<th>Action</th>";			
		}
		
		if($bRowCount)
		{
			$iRowCount = $oDB->iDBRowCount; 
			$cOutput .= '<span class="row_count">' .$iRowCount. ' records found.</span><br/><br/>';
		}
		
		$cOutput .= '<div title="Table" class="overflow"><table border="0" cellpadding="5" cellspacing="0" bgcolor="#CCCCCC"><tr>';	
		
		/* Zero counter */
		$i = 0;
		
		/* Loop each column in query result. */	
		foreach($oDB->cDBMeta as $cFieldMetadata)
		{					
			/* Loop coloumn metadata collection. */
			foreach($cFieldMetadata as $cFieldMetaDataName => $cFieldMetaDataValue)
			{			
				/* Column name? */				
				if($cFieldMetaDataName == 'Name')
				{						
					/* Check field skip array before using this field name */
					if(!in_array($cFieldMetaDataValue, $cFieldSkip))
					{						
						/* Output to table header markup and populate name array. */									
						$cOutput .= "<th>".$cFieldMetaDataValue."</th>";	//Populate table header markup.																	
					}
					
					$cFieldName[$i] = $cFieldMetaDataValue;				//Populate Name array.
					
					/* Increment field count. */
					$iFields++;
				}					
			}
			
			/* Increment counter. */
			$i++;							
		}		
					
		$cOutput .= $cAuxLink["Header"];	
				
		/* Output query results as table. */
		while($oDB->db_line(SQLSRV_FETCH_NUMERIC))
		{		
		
			$cLink 		= $cAuxLink["Link"];
			
			/* Increment line counter */
			$iLine++;
			
			/* Insert table row and style. */
			$cOutput .= "<tr bgcolor='".$this->oUtl->utl_color_alternation($iLine)."'>";
											
			for ($i = 0; $i < $iFields; $i++)
			{					
				$cName		= $cFieldName[$i];
				$cValue 	= $oDB->cDBLine[$i];								
			
				/* Check field skip array before using this field. */
				if(!in_array($cName, $cFieldSkip))
				{				
					$cOutput .= "<td>".$cValue."</td>";
				}
				
				if($cLink != NULL)
				{			
					if(in_array($cName, $cAuxLinkFields))
					{
						$cLink .= $cFieldName[$i]."=".$cValue."&";
					}				
				}
			}
			
			if($cLink != NULL)
			{
				$cOutput .= '<td><a href="'.$cLink.'" target="'.$cAuxLink["Target"].'">'.$cAuxLink["Text"].'</a></td>';								
			}
		}
					
		$cOutput .= "</table><br/><br/></div>";
		
		$this->cMarkup = $cOutput;
		
		return $this->cMarkup;
	}		
}
?>



Class – Sessions

<?php

class class_sessions implements SessionHandlerInterface
{    

	/*
	class_sessions
	Damon Vaughn Caskey
	2012_12_10
	
	Override PHP's default session handling to store data in an MSSQL table. 
	*/	
	
	const 	c_iLife 	= 1440;	//Default session time out (in seconds)
	
	private	$oDB 		= NULL;	//Databse class object.
	private $iLife		= NULL;	//Session time out.

	function __construct($oDep, $iLife=self::c_iLife)
	{
		/*
		Constructor
		Damon Vaughn Caskey
		2012_12_29
		
		Class constructor.
		*/		
								
		/* Set class vars. */
		$this->iLife = $iLife;	//Session time out.
		
		/* Import object dependencies. */
		$this->oDB = $oDep['DB'];
				
		/* Verify object dependencies. */
		if(!$this->oDB)	trigger_error("Missing object dependency: Database.", E_USER_ERROR);		
	}
      
   	public function session_set($cID, $cValue=NULL)
	{
		/*
		session_set
		Damon Vaughn Caskey
		2012_12_23
		
		Wrapper to set value of a $_SESSION[] variable.
		
		$cID:		Session variable name/id.
		$cValue:	Value to set.
		*/
		
		$_SESSION[$cID] = $cValue;
	}
	
	public function session_get($cID)
	{
		/*
		session_get
		Damon Vaughn Caskey
		2012_12_23
		
		Wrapper to aquire value in a $_SESSION[] variable.
		
		$cID:	Session variable name/id.
		*/
		
		$cValue	= NULL;	//Value to return.
		
		/* Get session value if any */
		if(isset($_SESSION[$cID]))
		{
			$cValue = $_SESSION[$cID];
		}	
		
		/* Return value. */
		return $cValue;
	}	
   
   	public function open($savePath, $sessionName)
    {	
		/*
		open
		Damon Vaughn Caskey
		2012_12_10
		
		Set database class object for other session functions. Called by PHP to open session.
		
		$savePath: 		Path to locate session file. Unused.
		$sessionName:	Name of session file. Unused.
		*/
					
		/* Return TRUE. */
        return true;
    }

    public function close()
    {	
		/*
		close
		Damon Vaughn Caskey
		2012_12_10
		
		Filler; function is called by PHP to close session.
		*/			
		
		/* Return TRUE. */
        return true;
    }

    public function read($cID)
    {		
        /*
		read
		Damon Vaughn Caskey
		2012_12_10
		
		Locate and read session data from database.
		
		$cID = Session ID.
		*/
	
		$cData 		= NULL; 						//Final output.
		$cQuery 	= NULL;							//Query string.
		$cTime 		= date(constants::c_cDateF);	//Current time.
		$cParams	= NULL;							//Parameter array.						
					 
		/* Build query string. */
		$cQuery = "SELECT session_data 
					FROM tbl_php_sessions 
					WHERE
							session_id = ? 
						AND 
							expire > ?";
		
		/* Apply parameters. */
		$cParams = array(&$cID, &$cTime); 
		
		/* Execute query. */	
		$this->oDB->db_basic_select($cQuery, $cParams);
						
		/* Get result and pass to local var(s). */
		if($this->oDB->rDBResult)
		{
			/* Set line array. */
			$this->oDB->db_line();
			
			/* Get session data. */
			$cData = $this->oDB->cDBLine['session_data'];
		}	
		
		/* Return results. */
		return $cData;
    }

    public function write($cID, $cData)
    {
		/*
		write
		Damon Vaughn Caskey
		2012_12_10
		
		Update or insert session data. Note that only ID, Expire, and Session Data are 
		required. Other data is to aid in debugging.
		
		$cID 	= Session ID.
		$cData	= Session data.
		*/
		
		$cQuery = NULL;	               		//Query string.
		$cTime 	= NULL;						//Current time.
		$cLoc	= $_SERVER["PHP_SELF"];		//Current file.
		$cIP	= $_SERVER['REMOTE_ADDR'];	//Client IP address.
					
		/* Calculate epirire time. */
		$cTime		= date(constants::c_cDateF, time()+$this->iLife);	
		
		/* Ensure IP string is <= 15. Anything over is a MAC or unexpected (and useless) value. */
		$cIP = substr($cIP, 0, 15);
		
		/* Build query string. */
		$cQuery ="MERGE INTO tbl_php_sessions
		USING 
			(SELECT ? AS Search_Col) AS SRC
		ON 
			tbl_php_sessions.session_id = SRC.Search_Col
		WHEN MATCHED THEN
			UPDATE SET
				session_data	= ?,
				expire			= ?,
				source			= ?,
				ip				= ?
		WHEN NOT MATCHED THEN
			INSERT (session_id, session_data, expire, source, ip)
			VALUES (SRC.Search_Col, ?, ?, ?, ?);";		
		
		/* Apply parameters. */
		$cParams = array(&$cID,
				&$cData,
				&$cTime,
				&$cLoc,
				&$cIP,
				&$cData,				
				&$cTime,
				&$cLoc,
				&$cIP);	
		
		/* Execute query. */	
		$this->oDB->db_basic_action($cQuery, $cParams);
		
		/* Return TRUE. */
		return true;
    }

    public function destroy($cID)
    {	
	
		/*
		destroy
		Damon Vaughn Caskey
		2012_12_10
		
		Delete current session.
		
		$cID: Session ID.		 
		*/
				
		$cQuery 	= NULL;	//Query string.
		$cParams	= NULL;	//Parameter array.
		
		/* Build query string. */
		$cQuery		= "DELETE FROM tbl_php_sessions WHERE session_id = ?";
		
		/* Apply parameters. */
		$cParams	= array(&$cID);
		
		/* Execute query. */	
		$this->oDB->db_basic_action($cQuery, $cParams);		
		
		/* Return TRUE. */
		return true;
    }

    public function gc($maxlifetime)
    {
		/*
		gc (Garbage Cleanup)
		Damon Vaughn Caskey
		2012_12_10
		
		Delete expired session data.
		
		$maxlifetime: Expire time. Unused. 
		*/
		
		$cTime		= date(constants::c_cDateF);	//Current time.	
		$cQuery		= NULL;							//Query string.
		$cParams 	= NULL;							//Parameter array.
		
		/* Build query string. */
		$cQuery		= "DELETE FROM tbl_php_sessions WHERE expire < ?";
		
		/* Apply parameters. */
		$cParams	= array(&$cTime);

		/* Execute query. */	
		$this->oDB->db_basic_action($cQuery, $cParams);
	
		/* Return TRUE. */
		return true;
    }
}



Class – Error

<?php

class class_error
{    

	/*
	class_error
	Damon Vaughn Caskey
	2012_12_28
	
	Error handler.
	*/	
	
	const 	c_cDBEHost		= "box406.bluehost.com";	//Error log DB host.
	const 	c_cDBELName		= "caskeysc_uk";			//Error log DB logical name.
	const 	c_cDBEUser		= "caskeysc_ehsinfo";		//Error log DB user.
	const 	c_cDBEPword		= "caskeysc_ehsinfo_user";	//Error log DB password.
	const	c_iETScript		= 0;						//Error type; general script errors.
	const	c_iETDB			= 1;						//Error type; datbase error.
	
	private $cIP			= NULL;						//$_SERVER['REMOTE_ADDR']
	private $cSource		= NULL; 					//$_SERVER['PHP_SELF']
	private $debug			= 0;
	private $oMail			= NULL;						//Class mail hanlder.
	private $oUtl			= NULL;						//Utility functions.
	
	public	$cErrType		= NULL;						//Error number or user type.
	public 	$cErrCode		= NULL;						//Error code.
	public 	$cErrDetail		= NULL;						//Error detail (SQL string, parameters, user defined data...).
	public 	$cErrFile		= NULL;						//File running at error time.
	public	$cErrLine		= NULL; 					//Error line.
	public 	$cErrMsg		= NULL;						//Error message.
	public	$cErrState		= NULL;						//State of server (ex. SQL State).
	public	$cErrTOE		= NULL;						//Time of error.
	public	$cErrVars		= NULL;						//String dump of variables.
	
	public function __construct($oDep, $debug = 0)
    {
        /* Import object dependencies. */
		$this->oMail = $oDep['Mail'];
		$this->oUtl = $oDep['Utl'];
				
		/* Verify object dependencies. */
		if(!$this->oMail)	trigger_error("Missing object dependency: Mail.", E_USER_ERROR);
		if(!$this->oUtl)	trigger_error("Missing object dependency: Utility.", E_USER_ERROR);
		
		$this->debug = $debug;
        set_error_handler(array($this, 'error_handle_start'));
	
		register_shutdown_function(array(&$this, 'error_shutdown'));
	}
	
	public function error_fatal()
	{	
		/*
		error_fatal
		Damon Vaughn Caskey
		2012_12_30
		
		Run final actions before exit on a fatal error.
		*/
		
		/*
		If headers haven't been sent, redirect user to an error page. Otherwise we'll just have to die and settle for a plain text message.
		*/
		if($this->oUtl->utl_redirect("/a_errors/php.php")===FALSE)
		{ 
			die("I'm sorry; it appears an internal error has occurred while processing your request. The webmaster has been alerted and will resolve this issue as soon as possible.");
		}
		
		exit;
			
	}
	
	public function error_handle_start($cCode=NULL, $cMsg=NULL, $cFile=NULL, $cLine=NULL)
	{
		$this->error_handle($cCode, $cMsg, $cFile, $cLine, self::c_iETScript, NULL, NULL);
		
		return true;		
	}
	
	public function error_handle($cCode=NULL, $cMsg=NULL, $cFile=NULL, $cLine=NULL, $cType=self::c_iETScript, $cState=NULL, $cDetail=NULL)
	{
		/*
		error_run
		Damon Vaughn Caskey
		2012_12_28
		
		Run error mail and and log in single call.
				
		$cCode:		Error code/number.
		$cMsg:		Error message.
		$cFile:		PHP generated file name.
		$cLine:		Code line location.
		$cType:		User defined error type.
		$cState:	Server state (mostly for SQL errors).
		$cDetail:	User added detail.
		*/
		
		$iLevel = NULL;
		$value	= NULL;
		$key	= NULL;
		$i		= 0;
				
		$this->cErrTOE		= date(constants::c_cDateF);
		$this->cIP			= $_SERVER['REMOTE_ADDR'];
		$this->cSource		= $_SERVER['PHP_SELF'];
		$this->cErrType		= $cType;
		$this->cErrFile		= $cFile;
		$this->cErrLine		= $cLine;	
		$this->cErrState	= $cState;
		$this->cErrCode		= $cCode;
		$this->cErrMsg		= $cMsg;
		$this->cErrDetail	= $cDetail;
		$this->cErrVars		= NULL;
						
		/*
		If logging in (/authenticate_0001.php) and error is suppressed then exit and do nothing.
		
		LDAP libraries are bugged. EX: ldap_bind throws error 49 on bad password instead of returning FALSE as documented. 
		In PHP this can only be worked around by suppressing the error. Otherwise suppressing errors with @ is bad practice 
		that should be avoided at all costs. Its use will be ignored within any other file.
		*/
		$iLevel = error_reporting();
		
		if (($iLevel == 0 || ($iLevel & $cCode) == 0) && $this->cSource == "/authenticate_0001.php")
		{
			return true;
		}
				
		if($this->cErrCode)
		{
			/*
			Log error to database.
			*/
			//$this->error_log_db();
			
			/*
			If error is any type other than a notice then immediately end script and send an email alert to webmaster.
			*/
			switch ($this->cErrCode)
			{
				case E_USER_ERROR:
				case E_USER_WARNING:
				case E_ERROR:
				case E_CORE_ERROR:
				case E_COMPILE_ERROR:
				default:
					
					if(isset($_GET))
					{
						foreach($_GET as $key => $value)
						{
							$this->cErrVars .= "GET[".$key."]: ".$value." || ";
						}
					}
					
					if(isset($_POST))
					{
						foreach($_POST as $key => $value)
						{
							$this->cErrVars .= "POST[".$key."]: ".$value." || ";
						}
					}
					
					if(isset($_SESSION))
					{
						foreach($_SESSION as $key => $value)
						{
							$this->cErrVars .= "SESSION[".$key."]: ".$value." || ";
						}
					}
		
					$this->error_mail();
					$this->error_fatal();
					break;
				case E_USER_NOTICE:
				case E_NOTICE:
					break;				
			}		
		}
	}
		
   	public function error_log_db()
	{
		/*
		error_db_log
		Damon Vaughn Caskey
		2012_12_28
				
		Attempt to log error detail to database. Self contained to avoid recursive calls to database class.
		*/
				
		$rDBConn		= NULL;	//Connection reference to DB error log.
		$cQuery			= NULL; //Error query string.
		$rDBStatement	= NULL;	//Prepared query reference.
		
		$rDBConn = new mysqli(self::c_cDBEHost, self::c_cDBEUser, self::c_cDBEPword, self::c_cDBELName);
		
		/* If the error log database connection was successful, insert each error to table. */
		if (!$rDBConn->connect_error) 
		{				
			/* Build query string. */ 		
			$cQuery = "INSERT INTO tbl_gen_errors (toe, ip, type, source, file, line, state, code, vars, msg, details) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
			$rDBStatement = $rDBConn->prepare($cQuery);
			
			/* Bind parameters. */
			$rDBStatement->bind_param("sssssssssss", $this->cErrTOE, $this->cIP, $this->cErrType, $this->cSource, $this->cErrFile, $this->cErrLine, $this->cErrState, $this->cErrCode, $this->cErrVars, $this->cErrMsg, $this->cErrDetail);
			
			/* Execute and close query. */ 
			if($rDBStatement != false)
			{							
				$rDBStatement->execute();
				$rDBStatement->close();
			}
			
			/* Close DB connection. */
			$rDBConn->close();			
		}						
		
	}
	
	public function error_mail()
	{
		/*
		error_mail
		Damon Vaughn Caskey
		2012_12_31
		~2012_01_02: Array list upgrade.
		
		Prepare and send an email error alert.
		*/
		
		$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,
			"Variables"			=>	$this->cErrVars,
			"Details"			=>	$this->cErrDetail
		);
				
		$this->oMail->mail_send($cMsg, "Error Report");
	}
			
	public function error_shutdown()
	{
		/*
		error_shutdown
		Damon Vaughn Caskey
		2012_12_31
		
		Shutdown function to capture error types PHP will not normally allow custom error handlers to deal with.
		*/
		
		$cError	= NULL;		//Last error status.
		
		/*
		Get last error status.
		*/
        $cError = error_get_last();
		
		$this->error_handle($cError['type'], $cError['message'], $cError['file'], $cError['line']);
    }	
}


Class – Mail

<?php

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 email headers.
	const	c_cESubject	= "From EHS Web";							//Default outgoing email subject.
	const	c_cEWMIn	= "dvcask2@uky.edu";						//Default webmaster's incoming email 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 email.
		$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);		
	}	
}

?>

Class – Forms

<?php 

class class_forms {

	/*
	Utility
	Damon Vaughn Caskey
	2013_01_21
	
	Miscellaneous form input functions.
	*/
		
	/* Constants */
	const FORMS_ID_USE_NAME						= NULL;		//Use name to generate ID.
	const FORMS_ITEM_ADDITIONS_NONE				= NULL;		//No manual additions to generated item list.
	const FORMS_LABEL_NONE						= NULL;		//No label for fieldset item.
	const FORMS_LABEL_BLANK						= 1;		//Blank label for fieldset item.
	const FORMS_LABEL_USE_ITEM_KEY				= 2;		//Use the item key of a field for its fieldset label or visible selection.
	const FORMS_LABEL_USE_ITEM_NAME				= 3;		//Use the item name of a field for its fieldset label or visible selection.
	const FORMS_LABEL_USE_ITEM_VALUE			= 4;		//Use the items value of a field for its fieldset label or visible selection.
	const FORMS_LABEL_TYPE_FIELDSET				= 0;		//Fieldset label.
	const FORMS_LABEL_TYPE_INLINE				= 1;		//Label text only; no formatting.
	const FORMS_LEGEND_NONE 					= NULL;		//No legend for fieldset.
	const FORMS_QUERY_PARAMETERS_NONE			= NULL;		//No query parameters.
	const FORMS_TYPE_RADIO						= 0;		//Radio type list.
	const FORMS_TYPE_SELECT						= 1;		//Select type list.
	const FORMS_VALUE_CURRENT_NONE				= NULL;		//Current (last selected) value.
	const FORMS_VALUE_DEFAULT_NONE				= NULL;		//Default selected value.
	const FORMS_VALUE_DEFAULT_NOW				= -1;		//Default to current time for specific field.
	const FORMS_EVENTS_NONE						= NULL;		//No events attached to fieldset item.
	const FORMS_READ_ONLY_OFF					= FALSE;
	const FORMS_READ_ONLY_ON					= TRUE;
		
	public $cItemsList 							= NULL;		//Array of items list for select/radio/etc.
	public $cFormElement						= NULL;		//Arracy to store completed element markup that will be placed in a fieldset.
	public $cFormElementActions					= NULL;		//Array of actions tied to form element (onchange, onclick, etc.).
	public $cFieldset							= NULL;		//Array of completed fieldset markups ready to echo into page.
	public $cFieldsetAddsA						= NULL;		//Array of additional instructions, links, etc. that may be added to fieldset above items.
				
	function __construct($oDep)
	{
		/*
		Constructor
		Damon Vaughn Caskey
		2013-01-21
		
		Class constructor.
		*/
		
		/* Import object dependencies. */
		//$this->oUtl = $oDep['Utl'];
		$this->oDB	= $oDep['DB'];
		//$this->Err	= $oDep['Err'];
				
		/* Verify object dependencies. */
		//if(!$this->oUtl)	trigger_error("Missing object dependency: Utility.", E_USER_ERROR);		
		if(!$this->oDB)		trigger_error("Missing object dependency: Database.", E_USER_ERROR);
		//if(!$this->Err)		trigger_error("Missing object dependency: Errors.", E_USER_ERROR);
	}	
	
	private function forms_events_markup($cEvents=self::FORMS_EVENTS_NONE)
	{
		/*
		forms_events_markup
		Damon Vaughn Caskey
		2013-03-26
		
		Prepare HTML markup string for fieldset form item events (onchange, onclick, etc.).
		*/
		
		if(isset($cEvents))
		{		
			foreach ($cEvents as $cKey => $cValue)
			{
				
				$cEvent .= $cKey.'="'.$cValue.'"';
			}
		}
		return $cEvent;
	}
	
	public function test()
	{
		echo self::FORMS_LABEL_USE_ITEM_VALUE;
	}
	
	private function forms_label_markup($iStyle=self::FORMS_LABEL_NONE, $iType=self::FORMS_LABEL_TYPE_FIELDSET, $cName=NULL, $cID=NULL, $cKey=NULL, $cValue=NULL)
	{
		/*
		forms_label_markup
		Damon Vaughn Caskey
		2013-03-26
		
		Prepare HTML markup string for fieldset form item labels.
		
		Preconditions:
			$cName: 	Name of item.
			$cID:		ID of item.
			$cKey:		Array key of item.
			$cValue: 	Array value of item.
			$iStyle: 	How to arrange label markup.
				self::FORMS_LABEL_USE_ITEM_KEY = The item's Key will be used as a label.
				self::FORMS_LABEL_USE_ITEM_VALUE = The item's Value will be used as label.
				self::FORMS_LABEL_BLANK = The label will be left blank.
				self::FORMS_LABEL_NONE = No label markuop at all.
		
		Postconditions:
			Return finished label markup string.		
		*/
		
		$cClosing = NULL;
		$cLabel = NULL;
		
		if($iType == self::FORMS_LABEL_TYPE_FIELDSET)
		{
			/* Prepare opening label markup. */
			$cLabel = '<div class="'.$cClass['Container_Label'].'"><label for="'.$cID.'">';
			$cClosing = '</label></div>';	
		}							
			
		switch($iStyle)
		{
			case self::FORMS_LABEL_USE_ITEM_KEY:				
				
				$cLabel .= $cKey.$cClosing;									
				break;
		
			case self::FORMS_LABEL_USE_ITEM_NAME:			
				
				$cLabel .= $cName.$cClosing;									
				break;
			
			case self::FORMS_LABEL_USE_ITEM_VALUE:
				
				$cLabel .= $cValue.$cClosing;											
				break;
			
			case self::FORMS_LABEL_BLANK:
			
				$cLabel .= $cClosing;
				break;				
			
			case self::FORMS_LABEL_NONE:
			
				$cLabel = NULL;
				break;
				
			default:
				
				$cLabel .= $iStyle.$cClosing;							
		}
		
		/* Return label markup string. */
		return $cLabel;
	}
	
	public function forms_list_array_from_query($cQuery=NULL, $cParams=array(self::FORMS_QUERY_PARAMETERS_NONE), $cAddsT=self::FORMS_ITEM_ADDITIONS_NONE, $cAddsB=self::FORMS_ITEM_ADDITIONS_NONE){		
		
		/*
		forms_list_array_from_query
		Damon Vaughn Caskey
		2012-12-19
		
		Create list array directly from query results.
		
		$iType:		Select, options, etc.		
		$cQuery:	SQL query string.
		$cParams:	Parameter array.
		$cDefault:	Default selection.
		$cCurrent:	Current selection.
		$bKey:		Use key as item label?
		$cAddsT:	Additional items to place at top of generated list.
		$cAddsB:	Additional items to place at bottom of generated list.
		*/
	
		$i		=	NULL;		//Counter.
		$cList	=	NULL;		//Output string.
		$cKey	=	NULL;
		
		$cList	=	array();
		
		/* Query for list items. */
		$this->oDB->db_basic_select($cQuery, $cParams);
				
		/* Populate list variable. */
		while($this->oDB->db_line(SQLSRV_FETCH_NUMERIC))
		{	
			/* Get key (used for items visible to user). */
			$cKey = $this->oDB->cDBLine[1];
			
			/* If fields exist beyond first key, append to a single key value. */
			if($this->oDB->iDBFCount > 2)
			{	
				/* Start with field #2 (third field) and append to key string until last field is reached. */
				for($i = 2; $i <= ($this->oDB->iDBFCount-1); $i++)
				{
					$cKey .= "; ". $this->oDB->cDBLine[$i];	
				}
			}
			
			/* Populate list array using visible portion of list values as key. */			 
			$cList[$cKey] = $this->oDB->cDBLine[0];									
		}
		
		/* Merge Additions. (As of 5.4 array_merge() will always reorder indexes). */
		if($cAddsT && is_array($cAddsT))
		{	
			$cList = $cAddsT + $cList;	
		}
		
		if($cAddsB && is_array($cAddsB))
		{	
			$cList += $cAddsB;	
		}	
		
		$this->cItemsList = $cList;
		
		/* Output final list value. */
		return $this->cItemsList;
	}
	
	function forms_list_numeric($iType=NULL, $cQuery=NULL, $cParams=NULL, $cDefault=NULL, $cCurrent=NULL, $bKey=self::FORMS_LABEL_USE_ITEM_KEY, $iStart=0, $cAddsT=NULL, $cAddsB=NULL)
	{		
		/*
		forms_list_numeric
		Damon V. Caskey
		2012-12-19		
		
		Generate a simple numeric list with maximum value based number of rows returned by query.
		
		$iType: 	
		$cQuery:	SQL query string.
		$cParams:	Parameter array.
		$cDefault:	Default selection.
		$cCurrent:	Current selection.
		$bKey:		Use key as item label?
		$iStart:	First numeric value of generated list.
		$cAddsT:	Additional items to place at top of generated list.
		$cAddsB:	Additional items to place at bottom of generated list.
		*/
		
		$i		= NULL;	//Counter.
		$cList	= NULL;	//Item list array.					
		
		$cList	= array();
				
		$this->oDB->db_basic_select($cQuery, $cParams);	
								
		for($i = $iStart; $i <= $this->oDB->iDBRowCount; $i++)
		{		
			$cList[$i] = $i;
		}				
		
		/* Merge Additions. (As of 5.4 array_merge() will always reorder indexes). */
		if($cAddsT && is_array($cAddsT))
		{	
			$cList = $cAddsT + $cList;	
		}
		
		if($cAddsB && is_array($cAddsB))
		{	
			$cList += $cAddsB;	
		}
		
		switch ($iType)
		{
			case self::FORMS_TYPE_RADIO:
				//$this->cDLListCode = $this->forms_select_options($cList, $cDefault, $cCurrent, $bKey);
			default:
				$this->cDLListCode = $this->forms_select_options($cList, $cDefault, $cCurrent, $bKey);
		}
		
		return $this->cDLListCode;
	}
		                 
	public function forms_phone($cName=NULL, $cID=self::FORMS_ID_USE_NAME, $cLabel=self::FORMS_LABEL_NONE, $cDefault=array("cc" => "1", "ac" => "859", "lc" => NULL, "pn" => NULL), $cCurrent=self::FORMS_VALUE_CURRENT_NONE, $cClass=NULL, $cEvents=NULL)
	{	
		/*
		forms_phone
		Damon Vaughn Caskey
		2013-01-21
		
		Output form phone input markup.
		*/
	
		$cMarkup 	=	NULL;	//Final markup to echo.
		$cEvent		=	NULL;	//Event string.	
		
		$cMarkup .='<div class="'.$cClass['Container_All'].'">';
				
		/* Set ID to name? */
		$cID = $cID != self::FORMS_ID_USE_NAME ? $cID : $cName;
		
		/* If current value empty or NULL, set "No current" cosntant */
		$cCurrent = $cCurrent ? $cCurrent : self::FORMS_VALUE_CURRENT_NONE;
		
		$cDefault = $cDefault == self::FORMS_VALUE_DEFAULT_NONE ? NULL : $cDefault; 
		
		/* If no current value is available, use default. */
		if(!$cCurrent || $cCurrent == self::FORMS_VALUE_CURRENT_NONE)
		{
			$cCurrent = $cDefault;
		}
				
		/* Parse event actions. */
		$cEvent = $this->forms_events_markup($cEvents);			
		
		/* Prepare label markup. */
		$cMarkup .= $this->forms_label_markup($cLabel, self::FORMS_LABEL_TYPE_FIELDSET, $cName, $cID, $cKey, $cValue);		
		
		$cMarkup .= '<div class="'.$cClass['Container_Item'].'"><input type="text" name="'.$cName.'_cc" id="'.$cID.'_cc" class="'.$cClass.'" value="'.$cDefault['cc'].'" size="1" maxlength="1" />
						  (
							<input type="text" name="'.$cName.'_ac" id="'.$cID.'_ac" class="'.$cClass.'" value="'.$cDefault['ac'].'" size="3" maxlength="3" />
							) 
							<input type="text" name="'.$cName.'_lc" id="'.$cID.'_lc" class="'.$cClass.'" value="'.$cDefault['lc'].'" size="3" maxlength="3" /> 
						  - 
						  <input type="text" name="'.$cName.'_pn" id="'.$cID.'_pn" class="'.$cClass.'" value="'.$cDefault['pn'].'" size="4" maxlength="4" />				  
					</div></div>';		
		/*
		Return end result.
		*/
		return $cMarkup;
	}	
					
	public function forms_radio($cName=NULL, $cID=self::FORMS_ID_USE_NAME, $iLabelStyle=self::FORMS_LABEL_USE_ITEM_KEY, $cList=array(NULL), $cDefault=NULL, $cCurrent=self::FORMS_VALUE_CURRENT_NONE, $cClass=array("Item" => "Standard"), $cEvents=NULL)
	{
		/*
		forms_radio
		Damon Vaughn Caskey
		2013-03-24	
		*/
								
		$cKey		=	NULL;	//Array key.
		$cValue		=	NULL;	//Array value.
		$cChecked	= 	NULL;	//Checked (default/current)?
		$cMarkup 	=	NULL;	//Final markup to echo.
		$cLabel		=	NULL;	//Item label markup.
		$cIDFinal	= 	NULL;	//Final ID inserted into markup.
		$cEvent		=	NULL;	
		
		$cMarkup .='<div class="'.$cClass['Container_All'].'">';
		
		/* Set ID to name? */
		$cID = $cID != self::FORMS_ID_USE_NAME ? $cID : $cName;
		
		/* If current value empty or NULL, set "No current" cosntant */
		$cCurrent = $cCurrent ? $cCurrent : self::FORMS_VALUE_CURRENT_NONE;
		
		/* Parse event actions. */
		$cEvent = $this->forms_events_markup($cEvents);		
		
		foreach ($cList as $cKey => $cValue)
		{				
			/* If $cValue matches $cCurrent, or $cCurrent not provided but $cValue matches $cDefault, add 'checked' to make this the default list item selected. */	
			if ($cCurrent == $cValue || ($cCurrent == self::FORMS_VALUE_CURRENT_NONE && $cValue == $cDefault))
			{
				$cChecked = 'checked="checked"';
			}
			else
			{
				$cChecked = NULL;
			}		
					
			/* IDs must be unique, so we'll combine ID with value. */
			$cIDFinal = $cID."_".$cValue;			
			
			/* Prepare label markup. */
			$cMarkup .= $this->forms_label_markup($iLabelStyle, self::FORMS_LABEL_TYPE_FIELDSET, $cName, $cIDFinal, $cKey, $cValue);			
			
			$cMarkup .= '<div class="'.$cClass['Container_Item'].'"><input type="radio" name="'.$cName.'" id="'.$cIDFinal.'" value="'.$cValue.'" '.$cChecked.' '.$cEvent.' /></div>';			
		}					
		
		$cMarkup .= '</div>';
		
		/*
		Return end result.
		*/
		return $cMarkup;
	
	}
	
	public function forms_select($cName=NULL, $cID=self::FORMS_ID_USE_NAME, $iLabelStyle=self::FORMS_LABEL_USE_ITEM_KEY, $iKeyStyle=self::FORMS_LABEL_USE_ITEM_KEY, $cList=array(NULL => NULL), $cDefault=NULL, $cCurrent=self::FORMS_VALUE_CURRENT_NONE, $cClass=array("Item" => "Standard", "Container_All" => "Show Me"), $cEvents=NULL)
	{
		/*
		forms_radio
		Damon Vaughn Caskey
		2013-03-24	
		*/
								
		$cKey		=	NULL;	//Array key.
		$cValue		=	NULL;	//Array value.
		$cChecked	= 	NULL;	//Checked (default/current)?
		$cMarkup 	=	NULL;	//Final markup to echo.
		$cLabel		=	NULL;	//Item label markup.
		$cEvent		=	NULL;	
		$cItems		=	NULL;	//Select options.
		
		$cMarkup .='<div class="'.$cClass['Container_All'].'">';
		
		/* Set ID to name? */
		$cID = $cID != self::FORMS_ID_USE_NAME ? $cID : $cName;		
		
		/* Parse event actions. */
		$cEvent = $this->forms_events_markup($cEvents);		
		
		if (!is_array($cList))
		{
			$cList = array(NULL => NULL);
		}
		
		foreach ($cList as $cKey => $cValue)
		{				
			/* If $cValue matches $cCurrent, or $cCurrent not provided but $cValue matches $cDefault, add 'checked' to make this the default list item selected. */	
			if ($cCurrent == $cValue || ($cCurrent == self::FORMS_VALUE_CURRENT_NONE && $cValue == $cDefault))
			{
				$cChecked = 'selected';
			}
			else
			{
				$cChecked = NULL;
			}		
					
			/* Prepare label markup. */
			$cLabel = $this->forms_label_markup(self::FORMS_LABEL_USE_ITEM_KEY, self::FORMS_LABEL_TYPE_INLINE, $cName, $cID, $cKey, $cValue);	
			
			$cItems.='<option value="'.$cValue.'" '.$cChecked.'>' . $cLabel . '</option>';			
		}				
		
		
		/* Prepare label markup. */
		$cLabel = $this->forms_label_markup($iLabelStyle, self::FORMS_LABEL_TYPE_FIELDSET, $cName, $cID, $cKey, $cValue);	

		$cMarkup .= $cLabel.'<div class="'.$cClass['Container_Item'].'"><select type="select" name="'.$cName.'" id="'.$cID.'" class="'.$cClass['Item'].'" '.$cEvent.'>'.$cItems.'</select></div></div>';
		
		/*
		Return end result.
		*/
		return $cMarkup;
	
	}
					
	public function forms_text($cName=NULL, $cID=self::FORMS_ID_USE_NAME, $cLabel=self::FORMS_LABEL_NONE, $cDefault=self::FORMS_VALUE_DEFAULT_NONE, $cCurrent=self::FORMS_VALUE_CURRENT_NONE, $cClass=array("Item" => "Standard"), $cEvents=NULL)
	{	
		/*
		forms_text
		Damon Vaughn Caskey
		2013-01-21
		
		Output form text input markup.				
		*/
	
		$cMarkup 	=	NULL;	//Final markup to echo.
		$cEvent		=	NULL;	//Event string.	
		
		$cMarkup .='<div class="'.$cClass['Container_All'].'">';
				
		/* Set ID to name? */
		$cID = $cID != self::FORMS_ID_USE_NAME ? $cID : $cName;
		
		/* If current value empty or NULL, set "No current" cosntant */
		$cCurrent = $cCurrent ? $cCurrent : self::FORMS_VALUE_CURRENT_NONE;
		
		$cDefault = $cDefault == self::FORMS_VALUE_DEFAULT_NONE ? NULL : $cDefault; 
		
		/* If no current value is available, use default. */
		if(!$cCurrent || $cCurrent == self::FORMS_VALUE_CURRENT_NONE)
		{
			$cCurrent = $cDefault;
		}
				
		/* Parse event actions. */
		$cEvent = $this->forms_events_markup($cEvents);			
		
		/* Prepare label markup. */
		$cMarkup .= $this->forms_label_markup($cLabel, self::FORMS_LABEL_TYPE_FIELDSET, $cName, $cID, $cKey, $cValue);
					
		$cMarkup .= '<div class="'.$cClass['Container_Item'].'"><input type="text" name="'.$cName.'" id="'.$cID.'" class="'.$cClass['Item'].'" value="'.$cCurrent.'" '.$cEvent.' /></div></div>';
		
		/*
		Return end result.
		*/
		return $cMarkup;
	}
	
	public function forms_time($cName=NULL, $cID=self::FORMS_ID_USE_NAME, $cLabel=self::FORMS_LABEL_NONE, $cDefault=NULL, $cCurrent=NULL, $cOptions="{dateFormat: 'yy-mm-dd', timeFormat: 'HH:mm:ss', controlType: 'select', changeYear: true, constrainInput: true}", $cFunction="datetimepicker", $bReadOnly=self::FORMS_READ_ONLY_ON, $cClass=NULL, $cEvents=NULL)
	{	
		/*
		forms_time
		Damon Vaughn Caskey
		2013-01-21
		
		Output form date/time input markup.
		*/
	
		$cMarkup 	=	NULL;	//Final markup to echo.
		$cEvent		=	NULL;	//Event string.	
				
		$cMarkup .='<div class="'.$cClass['Container_All'].'">';
				
		/* Set ID to name? */
		$cID = $cID != self::FORMS_ID_USE_NAME ? $cID : $cName;
		
		/* If current value empty or NULL, set "No current" cosntant */
		$cCurrent = $cCurrent ? $cCurrent : self::FORMS_VALUE_CURRENT_NONE;
		
		$cDefault = $cDefault == self::FORMS_VALUE_DEFAULT_NONE ? NULL : $cDefault; 
		
		/* If no current value is available, use default. */
		if(!$cCurrent || $cCurrent == self::FORMS_VALUE_CURRENT_NONE)
		{
			$cCurrent = $cDefault;
		}
		 						
		/* Parse event actions. */
		$cEvent = $this->forms_events_markup($cEvents);			
		
		/* Prepare label markup. */
		$cMarkup .= $this->forms_label_markup($cLabel, self::FORMS_LABEL_TYPE_FIELDSET, $cName, $cID, $cKey, $cValue);		
		
		$cMarkup .= "<script>$(function(){
						$( '#".$cID."' ).".$cFunction."(".$cOptions.");
					});</script>";

		$cMarkup .= "<input type='text' name='".$cName."' id='".$cID."' value='".$cCurrent."'";
		
		if ($bReadOnly==TRUE)
		{
			$cMarkup .= " readonly='readonly'";
		}
		
		$cMarkup .= " /></div>";
		
		/*	Return end result. */
		return $cMarkup;
	}
	
	public function forms_fieldset($cID=NULL, $cLegend=self::FORMS_LEGEND_NONE, $cElements=array(NULL), $cAddOns=array(NULL), $cClass=array("Div"=>"table_row_0", "Fieldset"=>"Standard"))
	{
		/*
		forms_fieldset
		Damon Vaughn Caskey
		2013-03-25
		
		Arrage form input items into a fieldset.
		
		$cID: 		Fieldset ID.
		$cLegend: 	Legend label, if any.
		$cElements:	Markup of field list items (select lists, radio groups, text boxes, etc).
		$cClass:	Style classes.
		*/
		
		$cElementKey	= NULL;	//Single element key.
		$cElementVal	= NULL;	//Single element value.
		
		$cMarkup = '<div class="'.$cClass['Div'].'"><fieldset id="'.$cID.'" class="'.$cClass['Fieldset'].'">';
		
		
		if($cLegend != self::FORMS_LEGEND_NONE)
		{
			$cMarkup .= '<legend>'.$cLegend.'</legend>';	 
		}				
		
		foreach($cAddOns as $cElementKey => $cElementVal)
		{
			$cMarkup .= '<div class="'.$cElementKey.'">'.$cElementVal.'</div>';
		}	
		
		foreach($cElements as $cElementKey => $cElementVal)
		{
			$cMarkup .= '<div class="'.$cElementKey.'">'.$cElementVal.'</div>';
		}		
		
		$cMarkup .= '</fieldset></div>';
		
		$this->cFieldset[$cID] = $cMarkup;
		
		return $this->cFieldset[$cID];
	}
		
}
?>