Bad Cable Woes Force me to Force 10Mbps Full Duplex

This seems to be a rare problem for most people, and in fact should be, however, if you’ve ever had bad CAT (5/5e/6/whatever) cables [because you made them yourself maybe], then theres a possibility you’ve come across a strange scenario where your NIC cannot access the network (or establish a good connection with your Switch/Hub or Router) and forcibly setting it down to 10Mbps is the only way to get it to work.

So, if you have the same problem, there’s a ridiculously easy solution in Linux. Years ago, we had to use mii-tool. mii-tool, however, is now deprecated and could only handle 100baseT4, 100baseTx-FD, 100baseTx-HD, 10baseT-FD or 10baseT-HD.

Here comes in our hero of the day namely ethtool.

Now, I was at my ranch where I did all of the wiring for the network cables. That included the RJ-45 wall jackets, as well as the plastic connectors for the basement where all of the cables eventually lead down to multiple / separate switches and routers (yes, multiple routers, mini-networks, pain in the ass – i know)

Well there’s one room thats always caused problems from the get-go. At first I thought it was the socket, then I thought it was the plastic connector. I’ve changed both many times, different computers would work, some would not, sometimes it’d work when I would boot with one OS, often it wouldn’t with another.

Finally, I figured out that the pattern had to do with whether or not the NIC was set to 10Mbps, as opposed to 100Mbps or 1000Mbps/1Gbps. Then it hit me, the cable must have be damaged IN SIDE the wall somewhere or in the floor.. either way way I have to make sure that the NIC is downgraded to 10Mbps and everyone works fairly well afterwards.

So, here’s the magical command everyone insisted on me using:

ethtool -s eth0 speed 10 duplex full autoneg on

Sadly, this command would not work!

First things first, I am using the RTL6169 driver for my RTL6168/6111b NIC – it doesn’t support being told to renegotiate, I realized, so then I thought I would follow up with these commands:


ethtool -s eth0 speed 10 duplex full
ethtool -r eth0

…to manually re-negotiate after setting the speed. However, I found that the first step would not even work. Basically, in no way could I get ethtool to downgrade or change the speed setting. It just refuses to do make it change at all.

This means I had to go back and use the so-called “deprecated” mii-tools. On Ubuntu 11.04 I was able to install it using the net-tools package. Alternatively you can download the source to mii-tools (its a very harmless easy compile / install with the make command).

So I fired up the good ‘ol tool using this exact command:

mii-tool -F 10baseT-FD eth0

Voila! Presto! Banzai! It works! It.. just.. works.. ethtool could not work or ethtool would not work, but mii-tool worked just fine.

Obviously, I did not want to run the command every time I rebooted, so I edited the file /etc/network/interfaces and added this line at the bottom:

pre-up /sbin/mii-tool -F 10baseT-FD eth0

Some people recommend making a script or running it from rc.d or init.d, etc. That’s just bad system administration, IMHO. There is no better place than the interfaces file, its there (and the use of the pre-up command) for a reason just like this one for startup NIC operations.

So the moral of the story? Just because a tool is old does not mean its usefulness has waned!

Bypassing DISTINCT’s ORDER BY Requirement with Sub Query Wrapper

When using DISTINCT in a query to weed out duplicates (which is necessary often in PostgreSQL, since it has the very tiresome rule of making a simple GROUP BY pointless by requiring that all fields being pulled be included in the GROUP BY expression), its important to use smart, efficient methodology.

Using DISTINCT can be very simple and very powerful, but can quickly get annoying when you start off the beaten path unless you employ some simple SQL techniques.

Lets say we have a table called employees that has several fields including (but not limited to) id, name, and clearance_level (whether id is a primary key or not is un-important, as well as whether or not the other fields are integers or strings or blah blah blah.)

SELECT DISTINCT ON (E.id) id, name, clearance_level FROM employees E ORDER BY id

Which is fine and dandy, if you want the query to return them by the order of their id. However, I’m sure you’ve found that when you attempt something like say:

SELECT DISTINCT ON (E.id) id, name, clearance_level FROM employees E ORDER BY clearance_level

or

SELECT DISTINCT ON (E.id) id, name, clearance_level FROM employees E ORDER BY name

…then you’ll find yourself in sad or dire straits.

