Company Blog

Apr 27th

SQLite Database Class

I have been wanting to try SQLite for some time and I recently got the chance to for a new project.

For the uninitiated:
SQLite is a flat-file database system with most of the functionality of larger database software like MySQL or MSSQL. SQLite is best suited for small footprint, light use databases, handling site newsreels or client contact data.

To start my new project I decided to clone a PHP database class that I have been using for some time for another platform. It does:

  • Database connection/creation.
  • Select, insert, and update queries.
  • Array based insert/update queries for rapid programming.
  • Error reporting on SQLite class functions.
  • Data scrubbing on insert/update queries to prevent issues.

Source Code:

class sqlite_database
{
	protected $link;
	protected $error;
	private $db_path = '/path/to/your/database.db';

	function __construct()
	{
		$this->link = sqlite_open( $this->db_path, 0666, $this->error ) or die ('Error: ' . $this->error);
	}

	function close()
	{
		sqlite_close($this->link);
	}

	function last_id()
	{
		return sqlite_last_insert_rowid($this->link);
	}

	function escape_str( $string )
	{
		return sqlite_escape_string($string);
	}

	function query( $sql )
	{
		$r = sqlite_unbuffered_query($this->link, $sql, SQLITE_ASSOC, $this->error) or die('Error: ' . $this->error . '<br />SQL: ' . $sql);
		if ( !$r )
		{
			return false;
		}
		else
		{
			if ( sqlite_valid($r) )
			{
				$data->dataset = array();
				while ( $row = sqlite_fetch_object($r) )
				{
					$data->dataset[] = $row;
				}
				$data->rows = count($data->dataset);
				return $data;
			}
			else
			{
				return false;
			}
		}
	}

	function query_insert( $table, $data )
	{
		$q = 'INSERT INTO ' . $table;
		$v = '';
		$n = '';
		foreach ( $data as $key => $val )
		{
			$n .= $key . ', ';
			if ( strtolower($val) == 'null' )
			{
				$v .= 'NULL, ';
			}
			elseif (strtolower($val) == 'now()' )
			{
				$v .= 'NOW(), ';
			}
			else
			{
				$v .= "'" . $this->escape_str($val) . "', ";
			}
    	}
		$q .= ' (' . rtrim($n, ', ') . ') VALUES (' . rtrim($v, ', ') . ');';
		$r = sqlite_unbuffered_query($this->link, $q, SQLITE_ASSOC, $this->error) or die('Error: ' . $this->error . '<br />SQL: ' . $q);
		return ( $r ) ? true : false;
	}

	function query_update($table, $data, $where)
	{
		$q = "UPDATE {$table} SET ";
		foreach ( $data as $key => $val )
		{
			if ( strtolower($val) == 'null' )
			{
				$q .= "`$key` = NULL, ";
			}
			elseif ( strtolower($val) == 'now()' )
			{
				$q .= "`$key` = NOW(), ";
			}
			else
			{
				$q .= "`$key`='" . $this->escape_str($val) . "', ";
			}
		}
		foreach ( $where as $key => $val )
		{
			$where_sql .= '( ' . $key[0] . ' ' . $key[1] . ' \'' . $key[2] . '\' ) ';
		}
		$where_sql = substr($where_sql, 0, -1);
		$q = rtrim($q, ', ') . ' WHERE ' . $where_sql . ';';
		$r = sqlite_unbuffered_query($this->link, $q, SQLITE_ASSOC, $this->error) or die('Error: ' . $this->error . '<br />SQL: ' . $q);
		return ( $r ) ? true : false;
	}
}

Examples
Connect to a database:

// require the sqlite database class library from Amyst Design
require('path/to/sqlite.php');
// instantiate the database object
// the path and file name of the database are set within the class
// If the database file doesn't exist SQLite will create the file
$db = new sqlite_database();

Insert a row of data:

// build the array of data to be inserted
// using key/value pairs, set keys to database field names.
$data = array('field1' => $value1,
			  'field2' => $value2,
			  'fieldn' => $valuen);
// assuming the database object has been instantiated
// function will return true or false depending on outcome
$result = $db->query_insert( 'tablename', $data );

Update a row of data:

// build the array of data to be inserted
// using key/value pairs, set keys to database field names.
$data = array('field1' => $value1,
			  'field2' => $value2,
			  'fieldn' => $valuen);
// build the array of criteria
// field name, operator, criteria
// this does not support complex where clauses
$where = array(array('fieldname1', '=', 'value1'),
			   array('fieldname2', '>', 'value2'));
// assuming the database object has been instantiated
// function will return true or false depending on outcome
$result = $db->query_insert( 'tablename', $data, $id_to_update );
Mar 31st

Search for a file and delete it.

This snippet is fairly specific to the task it was required for, a client had a directory on their website that contained literally thousands of folders inside it, not nested just a ton of folders inside of one folder. The task was to search each one of these sub-folders (not recursively to any sub-folders inside these first level ones, just the first level children to the target directory) and search for a file called ‘index.php’ and delete it (the client preferred another file extension be used for the index page).

