How to set environment variables that can be referenced by Apache, shells and cron jobs

In some cases, environment variables are used to store configuration information. If the values are referenced from different sources, such as through a web server and on the command line, it is a good idea to define them in a single place and gracefully make them available.

This is one way to set the environment variables in one place, then source them into accounts for use (CentOS 6.4):

1. Create /opt/webapp/etc/appconfig/common and put the environment variables in it

export TEST_ENV_VAR="Test Environment Variable"

2. Add these two lines to /opt/webapp/etc/sysconfig/httpd

if [ -f /opt/webapp/etc/appconfig/common ]; then
. /opt/webapp/etc/appconfig/common
fi

3. Add these two lines to /etc/sysconfig/httpd

if [ -f /opt/webapp/etc/sysconfig/httpd ]; then
. /opt/webapp/etc/sysconfig/httpd
fi

4. Add this line to /etc/httpd/conf.d/webapp.conf (webapp Apache conf file)

PassEnv TEST_ENV_VAR

4. Restart Apache with service httpd restart

5. Test with http://webapp/phpinfo.php (<?php phpinfo(); ?>

6. Add these two lines to /home/admin/.bashrc - or whatever the account is that will use the variables.

if [ -f /opt/webapp/etc/appconfig/common ]; then
. /opt/webapp/etc/appconfig/common
fi

7. Test with echo $TEST_ENV_VAR

What this does is creates a common place to store the environment variables and makes them accessible to both Apache and the shell of admin (and any other account that includes them). That way, when a script is run as a cron job or on the command line, it has the environment variables all set. If new environment variables are needed, or if they change, the common file is updated as well as any others that reference the new variables. Then you restart Apache.

CSS list filter and view

The goal of this fiddle was to provide a CSS and JavaScript method to switch between a list and card or grid view.

It uses jQuery and a very simple filter that fires on keyup.

The code is commented here, you can see it run at http://jsfiddle.net/PbCV3/5/


$(document).ready(function () {

    $("#filter").keyup(function () {
        var filter = $(this).val().toLowerCase();
        var len = filter.length;
        $("li").each(function () {
            /* You may want to use indexOf instead of substring to filter */ 
            if ($(this).html().substring(0, len).toLowerCase() != filter) {
                $(this).addClass('hidden');
            } else {
                $(this).removeClass('hidden');
            }
        });
        /* Check if the list is in card view or list view */
        if ($("ul").hasClass("cards")) {
            cards();
        } else {
            list();
        }
    });
    $("#controls").delegate("button", "click", function () {
        /* The id of the button clicked corresponds to the class of the list */
        var id = $(this).attr("id");
        $("ul").removeClass();
        $("ul").addClass(id);
        if (id == "cards") {
            cards();
        } else {
            list();
        }
    });

    function cards() {
        var count = 0,
            adjacent, adjHeight, thisHeight, newHeight;
        /* The visible pseudo class is a jQuery extension */
        $("li:visible").each(function () {
            /* adjacent is the item of the list which is on the same row */
            adjacent = (count % 2) ? $(this).prev("li:visible") : $(this).next("li:visible");
            if (adjacent) {
                adjHeight = $(adjacent).height();
                thisHeight = $(this).height();
                /* The new height should be the height of the taller item */ 
                newHeight = Math.max(adjHeight, thisHeight);
                if (newHeight == thisHeight) {
                    $(adjacent).height(newHeight);
                } else {
                    $(this).height(newHeight);
                }
            }
            /* count is used to determine whether the item is on the left or right */
            count++;
        });
    }

    function list() {
        /* Restore the heights to auto */
        $("li").each(function () {
            $(this).height("auto");
        });
    }

});

Create a PHP class from a database table

Simple script to get the columns from a database table and write out a PHP class.


$table = preg_replace('/\W/','',$argv[1]);
if (empty($table)) die ('Invalid table'.PHP_EOL);