Fear not! We can bypass this nasty little requirement of DISTINCT by making the original query a sub query and then re-order that data. Not only that, it is crazy simple:

SELECT * FROM
(SELECT DISTINCT ON (E.id) id, name, clearance_level FROM employees E) xyzzy
ORDER BY clearance_level;

Voila!

You can see, we simply turned our original query into a sub-query, from which we are collecting everything, and then referring to it as xyzzy (of course you can name it anything you please) and then ordering that data by the clearance_level.

I would recommend that delimiters that can be used in the initial query be used so, so as to allow the secondary (outer) ORDER BY statement to run as fast as possible.

Database Management Systems

Updating PostgreSQL fields using multiple tables

I was involved in a small project where I had to crawl through several systems to mine data, organize it, and filter it down so it could be placed into a database. The actual crawl took many days to complete and unfortunately, a small irregularity occurred during the process. Simply put, INSERTs were being used when in fact UPDATEs with a check should have been implemented.

Imagine my dismay when I found that, although the information was all in the database, it was floating around jumbled and would be difficult to re-organize, so much so that I almost feared that the a re-crawl could be necessary.

Of course, that would have been insane; after all, once you have your data in a database, there should always be some fancy, efficient way of re-organizing it.

At one point during the process, I needed to able to take data from one field and assign it to a similar field in a different table. To do so I required an UPDATE statement of a caliber I had never used (or needed) before.

At first I tried funny (and terrible) variations like:

UPDATE table_a AS a, table_b AS b SET a.this_field = a.thatfield WHERE a.some_id = b.some_id

I’m sure you’re laughing if you can see I was under the delusion that I could use an UPDATE statement like a normal SELECT statement.

Anyhow, after doing a little digging the solution is still elegant and simple simply requiring something still closely resembling an INSERT query.

I ended up using this format instead:

UPDATE private."MyData" MD SET thisid = C.thisid FROM private."ComparisonData" C WHERE MD.thatid = C.thatid AND (other statements..)