Think…

-target_directory
   | -subfolder_1
      | -index.html
      | -index.php
   | -subfolder_2
      | -index.html
      | -index.php
   | -subfolder_n
      | -index.html
      | -index.php

// open the target directory
$dh = opendir('/path/to/target/directory');
// iterate through the folders in the target directory
while ( ( $file = readdir($dh) ) !== false )
{
	// only check folders, exclude files and the directory controls
	if ( $file != "." && $file != ".." && !is_file($file) )
	{
		$index_path = $path.'/'.$file.'/'.'index.php';
		// check if 'index.php' exists
		if ( is_file($index_path) )
		{
			// delete 'index.php'
			unlink($index_path);
		}
	}
}
closedir($dh);
Mar 3rd

MySQL copy a row from one table to another.

Recently on a project it became necessary to copy data from one database table to another, identical table. The theory is that once data is data, it is data forever. Meaning this; Just because it isn’t useful information at the moment doesn’t necessarily mean that it will always be useless. Long story short, if you have data… Keep it.

Of course it is possible to just SELECT the data from table_1, INSERT it into table_2 then DELETE the original record from table_1, but why do that when MySQL has built in a shortcut? Enter, the INSERT/SELECT hybrid query.

INSERT INTO table_2
SELECT * FROM table_1 t1
WHERE ( t1.id_field = 'some_unique_id' );

After that, just follow it up with a standard DELETE query to remove the original record.

DELETE FROM table_1
WHERE ( id = 'some_unique_id' );
Feb 28th

Page load time with large loops.

Yesterday, charged with the task of figuring out why a web page [NOT programmed by Amyst Design] was taking upwards of 45.00 sec. to load we successfully reduced load time to a respectable 0.02 sec.

The first order of business was to implement a page load timer, to get real – empirical – data to gauge our improvement.

At the top:

// timestamp function, use this to measure page load time
$time_start = explode(' ', microtime());
$time_start =  $time_start[1] + $time_start[0];

At the bottom:

$time_finish = explode(' ', microtime());
$time_elapsed = $time_finish[0] +  $time_finish[1] - $time_start;
printf('<p style="text-align:center;">Page loaded in %.3f seconds.</p>',  $time_elapsed);

Once this code was in place, loaded the page (25) times on (2) CPUS on the same network and came up with average load time of 46.72 sec.

The page wasn’t particularly complicated, nor did it contain more than the average number of database queries or loops ( for, while, foreach ). After going through all 700+ lines of code from top to bottom and fixing process hogs on nearly every line, thinks like double quote encapsed strings with no variables in them to parse or no real benefit to parsing a variable vs. concatenating a string around a variable. Also mentionable were a great many associative array fixes, more a pet peeve than a real process killer.
From:

$array[key]="string of text with no variable to parse.";

To:

$array['key'] = 'string of text with no variable to parse.';

After all these changes there was no real marked improvement, with an average load time of 42.21 sec it wasn’t a real improvement. That was when a closer look at the loops were taken, and the culprit was found.

$result = mysql_query("SELECT * FROM widgets WHERE ( widget_status = '{$user_selected_status}' );");
while ( $widget = mysql_fetch_object($result) )
{
    // process several data preparation routines than...
    // jump out of the php <?php ?> brackets and print a very, very long XHTML table
}

Looking at this it became immediately apparent that within the while-loop there were at least (11) variables/arrays/objects being defined and re-defined every time the loop iterated, but no where had the programmer unset a single one, leaving the PHP parser to chug like a workhorse through a peat bog in Ireland in June, descriptive yes, and just as deadly.

after implementing:

$result = mysql_query("SELECT * FROM widgets WHERE ( widget_status = '{$user_selected_status}' );");
while ( $widget = mysql_fetch_object($result) )
{
    // process several data preparation routines than...
    // jump out of the php <?php ?> brackets and print a very, very long XHTML table

    // lets cut the parser some slack...
    unset($objects, $arrays, $variables);
}

After the ‘unset()’ fix the average load time of this page dropped to a more expected 0.02 sec.

What do we gather from this? Don’t waste your time and money on hobbyist programmers, your project, your business and ultimately your bottom line will suffer for it.

Feb 21st

Using a mysql update query to increment a field

How many of us have had to increment a MySQL field and done a select query to get the current value, use PHP or another language to increment it, then turn right back around and run an update query.

This little snippet of code will save you two of those steps, and save precious time doing it.

MySQL, being as beautifully simple and functional as it is, will let you increment a field via SQL, no reason to use another language to do it. The snippet below is the query in it its simplest terms.

UPDATE
    table_name
SET
    field_to_increment = field_to_increment + 1
WHERE
   ( id_field =  'some_id' );
« Newer Posts