try {
	$dbh = new PDO('mysql:host=localhost;dbname=test', 'root');

	$className = ucfirst($table);
	echo <<<START
<?php
Class Model_$className
	extends Model_Abstract {

START;

	$query = $dbh->query('DESCRIBE '.$argv[1]);
	$columns = $query->fetchAll(PDO::FETCH_CLASS);
	foreach ($columns as $row) {
		echo "\tprivate \${$row->Field};\n";
	}
echo '}';
} catch (PDOException $e) {
    print "Error!: " . $e->getMessage() . "
"; die(); } ?>

Open Source Software and House Paint

If you think about it, free or inexpensive open source software is like house paint. The product is readily available and doesn't cost a lot, but can be very valuable. A good open source software system such as a content management system, ecommerce system, forum or blog can transition a simple site into one that offers site visitors services and may provide important revenue for a company. A can of paint can transform a worn exterior or tired interior into fresh welcoming walls, making a home more attractive and valuable.

In both cases the most important element is the skill used to apply the product.

Software must be visually appealing, easy to use, and it must work. A designer or user interface person can layout the page, a developer must code the HTML and it must then be integrated into the system. Installation, configuration and customization are required to bring the application to life. Simply put, most powerful open source software requires a significant amount of skill and experience across the full spectrum of web development.

The same is true of paint and parallels the skills required for software. From a design perspective, the color and finish must be chosen carefully to match where the paint will be used. The walls must be prepared, including thorough removal of any wallpaper, patching any holes or dents, the floor must be covered, and areas that require masking tape have to be readied. Choosing the right tools is important, from ladders to paint brushes.

What's the point of this post?

That the expense of the paint or software doesn't reflect the cost to benefit from it.

Many people assume that because the software is free it shouldn't cost anything if they want to use it on their site. If there is a web company that is using that product, there is usually a significant skill investment required. Those skills are the difference between a secure, polished, functional, reliable and stable site and an awkward site that is far less credible.

Yesterday I bought a gallon of light blue paint for about $25. The walls had been prepared a few weeks ago, there was probably 10 hours of work stripping off the old wallpaper, soaking off the paper backing, and removing the wallpaper paste. A small can of spackle filled in the minor imperfections. The first coat of paint took three hours to apply and it came out nicely. It is mostly evenly distributed, there is very little paint where it shouldn't be, and the finish is fairly uniform. One more coat will complete the project. The true cost of the project is the labor to put the paint on the wall nicely, not the can of paint itself. Just like open source software.

PHP - Sorting Objects - Performance Considerations

PHP has some great functions for sorting arrays, however, they should be used with care.

If you have an array of complex objects and plan to sort only on one value, you may see significant performance gains if you flatten the array into a single dimension and use the simpler library functions. The test run posted here shows a 10x improvement.

This is a very simple demonstration script that creates an array of 100 objects with a random value and timestamp. The array is sorted in ascending and descending order.

Sample output

Sorting an array of objects
------------------------------
uAsortBiDir ASC
Elapsed 0.001910924911499ms
uAsortUniDir ASC
Elapsed 0.0020918846130371ms
uAsortBiDir DESC
Elapsed 0.0018858909606934ms
uAsortUniDir DESC
Elapsed 0.0021059513092041ms

Sorting a flattened array
------------------------------
asort
Elapsed 0.00023484230041504ms
arsort (Reverse)
Elapsed 0.00020194053649902ms

<?php

// Arbitrary constants
define ('LIMIT',100);
define ('MIN', 0);
define ('MAX', 100);

// An array of objects 
$arr = array();
for ($i = 0; $i < LIMIT; $i++) {
	$arr[] = new Item(rand(MIN, MAX), microtime(true));
}

echo 'Sorting an array of objects'.PHP_EOL;
echo str_repeat('-',30).PHP_EOL;
$sorter = new Sorter;
echo 'uAsortBiDir ASC'.PHP_EOL;
$start = microtime(true);
uasort($arr, array($sorter, 'uAsortBiDir'));
$end= microtime(true);
echo 'Elapsed '.($end - $start).'ms'.PHP_EOL;

shuffle($arr);

echo 'uAsortUniDir ASC'.PHP_EOL;
$start = microtime(true);
uasort($arr, array($sorter, 'uAsortUniDir'));
$end= microtime(true);
echo 'Elapsed '.($end - $start).'ms'.PHP_EOL;

shuffle($arr);

$sorter = new Sorter(Sorter::DESC);
echo 'uAsortBiDir DESC'.PHP_EOL;
$start = microtime(true);
uasort($arr, array($sorter, 'uAsortBiDir'));
$end= microtime(true);
echo 'Elapsed '.($end - $start).'ms'.PHP_EOL;

shuffle($arr);

echo 'uAsortUniDir DESC'.PHP_EOL;
$start = microtime(true);
uasort($arr, array($sorter, 'uAsortUniDir'));
$arr = array_reverse($arr);
$end= microtime(true);
echo 'Elapsed '.($end - $start).'ms'.PHP_EOL;

shuffle($arr);

echo PHP_EOL;

echo 'Sorting a flattened array'.PHP_EOL;
echo str_repeat('-',30).PHP_EOL;
echo 'asort'.PHP_EOL;
$start = microtime(true);
$flat = array();
foreach ($arr as $index => $item) {
	$flat[$index] = $item->value;
}
asort($flat);
$new = array();
foreach ($flat as $index => $item) {
	$new[$index] = $arr[$index];
}
$end= microtime(true);
echo 'Elapsed '.($end - $start).'ms'.PHP_EOL;

shuffle($arr);

echo 'arsort (Reverse)'.PHP_EOL;
$start = microtime(true);
$flat = array();
foreach ($arr as $index => $item) {
	$flat[$index] = $item->value;
}
arsort($flat);
$new = array();
foreach ($flat as $index => $item) {
	$new[$index] = $arr[$index];
}
$end= microtime(true);
echo 'Elapsed '.($end - $start).'ms'.PHP_EOL;

Class Item {
	public $data = array();
	
	function __construct($value, $timestamp) {
		$this->data['value'] = $value;
		$this->data['timestamp'] = $timestamp;
	}

	function __get($property) {
		return $this->data[$property];
	}
}

Class Sorter {

	const ASC = 'asc';
	const DESC = 'desc';

	protected $dir;

	function __construct($dir = self::ASC) {
		$this->dir = $dir;
	}

	function uAsortBiDir($a, $b) {
		$cmp = ($a->value < $b->value);
		if ($this->dir === self::DESC) $cmp != $cmp;
		return $cmp;
	}

	function uAsortUniDir($a, $b) {
		$cmp = ($a->value < $b->value);
		return $cmp;
	}
}