As you can see I’m using a Schema called private which you can happily ignore, and some of the tables and fields’ names have been changed to protect the innocent (or perhaps in this case, the guilty 🙂

Manipulating 0 byte or empty files in Linux

There are a surprising amount of times I’ve had to manipulate empty files dispersed amongst a large group of variously sized other files.

A long time ago I remember using some convoluted shell script on my Sun Workstation 3/80 (SunOS baby, none of that fancy Solaris whippersnapper!)

Later when I was using Debian, I wrote little TCL (and even later Python) scripts.

Now I’m using Ubuntu on most of my Desktop (or development I s’pose) machines and it seems things just keep getting easier.

Now I found a method that borders on the rediculous easy, using the find command.


find . -type f -size 0 | xargs command

So lets say we just want to list the files MMmkay?


find . -type f -size 0 | xargs ls -l

Or say we want to remove/delete the files


find . -type f -size 0 | xargs rm -f

Of course I know that this isn’t an Ubuntu specific solution (this should obviously work even on older versions of find and pick-your-unix-flavor or even some inferior operating system (*cough*) where you’ve ported over your unix tools to.

Resolving Prototype Scriptaculous jQuery Conflictions with noConflict() Example

There is a good chance if you are reading this, you were under the same problem I myself had a short while ago…

You’re using Scriptaculous or something else built on top of Prototype and everything works fine when one fine day or hour, you decide you want to incorporate a widget or some code that uses jQuery.

So you do what I did, search around only to have people mention with a high and mighty, auspicious sounding response that the answer to all your problems, the magical cure-all for your what ails ya:

jQuery.noConflict();

Of course they mention that all you have to do is “call this code” after importing the jquery script.. and possibly that you should call it like this ‘$.noConflict();’ or perhaps ‘jQuery.noConflict();’ or laughingly ‘$jQuery.noConflict();’

Some of the smarter (but no more helpful) ones tell you correctly to use assign the noConflict to a variable

like so:
$var = jQuery.noConflict();

Yet they then expect you to just know what to do from there. Great. Thanks. So you spend a couple hours thinking that maybe if you call the statement before the script is imported or right after or before that one or after that one, and then you start to change some of the references in your code.

No luck?

The thing is that all references to $ need to be changed.

Let’s go over an example. I was using a script for a neat little widget on a site that I was working on and it sat on top of Scriptaculous (and of course Prototype). When I dropped in the jQuery code… things went all to hell.

Courage Wolf Says its Better to Have Tried and Failed than to Never Try At All
He may be right, but we're not going to fail this time!

The Scriptaculous is not important, we do not have to make any changes to any of that code at all to get your new jQuery code to work. In my example I dropped in a modalbox, one of my favorites called “Sexylightbox“.

I placed my new modalbox code after my old code.

It required these lines to work:


Import/Src these scripts:


jquery.js
jquery.easing.js
sexylightbox.v2.3.jquery.js

Then it also needed to be initialized:

<script type=”text/javascript>

$(document).ready(function(){

SexyLightbox.initialize({color:’black‘, dir: ‘../../images/sexyimages‘});

});
</script>

Then I had to decide what to name my noConflict variable.. in this case I decided to go with $sexy.

So I changed

 

<script type=”text/javascript>

$(document).ready(function(){

SexyLightbox.initialize({color:’black‘, dir: ‘../../images/sexyimages‘});

});
</script>

to

 

<script type=”text/javascript>

$sexy(document).ready(function(){

SexyLightbox.initialize({color:’black‘, dir: ‘../../images/sexyimages‘});

});
</script>

This is just the first step! I made sure to edit sexylightbox.v2.3.jquery.js and I added in this line to the top of the file:


$sexy = jQuery.noConflict();

Then, I completed it with my finish move and in my editor VI I replaced every instance of the $ character with the $sexy string using a global search and replace command while in Escape mode. If you’re more of the GUI type and using BlueFish or SlickEdit or something else, then you should have a “Replace” and then “Replace All Instances of” option under the Find menubar option.

Then as crazy as it may sound, everything just started working perfectly.

The important thing to keep in mind is that every single instance of where jQuery code is using the $, you have to replace it with the new variable you’ve created with the noConflict function. I wish someone had spelled it out that simply for me.. would have saved me hours of wasted time and frustration.

Converting XML to Associative Array in PHP

Sometimes there are situations where I have had code that is expecting an Associative Array with its corresponding values to deal with. However, as can often stand the case when propagating over to XML, sometimes its not possible (or digitally healthy) to convert everything all at once and I end up in a situation where I have all my data in single layer XML objects but need to interact with it on an associate array level.

So, as a quick to fix I wrote this small function entitled xml2AssArray() to deal with the children of a single layer XML object and turn it into an array with the children’s names used as the key-names of the array.

function xml2AssArray($xmlobj)
{
    $assarray = array(); // Initialize the Array
    // Loop through the XML object's children
    foreach ($xmlobj->children() as $child)
    {
        // Assign the childs name as the key for the next entry while assigning the value itself as well
        $assarray[$child->getName()] = $child;
    }
    return $assarray; // Return the new Array
}

Let’s take this XML object (called $myxml which we create using SimpleXML) for example:

<?xml version="1.0"?>
<Lead>
    <ID>1213</ID>
    <SSN>123450000</SSN>
    <FullName>Israel Smith</FullName>
</Lead>

When we run it through our new function, the array that is returned, is now an associate array:

> $myarray = xml2AssArray($myxml);
> echo $myarray['FullName'];
Israel Smith
>

Huzzah!

An example of a web 2.0 pinwheel gradient

HOWTO: Web 2.0 Pinwheel Background Effect made in GIMP

You’ve seen these effects before on peoples websites in the background. I myself wanted to create a large image for this site that I am setting up in a few weeks. We’ll start with creating the gradient, laying it down, applying the correct filters, the final result, as well as some conjecture on making the process more interesting, easier or possibly advancing it.

I wanted to create a particularly large image for this example, so I made a new image with decently size proportions (in this case: 1600×1200 – your own mileage while you create your first test one should probably be smaller)

Create a New Image in GIMP
Creating a new 1600x1200 image in GIMP

Next I created a new gradient by going to the Layers/Channels/Paths/ window, going down to the Brushes / Patterns / Gradients section at the bottom and selecting “New Gradient”.

Create a New Gradient in GIMP
Selecting a New Gradient in GIMP

We now have the Gradient Editor display. We can title the gradient, we can manipulate the gradient by creating & diving sections, we can see what the result will be, zoom-in, zoom-out and save.

GIMP Gradient Editor
A fresh new gradient inside the GIMP gradient editor

The basic original gradient is split up into one Segment which has a left “section” and a “right” section.

When just working with two colors, I set my foreground and background colors in the color tools area as the two respective colors I will be using in my gradient.

Since I want more out of my Gradient than a natual 1 part gradient, we will need to use the “Split Segment at Midpoint” action. Most of the actions inside GIMPs Gradient Editor (and very powerful ones at that) are all accessible by right clicking on the area you want to manipulate.

I begin by right-clicking on the left part of the 2-part segement underneath the gradient, where you can see the white delimiter triangle and its two accompanying black division triangles. Then I select “Split Segment at Midpoint”.

Splitting Segment at Midpoint in GIMP
Selecting the Split Segment at Midpoint option in the GIMP Gradient Editor

We now should have something that looks like the following image, where the gradient now effectively has two segments. A left segment and a right segment (both of which each have a left point and a right point).

A GIMP Gradient with 2 Segments
Inside the GIMP Gradient Editor with a gradient that has 2 Segments

Feel Free to Move the White and Black Triangle Segment Pieces in this Example to Match mine or to create your own original Look

Now that we have our doublly segmented gradient, lets start on changing the colors on the first segment (the left one) by clicking ON that segment, as you can see I am on this next image.

Selecting a GIMP Gradient's Section
Selecting the First (Left) Segment on this GIMP Gradient

You’ll remember that I had chosen my gradient’s two colors ahead of time and setting them as the Foreground and Background colors. So my colors look like this:

Foreground and Background Colors picked in GIMP
I am using an annoying Red and a Depressingly Sick Blue as my Foreground and Background colors respectively for my pinwheel.

So now lets right-click again on the left segment and select “Left Color Type” and choose “Foreground Color”

Then right-click on the left segment once more and select “Right Color Type” and choose “Background Color”.

We’ll do the right (second) segment next but your gradient should now look like the following:

Left Segment in GIMP Gradient has Colors Set
I set the first segment to have its left color be red, and its right color be blue. The right segment stays the same.

To complete setting the colors, we have now clicked (chosen) the second (or right segment) of the gradient and likewise right-clicked to set the Left point as the Background (blue) color and the Right point as the Foreground (red) color.

GIMP Gradient with 2 Segments has both Colors set
The gradient's 2 segments now have their respective end-point colors set.

This makes sure our gradient’s colors have a good flow when they are repeated later in this tutorial. However, I don’t want my pinwheel to have such a soft edge between colors. So we’re going to create a third YES A THIRD segment that will go in the middle of the gradient. So we go ahead and right-click to “Split Segment at Middle Point” again.

GIMP Gradient in Gradient Editor with 3 Segments
Our gradient now has 3 total segment for further manipulation on the gradient's look.

To give the gradient a “harder edge” I begin to move the white and dark triangle segments closer together.

3 Segment Gradient in GIMP with Harder Edged Gradients
The segment pieces in the middle have been moved closer together for a harder look.

Now I am going to go a little more extreme and give blue the most amount of space and take away most of the gradient. After that we’ll be done and can save our new gradient.

A 3-part Segmented Gradient in GIMP is Finished and to be Saved
We are now have the finished three part gradient with two colors and a hard look.

If I were you, I would leave both sides a little more equal, and even allow one segment to have a softer edge/look.

We will now select our fresh spanking new gradient and choose the “Sawtooth wave” repeat option.

Choosing the new custom-made GIMP Gradient

Now lets apply the Gradient to our image by starting at X-coordinate 0 and holding down the Ctrl key so that our gradient line is straight.

Selecting the Area to Lay down the New GIMP Gradient
I've selected just a small portion as I want to the effect to re-peat many times

We should end up with something looking similar to the following:

Newly Minted Background with new Gradient

Then to initiate the Pinwheel Effect we make use of the Polar Coordinates filter.

Polar Coordinates Filter in GIMP

We now have the final product.

Web 2.0 Pinwheel Background
A couple layers of transparent gradient lines later and Voila!

Lastly, I’d like to make mention of a couple different things. First that giving an even harder edge to one side and a slightly (but not so much more) softer gradient look to another when creating your gradient will help give you that look you are seeking. As well increasing/decreasing the size of gradient area or introducing an extremely sharp third color to act as a semi-border between the two major colors.

Another idea would be to make use of the “Transparent” option in the Gradient Editor and using a flat color background in the back.

Either way, enjoy!

Here’s an example of a soft gradient that has more of an equal space for the two color and I’ve overlayed the light color-transparency gradient to run through the middle and the darker color->transparency to run through the top and bottom creating the effect we all know and love.
An example of a web 2.0 pinwheel gradient

PHP Simple Outbound Email API Library

On occasion I find it necessary on a project to setup my mini library for outbound email. I may not need a full set of functionality like the super large libraries (nor do I want the bloat), however, I do have some basic (semi-advanced) features as a requirement.

1. Sending an E-mail should be as Simple as 1 function call
2. Normal Text Mail Support
3. HTML Mail Support
4. Attachment Support

My “email” function which I’ve aptly named “email” can be used like thus:

For a simple E-mail Message:
email($to, $subject, $text_message);

For an E-Mail with both Text and HTML:
email($to, $subject, $text_message, $html_message);

For an E-Mail with just text and an Attachment:

email($to, $subject, $text_message, NULL, $attachment);

Lets go over the lib_email.inc file in 3 separate parts, the global variables/definitions whatever you’d like to call them, support function, and the main function.

Global Variables:


//////////////////////////////////////
// Globals
$__FROM_NAME__ = "Company Name";
$__FROM_ADDR__ = "israel@company.com";

//////////////////////////////////////
// MIME Types
$MediaTypes = array();
// Application Types
$MediaTypes['js']  = 'application/javascript';
$MediaTypes['ogg'] = 'application/ogg';
$MediaTypes['pdf'] = 'application/pdf';
$MediaTypes['ps']  = 'application/postscript';
$MediaTypes['zip'] = 'application/zip';
// Audio
$MediaTypes['mp3'] = 'audio/mpeg';
$MediaTypes['wma'] = 'audio/x-ms-wma';
$MediaTypes['wax'] = 'audio/x-ms-wax';
$MediaTypes['wav'] = 'audio/vnd.wave';
// Image
$MediaTypes['gif']  = 'image/gif';
$MediaTypes['jpg']  = 'image/jpeg';
$MediaTypes['jpeg'] = 'image/jpeg';
$MediaTypes['png']  = 'image/png';
$MediaTypes['svg']  = 'image/svg+xml';
$MediaTypes['tiff'] = 'image/tiff';
$MediaTypes['ico']  = 'image/vnd.microsoft.icon';
// Text
$MediaTypes['css']  = 'text/css';
$MediaTypes['csv']  = 'text/javasccsvript';
$MediaTypes['html'] = 'text/html';
$MediaTypes['txt']  = 'text/plain';
$MediaTypes['xml']  = 'text/xml';
// Video
$MediaTypes['mpg']  = 'video/mpeg';
$MediaTypes['mp4']  = 'video/mp4';
$MediaTypes['qt']   = 'video/quicktime';
$MediaTypes['wmv']  = 'video/x-ms-wmv';
// Other
$MediaTypes['rar']  = 'application/x-rar-compressed';
$MediaTypes['gz']   = 'application/x-gzip-compressed';

You should change __FROM_ADDR__ and __FROM_NAME__ to whatever fits into your project. Also, feel free to add to the MediaTypes array with any and all mime types you think you’ll be using / running across on your project.

We’ll move onto the only support function which I’m calling “createAttachment”. It takes filepath (e.g. /www/whatever/file.exa or ./file.exa) and then determines the filename, filetype and after reading in the file, stores all three bits of information into an associate array that we can use when we call the email() function.

Support Function

//////////////////////////////////////////////////////////////////////////////
// Function: createAttachment()
//////////////////////////////////////////////////////////////////////////////
// Description:
//        Takes a string which points at the file location and creates an
// array to be used by the email() function's $attachment parameter.
//////////////////////////////////////////////////////////////////////////////
// Returns: Array (3 parts; name of the file, mime type, and file contents)
//////////////////////////////////////////////////////////////////////////////
function createAttachment($filename)
{
    global $MediaTypes;
    
    $attachment = array();
    $filelocation   = explode('/', $filename);
    $attachment['filename'] = $filelocation[sizeof($filelocation) - 1];
    $filenameparts  = explode('.', $filename);
    $extension      = $filenameparts[sizeof($filenameparts) - 1];
    if ($MediaTypes[$extension])
    {
        $attachment['filetype'] = $MediaTypes[$extension];
    }
    $attachment['file'] = file_get_contents($filename);

    return $attachment;
}

Simple enough for my purposes, haven’t run across any problems yet.

Now we move onto the main function: email(). it will automatically generate the boundary types and set all of the appropriate headers for an e-mail. I know there are other header(s), and types, however in all my project I’ve never come across the need to use anything other than what this function produces.

If a message (of any type) or an attachment has been passed along, it will appropriately use them respectively and send out the e-mail using your hosts default PHP associated sendmail program/server.

Main Function

//////////////////////////////////////////////////////////////////////////////
// Function: email()
//////////////////////////////////////////////////////////////////////////////
// Description:
//        Takes self-explanatory parameters in order to send an email.
//
//        $to           - String (An email address)
//        $subject      - String (The Subject line)
//        $text_message - String (The body of the E-Mail Message)
//        $html_message - String (The body of the HTML E-Mail Message)
//        $attachment   - Non-Alphanumeric String (File contents)
//////////////////////////////////////////////////////////////////////////////
// See also: createAttachment()
//////////////////////////////////////////////////////////////////////////////
// Returns: Boolean (Based on Success)
//////////////////////////////////////////////////////////////////////////////
function email($to, $subject, $text_message = NULL, $html_message = NULL, $attachment = NULL)
{
    //////////////////////////////////////////
    // Initialize Message String
    $message = '';

    //////////////////////////////////////////
    // Boundary Section
    //////////////////////////////////////////
    // So we know where to look for the start of the data
    //////////////////////////////////////////
    $boundary = uniqid("Part_"); 
    $boundary = '----=_'.$boundary;

    //////////////////////////////////////////
    // Headers Section
    //////////////////////////////////////////
    $headers  = 'To: ' . $to . "rn";
    $headers .= 'From: "'.$__FROM_NAME__.'" <'.$__FROM_ADDR__.'>' . "rn";
    $headers .= 'MIME-Version: 1.0' . "rn";
    $headers .= "Content-Type: multipart/alternative;rn".
            "        boundary="$boundary"rnrn";

    //////////////////////////////////////////
    // Plain Text Message
    //////////////////////////////////////////
    if ($message)
    {
        $message .= "--$boundaryrn".
                "Content-Type: text/plain; charset=UTF-8rn".
                "Content-Transfer-Encoding: 7bitrnrn";
        $message .= $text_message;
        $message .= "rnrnrnrn";
    }

    //////////////////////////////////////////
    // HTML Message
    //////////////////////////////////////////
    if ($html_message)
    {
        $message .= "--$boundaryrn".
                    "Content-Type: text/html; charset=UTF-8rn".
                    "Content-Transfer-Encoding: 7bitrnrn";
        $message .= $html_message;
        $message .= "rn";
    }

    //////////////////////////////////////////
    // Attachment
    //////////////////////////////////////////
    // $attachment should be an array with the
    // filename, filetype, and file entries.
    ////////////////////////////////////////// 
    if ($attachment)
    {
         $message .= "--$boundaryrn".
                     "Content-Type: ".$attachment['filetype']."; name=".$attachment['filename']."rn".
                     "Content-Disposition: attachment; filename=".$attachment['filename']."rn".
                     "Content-Transfer-Encoding: base64rnrn";
         $message .= chunk_split(base64_encode($attachment['file']));
         $message .= "rnrnrnrn";
    }

    if (@mail($to, $subject, $message, $headers))
    {
        return true;
    }
    else 
    {
        return false;
    }
    return true;
}

In theory you should be able to plug this code in and use right away, although having a general understanding of email construction and also on subjects like the 5-point SPAM detection scale (usually dictated by advanced anti-spam products like spamassassin) would be good.

Likewise, you'll notice there isn't much in the way of error-catching, nor multiple attachments.. go ahead and add that in if you please. (If you do, please feel free to share them on here or with me!)

Code Snippets: PHP Function secs2human_time

On one project I was working on, it was driving someone crazy that the amount of time that had passed since an action occurred was being displayed in seconds (which was fine if the event had occurred 15 seconds ago, but not so much when 16,540 had).

I couldn’t find a builtin function (no wonder) that would do what I needed, which was to basically take the seconds and display the time in a human readable format. I set out to do that and came up with what I think works fairly well.

Here’s the code:

//////////////////////////////////////////////////////////
// FUNCTION: secs2human_time
// ///////////////////////////////////////////////////////
// Description:
// 
// This function takes seconds and converts them into a
// human readable format.
//
// If a string is passed it will be converted into an int
//
// ///////////////////////////////////////////////////////
// Parameters:
//     $total      - Amount of time in seconds
// ///////////////////////////////////////////////////////
// Example:
//     write_time_exact(604927);
//     returns: '1 week 2 minutes 7 seconds'
// ///////////////////////////////////////////////////////
// Returns: string - Human readable length of time from seconds
//////////////////////////////////////////////////////////
function secs2human_time($total)
{
    $secsMinute = 60;
    $secsHour   = 3600;
    $secsDay    = 86400;
    $secsWeek   = 604800;
    $secsMonth  = 2592000;
    $secsYear   = 31104000;

    $result = '';

    $seconds = 0;
    $minutes = 0;
    $hours   = 0;
    $days    = 0;
    $weeks   = 0;
    $months  = 0;
    $years   = 0;

    $total = intval($total);

    if (!$total || $total < 0)
        return FALSE;

    if ($total >= $secsYear)
    {
        $years = floor($total / $secsYear);
        $total -= $secsYear * $years;
    }
    if ($total >= $secsMonth)
    {
        $months = floor($total / $secsMonth);
        $total -= $secsMonth * $months;
    }
    if ($total >= $secsWeek)
    {
        $weeks = floor($total / $secsWeek);
        $total -= $secsWeek * $weeks;
    }
    if ($total >= $secsDay)
    {
        $days = floor($total / $secsDay);
        $total -= $secsDay * $days;
    }
    if ($total >= $secsHour)
    {
        $hours = floor($total / $secsHour);
        $total -= $secsHour * $hours;
    }
    if ($total >= $secsMinute)
    {
        $minutes = floor($total / $secsMinute);
        $total -= $secsMinute * $minutes;
    }
    $seconds = $total;

    if ($years)  { $result = $years.' years '; }
    if ($months) { $result = $result.$months.' months '; }
    if ($weeks) { $result = $result.$weeks.' weeks '; }
    if ($days) { $result = $result.$days.' days '; }
    if ($hours) { $result = $result.$hours.' hours '; }
    if ($minutes) { $result = $result.$minutes.' minutes '; }
    if ($seconds) { $result = $result.$seconds.' seconds '; }

    return $result;
}

Now I toyed with the idea of adding in decades, centuries, millenniums, ages, and eons… but I doubt my code will survive long enough to warrant that.

Code Snippets: PHP Function sqldate2timestamp

There are times when I have Dates variables which I’ve retrieved through SQL and they need manipulation sometimes later on in rare circumstances. In an environment where pulling too much data from the SQL DB (extra variations of a field) is bad, but pulling the data in its most basic form (timestamp from the start) costs too many CPU cycles (nobody ever said scripting languages were fast), a function like this comes in handy.

An example:

$my_ts = sqldate2timestamp($sql_date);
echo $my_ts;
1989348943830 (or whatever ;-)

Here’s the Code:

//////////////////////////////////////////////////////////
// FUNCTION: sqldate2timestamp
// ///////////////////////////////////////////////////////
// Description:
// 
// This function takes an SQL date (e.g. 12/31/2001) and
// converts it into a timestamp.
//
// Note: None
// ///////////////////////////////////////////////////////
// Returns: long integer
//////////////////////////////////////////////////////////
function sqldate2timestamp($date)
{
    return mktime(1, 1, 1,
                  substr($date, 0, 2),
                  substr($date, 3, 2),
                  substr($date, 6, 4));
}

Disgustingly simple, but elegant at the same time. (Like all code should be IMHO)