2009-09-20 02:53:15 +00:00
< ? php
/*
Copyright ( c ) 2005 Luke Plant < L . Plant . 98 @ cantab . net >
Permission is hereby granted , free of charge , to any person obtaining a copy of this software and
associated documentation files ( the " Software " ), to deal in the Software without restriction , including
without limitation the rights to use , copy , modify , merge , publish , distribute , sublicense , and / or
sell copies of the Software , and to permit persons to whom the Software is furnished to do so , subject
to the following conditions :
The above copyright notice and this permission notice shall be included in all copies or substantial
portions of the Software .
THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR IMPLIED , INCLUDING BUT NOT
LIMITED TO THE WARRANTIES OF MERCHANTABILITY , FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN
NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER LIABILITY ,
WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING FROM , OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE .
*/
/**
* Simple but powerful flatfile database
* See http :// lukeplant . me . uk / resources / flatfile / for documentation and examples
*
* @ tutorial flatfile . pkg
* @ package flatfile
* @ license http :// www . opensource . org / licenses / mit - license . php
*/
2014-06-24 19:51:22 +00:00
require_once ( 'flatfile_utils.php' );
2009-09-20 02:53:15 +00:00
/** Used to indicate the default comparison should be done, which is STRING_COMPARISON in the absence of a schema, or whatever the schema specifies if one has been added */
define ( 'DEFAULT_COMPARISON' , '' );
/** Used to indicate a comparison should be done as a string comparison */
define ( 'STRING_COMPARISON' , 'strcmp' );
/** Used to indicate a comparison should be done as an integer comparison */
define ( 'INTEGER_COMPARISON' , 'intcmp' );
/** Used to indicate a comparison should be done as a numeric (float) comparison */
define ( 'NUMERIC_COMPARISON' , 'numcmp' );
/** Indicates ascending order */
define ( 'ASCENDING' , 1 );
/** Indicates descending order */
define ( 'DESCENDING' , - 1 );
$comparison_type_for_col_type = array (
INT_COL => INTEGER_COMPARISON ,
DATE_COL => INTEGER_COMPARISON , // assume Unix timestamps
STRING_COL => STRING_COMPARISON ,
FLOAT_COL => NUMERIC_COMPARISON
);
2014-06-24 19:51:22 +00:00
function get_comparison_type_for_col_type ( $coltype ) {
2009-09-20 02:53:15 +00:00
global $comparison_type_for_col_type ;
return $comparison_type_for_col_type [ $coltype ];
}
/**
* Provides simple but powerful flatfile database storage and retrieval
*
* Includes equivalents to SELECT * FROM table WHERE ... , DELETE WHERE ...
* UPDATE and more . All files are stored in the { @ link Flatfile :: $datadir $datadir } directory ,
* and table names are just filenames in that directory . Subdirectories
* can be used just by specifying a table name that includes the directory name .
* @ package flatfile
*/
class Flatfile {
/** @access private */
var $tables ;
/** @access private */
var $schemata ;
2014-06-24 19:51:22 +00:00
/** The directory to store files in .
2009-09-20 02:53:15 +00:00
* @ var string
*/
var $datadir ;
2014-06-24 19:51:22 +00:00
function Flatfile () {
2009-09-20 02:53:15 +00:00
$this -> schemata = array ();
}
/**
* Get all rows from a table
2014-06-24 19:51:22 +00:00
* @ param string $tablename The table to get rows from
2009-09-20 02:53:15 +00:00
* @ return array The table as an array of rows , where each row is an array of columns
*/
2014-06-24 19:51:22 +00:00
function selectAll ( $tablename ) {
2009-09-20 02:53:15 +00:00
if ( ! isset ( $this -> tables [ $tablename ]))
$this -> loadTable ( $tablename );
2014-06-24 19:51:22 +00:00
return $this -> tables [ $tablename ];
2009-09-20 02:53:15 +00:00
}
2014-06-24 19:51:22 +00:00
2009-09-20 02:53:15 +00:00
/**
* Selects rows from a table that match the specified criteria
*
* This simulates the following SQL query :
* < pre >
* SELECT LIMIT $limit * FROM $tablename
* WHERE $whereclause
* ORDER BY $orderBy [ ASC | DESC ] [, $orderBy2 ... ]
* </ pre >
*
2014-06-24 19:51:22 +00:00
* @ param string $tablename The table ( file ) to get the data from
* @ param object $whereClause Either a { @ link WhereClause WhereClause } object to do selection of rows , or NULL to select all
* @ param mixed $limit Specifies limits for the rows returned :
2009-09-20 02:53:15 +00:00
* - use - 1 or omitted to return all rows
* - use an integer n to return the first n rows
* - use a two item array ( $startrow , $endrow ) to return rows $startrow to $endrow - 1 ( zero indexed )
* - use a two item array ( $startrow , - 1 ) to return rows $startrow to the end ( zero indexed )
2014-06-24 19:51:22 +00:00
* @ param mixed $orderBy Either an { @ link OrderBy } object or an array of them , defining the sorting that should be applied ( if an array , then the first object in the array is the first key to sort on etc ) . Use NULL for no sorting .
2009-09-20 02:53:15 +00:00
* @ return array The matching data , as an array of rows , where each row is an array of columns
*/
2014-06-24 19:51:22 +00:00
function selectWhere ( $tablename , $whereClause , $limit = - 1 , $orderBy = NULL ) {
2009-09-20 02:53:15 +00:00
if ( ! isset ( $this -> tables [ $tablename ]))
$this -> loadTable ( $tablename );
2014-06-24 19:51:22 +00:00
2009-09-20 02:53:15 +00:00
$table = $this -> selectAll ( $tablename ); // Get a copy
2014-06-24 19:51:22 +00:00
2009-09-20 02:53:15 +00:00
$schema = $this -> getSchema ( $tablename );
if ( $orderBy !== NULL )
usort ( $table , $this -> getOrderByFunction ( $orderBy , $schema ));
2014-06-24 19:51:22 +00:00
2009-09-20 02:53:15 +00:00
$results = array ();
$count = 0 ;
if ( $limit == - 1 )
$limit = array ( 0 , - 1 );
else if ( ! is_array ( $limit ))
$limit = array ( 0 , $limit );
2014-06-24 19:51:22 +00:00
2009-09-20 02:53:15 +00:00
foreach ( $table as $row ) {
if ( $whereClause === NULL || $whereClause -> testRow ( $row , $schema )) {
2014-06-24 19:51:22 +00:00
if ( $count >= $limit [ 0 ])
2009-09-20 02:53:15 +00:00
$results [] = $row ;
++ $count ;
if (( $count >= $limit [ 1 ]) && ( $limit [ 1 ] != - 1 ))
break ;
}
}
return $results ;
}
2014-06-24 19:51:22 +00:00
2009-09-20 02:53:15 +00:00
/**
* Select a row using a unique ID
2014-06-24 19:51:22 +00:00
* @ param string $tablename The table to get data from
* @ param string $idField The index of the field containing the ID
* @ param string $id The ID to search for
* @ return array The row of the table as an array
2009-09-20 02:53:15 +00:00
*/
2014-06-24 19:51:22 +00:00
function selectUnique ( $tablename , $idField , $id ) {
2009-09-20 02:53:15 +00:00
$result = $this -> selectWhere ( $tablename , new SimpleWhereClause ( $idField , '=' , $id ));
if ( count ( $result ) > 0 )
return $result [ 0 ];
else
return array ();
}
2014-06-24 19:51:22 +00:00
2009-09-20 02:53:15 +00:00
/*
* To correctly write a file , and not overwrite the changes
* another process is making , we need to :
* - get a lock for writing
* - read its contents from disc
* - modify the contents in memory
* - write the contents
* - release lock
* Because opening for writing truncates the file , we must get
* the lock on a different file . getLock and releaseLock
* are helper functions to allow us to do this with little fuss
*/
2014-06-24 19:51:22 +00:00
2009-09-20 02:53:15 +00:00
/** Get a lock for writing a file
* @ access private
*/
2014-06-24 19:51:22 +00:00
function getLock ( $tablename ) {
2009-09-20 02:53:15 +00:00
ignore_user_abort ( true );
2014-06-24 19:51:22 +00:00
$fp = fopen ( $this -> datadir . $tablename . '.lock' , 'w' );
2009-09-20 02:53:15 +00:00
if ( ! flock ( $fp , LOCK_EX )) {
2014-06-24 19:51:22 +00:00
// log error?
2009-09-20 02:53:15 +00:00
}
$this -> loadTable ( $tablename );
return $fp ;
}
2014-06-24 19:51:22 +00:00
2009-09-20 02:53:15 +00:00
/** Release a lock
* @ access private
*/
2014-06-24 19:51:22 +00:00
function releaseLock ( $lockfp ) {
2009-09-20 02:53:15 +00:00
flock ( $lockfp , LOCK_UN );
ignore_user_abort ( false );
}
2014-06-24 19:51:22 +00:00
2009-09-20 02:53:15 +00:00
/**
* Inserts a row with an automatically generated ID
*
* The autogenerated ID will be the highest ID in the column so far plus one . The
2014-06-24 19:51:22 +00:00
* supplied row should include all fields required for the table , and the
2009-09-20 02:53:15 +00:00
* ID field it contains will just be ignored
*
2014-06-24 19:51:22 +00:00
* @ param string $tablename The table to insert data into
* @ param int $idField The index of the field which is the ID field
* @ param array $newRow The new row to add to the table
* @ return int The newly assigned ID
2009-09-20 02:53:15 +00:00
*/
2014-06-24 19:51:22 +00:00
function insertWithAutoId ( $tablename , $idField , $newRow ) {
2009-09-20 02:53:15 +00:00
$lockfp = $this -> getLock ( $tablename );
2014-06-24 19:51:22 +00:00
$rows = $this -> selectWhere ( $tablename , null , 1 ,
new OrderBy ( $idField , DESCENDING , INTEGER_COMPARISON ));
2009-09-20 02:53:15 +00:00
if ( $rows ) {
$newId = $rows [ 0 ][ $idField ] + 1 ;
} else {
$newId = 1 ;
}
$newRow [ $idField ] = $newId ;
$this -> tables [ $tablename ][] = $newRow ;
$this -> writeTable ( $tablename );
$this -> releaseLock ( $lockfp );
return $newId ;
}
/**
* Inserts a row in a table
*
2014-06-24 19:51:22 +00:00
* @ param string $tablename The table to insert data into
* @ param array $newRow The new row to add to the table
2009-09-20 02:53:15 +00:00
*/
2014-06-24 19:51:22 +00:00
function insert ( $tablename , $newRow ) {
$lockfp = $this -> getLock ( $tablename );
2009-09-20 02:53:15 +00:00
$this -> tables [ $tablename ][] = $newRow ;
$this -> writeTable ( $tablename );
$this -> releaseLock ( $lockfp );
}
2014-06-24 19:51:22 +00:00
2009-09-20 02:53:15 +00:00
/**
* Updates an existing row using a unique ID
*
2014-06-24 19:51:22 +00:00
* @ param string $tablename The table to update
* @ param int $idField The index of the field which is the ID field
* @ param array $updatedRow The updated row to add to the table
2009-09-20 02:53:15 +00:00
*/
2014-06-24 19:51:22 +00:00
function updateRowById ( $tablename , $idField , $updatedRow ) {
$this -> updateSetWhere ( $tablename , $updatedRow ,
2009-09-20 02:53:15 +00:00
new SimpleWhereClause ( $idField , '=' , $updatedRow [ $idField ]));
}
2014-06-24 19:51:22 +00:00
2009-09-20 02:53:15 +00:00
/**
* Updates fields in a table for rows that match the provided criteria
2014-06-24 19:51:22 +00:00
*
2009-09-20 02:53:15 +00:00
* $newFields can be a complete row or it can be a sparsely populated
* hashtable of values ( where the keys are integers which are the column
* indexes to update )
*
2014-06-24 19:51:22 +00:00
* @ param string $tablename The table to update
* @ param array $newFields A hashtable ( with integer keys ) of fields to update
* @ param WhereClause $whereClause The criteria or NULL to update all rows
2009-09-20 02:53:15 +00:00
*/
2014-06-24 19:51:22 +00:00
function updateSetWhere ( $tablename , $newFields , $whereClause ) {
2009-09-20 02:53:15 +00:00
$schema = $this -> getSchema ( $tablename );
$lockfp = $this -> getLock ( $tablename );
for ( $i = 0 ; $i < count ( $this -> tables [ $tablename ]); ++ $i ) {
if ( $whereClause === NULL ||
2014-06-24 19:51:22 +00:00
$whereClause -> testRow ( $this -> tables [ $tablename ][ $i ], $schema )
) {
foreach ( $newFields as $k => $v ) {
2009-09-20 02:53:15 +00:00
$this -> tables [ $tablename ][ $i ][ $k ] = $v ;
}
}
}
$this -> writeTable ( $tablename );
$this -> releaseLock ( $lockfp );
$this -> loadTable ( $tablename );
}
2014-06-24 19:51:22 +00:00
2009-09-20 02:53:15 +00:00
/**
* Deletes all rows in a table that match specified criteria
*
2014-06-24 19:51:22 +00:00
* @ param string $tablename The table to alter
* @ param object $whereClause . { @ link WhereClause WhereClause } object that will select
2009-09-20 02:53:15 +00:00
* rows to be deleted . All rows are deleted if $whereClause === NULL
*/
2014-06-24 19:51:22 +00:00
function deleteWhere ( $tablename , $whereClause ) {
2009-09-20 02:53:15 +00:00
$schema = $this -> getSchema ( $tablename );
2014-06-24 19:51:22 +00:00
$lockfp = $this -> getLock ( $tablename );
for ( $i = count ( $this -> tables [ $tablename ]) - 1 ; $i >= 0 ; -- $i ) {
2009-09-20 02:53:15 +00:00
if ( $whereClause === NULL ||
2014-06-24 19:51:22 +00:00
$whereClause -> testRow ( $this -> tables [ $tablename ][ $i ], $schema )
) {
2009-09-20 02:53:15 +00:00
unset ( $this -> tables [ $tablename ][ $i ]);
}
}
$this -> writeTable ( $tablename );
$this -> releaseLock ( $lockfp );
$this -> loadTable ( $tablename ); // reset array indexes
}
2014-06-24 19:51:22 +00:00
2009-09-20 02:53:15 +00:00
/**
* Delete all rows in a table
*
2014-06-24 19:51:22 +00:00
* @ param string $tablename The table to alter
2009-09-20 02:53:15 +00:00
*/
2014-06-24 19:51:22 +00:00
function deleteAll ( $tablename ) {
2009-09-20 02:53:15 +00:00
$this -> deleteWhere ( $tablename , NULL );
}
/** #@+
* @ access private
*/
2014-06-24 19:51:22 +00:00
2009-09-20 02:53:15 +00:00
/** Gets a function that can be passed to usort to do the ORDER BY clause
2014-06-24 19:51:22 +00:00
* @ param mixed $orderBy Either an OrderBy object or an array of them
2009-09-20 02:53:15 +00:00
* @ return string function name
*/
2014-06-24 19:51:22 +00:00
function getOrderByFunction ( $orderBy , $rowSchema = null ) {
2009-09-20 02:53:15 +00:00
$orderer = new Orderer ( $orderBy , $rowSchema );
return array ( & $orderer , 'compare' );
}
2014-06-24 19:51:22 +00:00
function loadTable ( $tablename ) {
2009-09-20 02:53:15 +00:00
$filedata = @ file ( $this -> datadir . $tablename );
$table = array ();
if ( is_array ( $filedata )) {
foreach ( $filedata as $line ) {
$line = rtrim ( $line , " \n " );
$table [] = explode ( " \t " , $line );
}
}
$this -> tables [ $tablename ] = $table ;
}
2014-06-24 19:51:22 +00:00
function writeTable ( $tablename ) {
2009-09-20 02:53:15 +00:00
$output = '' ;
2014-06-24 19:51:22 +00:00
2009-09-20 02:53:15 +00:00
foreach ( $this -> tables [ $tablename ] as $row ) {
$keys = array_keys ( $row );
rsort ( $keys , SORT_NUMERIC );
$max = $keys [ 0 ];
for ( $i = 0 ; $i <= $max ; ++ $i ) {
if ( $i > 0 ) $output .= " \t " ;
2013-01-17 01:35:41 +00:00
$data = ( ! isset ( $row [ $i ]) ? '' : $row [ $i ]);
2014-06-24 19:51:22 +00:00
$output .= str_replace ( array ( " \t " , " \r " , " \n " ), array ( '' ), $data );
2009-09-20 02:53:15 +00:00
}
$output .= " \n " ;
}
$fp = @ fopen ( $this -> datadir . $tablename , " w " );
fwrite ( $fp , $output , strlen ( $output ));
fclose ( $fp );
}
/**#@-*/
/**
* Adds a schema definition to the DB for a specified regular expression
2014-06-24 19:51:22 +00:00
*
2009-09-20 02:53:15 +00:00
* Schemas are optional , and are only used for automatically determining
* the comparison types that should be used when sorting and selecting .
2014-06-24 19:51:22 +00:00
*
* @ param string $fileregex A regular expression used to match filenames
* @ param string $rowSchema An array specifying the column types for data
2009-09-20 02:53:15 +00:00
* files that match the regex , using constants defined in flatfile_utils . php
*/
2014-06-24 19:51:22 +00:00
function addSchema ( $fileregex , $rowSchema ) {
2009-09-20 02:53:15 +00:00
array_push ( $this -> schemata , array ( $fileregex , $rowSchema ));
}
/** Retrieves the schema for a given filename */
2014-06-24 19:51:22 +00:00
function getSchema ( $filename ) {
foreach ( $this -> schemata as $rowSchemaPair ) {
2009-09-20 02:53:15 +00:00
$fileregex = $rowSchemaPair [ 0 ];
2014-06-24 19:51:22 +00:00
if ( preg_match ( $fileregex , $filename )) {
2009-09-20 02:53:15 +00:00
return $rowSchemaPair [ 1 ];
}
}
return null ;
}
2014-06-24 19:51:22 +00:00
2009-09-20 02:53:15 +00:00
}
2014-06-24 19:51:22 +00:00
2009-09-20 02:53:15 +00:00
/////////////////////////// UTILITY FUNCTIONS ////////////////////////////////////
2014-06-24 19:51:22 +00:00
/**
* equivalent of strcmp for comparing integers , used internally for sorting and comparing
2009-09-20 02:53:15 +00:00
*/
2014-06-24 19:51:22 +00:00
function intcmp ( $a , $b ) {
2009-09-20 02:53:15 +00:00
return ( int ) $a - ( int ) $b ;
}
2014-06-24 19:51:22 +00:00
/**
* equivalent of strcmp for comparing floats , used internally for sorting and comparing
2009-09-20 02:53:15 +00:00
*/
2014-06-24 19:51:22 +00:00
function numcmp ( $a , $b ) {
2009-09-20 02:53:15 +00:00
return ( float ) $a - ( float ) $b ;
}
/////////////////////////// WHERE CLAUSE CLASSES ////////////////////////////////////
/**
* Used to test rows in a database table , like the WHERE clause in an SQL statement .
*
* @ abstract
* @ package flatfile
*/
2014-06-24 19:51:22 +00:00
class WhereClause {
2009-09-20 02:53:15 +00:00
/**
* Tests a table row object
* @ abstract
2014-06-24 19:51:22 +00:00
* @ param array $row The row to test
* @ param array $rowSchema An optional array specifying the schema of the table , using the INT_COL , STRING_COL etc constants
2009-09-20 02:53:15 +00:00
* @ return bool True if the $row passes the WhereClause
* selection criteria , false otherwise
*/
2014-06-24 19:51:22 +00:00
function testRow ( $row , $rowSchema = null ) {
}
2009-09-20 02:53:15 +00:00
}
/**
* Negates a where clause
* @ package flatfile
*/
2014-06-24 19:51:22 +00:00
class NotWhere extends WhereClause {
2009-09-20 02:53:15 +00:00
/** @access private */
var $clause ;
2014-06-24 19:51:22 +00:00
2009-09-20 02:53:15 +00:00
/**
* Contructs a new NotWhere object
*
2014-06-24 19:51:22 +00:00
* The constructed WhereClause will return the negation
2009-09-20 02:53:15 +00:00
* of the WhereClause object passed in when testing rows .
* @ param WhereClause $whereclause The WhereClause object to negate
*/
2014-06-24 19:51:22 +00:00
function NotWhere ( $whereclause ) {
2009-09-20 02:53:15 +00:00
$this -> clause = $whereclause ;
}
2014-06-24 19:51:22 +00:00
function testRow ( $row , $rowSchema = null ) {
2009-09-20 02:53:15 +00:00
return ! $this -> clause -> testRow ( $row , $rowSchema );
}
}
/**
* Implements a single WHERE clause that does simple comparisons of a field
* with a value .
*
* @ package flatfile
*/
2014-06-24 19:51:22 +00:00
class SimpleWhereClause extends WhereClause {
2009-09-20 02:53:15 +00:00
/** #@+
* @ access private
*/
var $field ;
var $operator ;
var $value ;
var $compare_type ;
/**#@-*/
/**
* Creates a new { @ link WhereClause WhereClause } object that does a comparison
* of a field and a value .
*
* This will be the most commonly used type of WHERE clause . It can do comparisons
* of the sort " $tablerow[$field] operator $value "
* where 'operator' is one of :< br >
* - = ( equals )
* - != ( not equals )
* - > ( greater than )
* - < ( less than )
* - >= ( greater than or equal to )
* - <= ( less than or equal to )
* There are 3 pre - defined constants ( STRING_COMPARISON , NUMERIC COMPARISON and
* INTEGER_COMPARISON ) that modify the behaviour of these operators to do the comparison
2014-06-24 19:51:22 +00:00
* as strings , floats and integers respectively . Howevers , these constants are
2009-09-20 02:53:15 +00:00
* just the names of functions that do the comparison ( the first being the builtin
2014-06-24 19:51:22 +00:00
* function { @ link strcmp strcmp ()}, so you can supply your own function here to customise the
2009-09-20 02:53:15 +00:00
* behaviour of this class .
2014-06-24 19:51:22 +00:00
*
* @ param int $field The index ( in the table row ) of the field to test
* @ param string $operator The comparison operator , one of " = " , " != " , " < " , " > " , " <= " , " >= "
* @ param mixed $value The value to compare to .
* @ param string $compare_type The comparison method to use - either
2009-09-20 02:53:15 +00:00
* STRING_COMPARISON ( default ), NUMERIC COMPARISON or INTEGER_COMPARISON
*
*/
2014-06-24 19:51:22 +00:00
function SimpleWhereClause ( $field , $operator , $value , $compare_type = DEFAULT_COMPARISON ) {
2009-09-20 02:53:15 +00:00
$this -> field = $field ;
$this -> operator = $operator ;
$this -> value = $value ;
$this -> compare_type = $compare_type ;
}
2014-06-24 19:51:22 +00:00
function testRow ( $tablerow , $rowSchema = null ) {
2009-09-20 02:53:15 +00:00
if ( $this -> field < 0 )
return TRUE ;
2014-06-24 19:51:22 +00:00
2009-09-20 02:53:15 +00:00
$cmpfunc = $this -> compare_type ;
2014-06-24 19:51:22 +00:00
if ( $cmpfunc == DEFAULT_COMPARISON ) {
if ( $rowSchema != null ) {
2009-09-20 02:53:15 +00:00
$cmpfunc = get_comparison_type_for_col_type ( $rowSchema [ $this -> field ]);
2014-06-24 19:51:22 +00:00
} else {
2009-09-20 02:53:15 +00:00
$cmpfunc = STRING_COMPARISON ;
}
}
2014-06-24 19:51:22 +00:00
2009-09-20 02:53:15 +00:00
if ( $this -> field >= count ( $tablerow )) {
$dbval = " " ;
} else {
$dbval = $tablerow [ $this -> field ];
}
$cmp = $cmpfunc ( $dbval , $this -> value );
if ( $this -> operator == '=' )
return ( $cmp == 0 );
else if ( $this -> operator == '!=' )
return ( $cmp != 0 );
else if ( $this -> operator == '>' )
return ( $cmp > 0 );
else if ( $this -> operator == '<' )
return ( $cmp < 0 );
else if ( $this -> operator == '<=' )
return ( $cmp <= 0 );
else if ( $this -> operator == '>=' )
return ( $cmp >= 0 );
2014-06-24 19:51:22 +00:00
2009-09-20 02:53:15 +00:00
return FALSE ;
}
}
/**
* { @ link WhereClause WhereClause } class to work like a SQL 'LIKE' clause
* @ package flatfile
*/
2014-06-24 19:51:22 +00:00
class LikeWhereClause extends WhereClause {
2009-09-20 02:53:15 +00:00
/**
2014-06-24 19:51:22 +00:00
* Creates a new LikeWhereClause
2009-09-20 02:53:15 +00:00
*
2014-06-24 19:51:22 +00:00
* @ param int $field Index of the field to look at
* @ param string $value Value to look for . Supports using '%' as a
2009-09-20 02:53:15 +00:00
* wildcard , and is case insensitve . e . g . 'test%' will match 'TESTS' and 'Testing'
*/
2014-06-24 19:51:22 +00:00
function LikeWhereClause ( $field , $value ) {
2009-09-20 02:53:15 +00:00
$this -> field = $field ;
2014-06-24 19:51:22 +00:00
$this -> regexp = '/^' . str_replace ( '%' , '.*' , preg_quote ( $value )) . '$/i' ;
2009-09-20 02:53:15 +00:00
}
2014-06-24 19:51:22 +00:00
function testRow ( $tablerow , $rowSchema = NULL ) {
2009-09-20 02:53:15 +00:00
return preg_match ( $this -> regexp , $tablerow [ $this -> field ]);
}
}
/**
* { @ link WhereClause WhereClause } class to match a value from a list of items
* @ package flatfile
*/
class ListWhereClause extends WhereClause {
/** @access private */
var $field ;
/** @access private */
var $list ;
/** @access private */
var $compareAs ;
2014-06-24 19:51:22 +00:00
2009-09-20 02:53:15 +00:00
/**
* Creates a new ListWhereClause object
*
* The resulting WhereClause will pass rows ( return true ) if the value of the specified
* field is in the array .
2014-06-24 19:51:22 +00:00
*
* @ param int $field Field to match
* @ param array $list List of items
2009-09-20 02:53:15 +00:00
* @ param string $compare_type Comparison type , string by default .
*/
2014-06-24 19:51:22 +00:00
function ListWhereClause ( $field , $list , $compare_type = DEFAULT_COMPARISON ) {
2009-09-20 02:53:15 +00:00
$this -> list = $list ;
$this -> field = ( int ) $field ;
$this -> compareAs = $compare_type ;
}
2014-06-24 19:51:22 +00:00
function testRow ( $tablerow , $rowSchema = null ) {
2009-09-20 02:53:15 +00:00
$func = $this -> compareAs ;
2014-06-24 19:51:22 +00:00
if ( $func == DEFAULT_COMPARISON ) {
if ( $rowSchema ) {
2009-09-20 02:53:15 +00:00
$func = get_comparison_type_for_col_type ( $rowSchema [ $this -> field ]);
2014-06-24 19:51:22 +00:00
} else {
2009-09-20 02:53:15 +00:00
$func = STRING_COMPARISON ;
}
}
2014-06-24 19:51:22 +00:00
foreach ( $this -> list as $item ) {
if ( $func ( $tablerow [ $this -> field ], $item ) == 0 )
2009-09-20 02:53:15 +00:00
return true ;
}
return false ;
}
}
/**
* Abstract class that combines zero or more { @ link WhereClause WhereClause } objects
* together .
* @ package flatfile
2014-06-24 19:51:22 +00:00
*/
class CompositeWhereClause extends WhereClause {
/**
2009-09-20 02:53:15 +00:00
* @ var array Stores the child clauses
2014-06-24 19:51:22 +00:00
* @ access protected
2009-09-20 02:53:15 +00:00
*/
var $clauses = array ();
2014-06-24 19:51:22 +00:00
2009-09-20 02:53:15 +00:00
/**
* Add a { @ link WhereClause WhereClause } to the list of clauses to be used for testing
2014-06-24 19:51:22 +00:00
* @ param WhereClause $whereClause The WhereClause object to add
*/
function add ( $whereClause ) {
2009-09-20 02:53:15 +00:00
$this -> clauses [] = $whereClause ;
}
}
/**
* { @ link CompositeWhereClause CompositeWhereClause } that does an OR on all its
* child WhereClauses .
*
* Use the { @ link CompositeWhereClause :: add () add ()} method and / or the constructor
* to add WhereClause objects
* to the list of clauses to check . The testRow function of the resulting object
* will then return true if any of its child clauses return true ( and returns
* false if no clauses have been added for consistency ) .
* @ package flatfile
*/
2014-06-24 19:51:22 +00:00
class OrWhereClause extends CompositeWhereClause {
function testRow ( $tablerow , $rowSchema = null ) {
2009-09-20 02:53:15 +00:00
foreach ( $this -> clauses as $clause ) {
if ( $clause -> testRow ( $tablerow , $rowSchema ))
return true ;
}
return false ;
}
2014-06-24 19:51:22 +00:00
2009-09-20 02:53:15 +00:00
/**
2014-06-24 19:51:22 +00:00
* Creates a new OrWhereClause
2009-09-20 02:53:15 +00:00
* @ param WhereClause $whereClause , ... optional unlimited list of WhereClause objects to be added
2014-06-24 19:51:22 +00:00
*/
2009-09-20 02:53:15 +00:00
function OrWhereClause () {
$this -> clauses = func_get_args ();
}
}
/**
* { @ link CompositeWhereClause CompositeWhereClause } that does an AND on all its
* child WhereClauses .
*
* Use the { @ link CompositeWhereClause :: add () add ()} method to add WhereClause objects
* to the list of clauses to check . The testRow function of the resulting object
* will then return false if any of its child clauses return false ( and returns
* true if no clauses have been added for consistency ) .
* @ package flatfile
*/
2014-06-24 19:51:22 +00:00
class AndWhereClause extends CompositeWhereClause {
function testRow ( $tablerow , $rowSchema = null ) {
2009-09-20 02:53:15 +00:00
foreach ( $this -> clauses as $clause ) {
if ( ! $clause -> testRow ( $tablerow , $rowSchema ))
return false ;
}
return true ;
}
2014-06-24 19:51:22 +00:00
2009-09-20 02:53:15 +00:00
/**
2014-06-24 19:51:22 +00:00
* Creates a new AndWhereClause
2009-09-20 02:53:15 +00:00
* @ param WhereClause $whereClause , ... optional unlimited list of WhereClause objects to be added
2014-06-24 19:51:22 +00:00
*/
2009-09-20 02:53:15 +00:00
function AndWhereClause () {
$this -> clauses = func_get_args ();
}
}
/////////////////////////// ORDER BY CLASSES ////////////////////////////////////
/**
* Stores information about an ORDER BY clause
*
* Can be passed to selectWhere to order the output . It is easiest to use
* the constructor to set the fields , rather than setting each individually
* @ package flatfile
*/
class OrderBy {
/** @var int Index of field to order by */
var $field ;
/** @var int Order type - ASCENDING or DESCENDING */
var $orderType ;
2014-06-24 19:51:22 +00:00
/** @var string Comparison type - usually either DEFAULT_COMPARISON, STRING_COMPARISON, INTEGER_COMPARISION, or NUMERIC_COMPARISON */
2009-09-20 02:53:15 +00:00
var $compareAs ;
2014-06-24 19:51:22 +00:00
2009-09-20 02:53:15 +00:00
/** Creates a new OrderBy structure
*
2014-06-24 19:51:22 +00:00
* The $compareAs parameter can be supplied using one of the pre - defined constants , but
2009-09-20 02:53:15 +00:00
* this is actually implemented by defining the constants as names of functions to do the
2014-06-24 19:51:22 +00:00
* comparison . You can therefore supply the name of any function that works like
2009-09-20 02:53:15 +00:00
* { @ link strcmp strcmp ()} to implement custom ordering .
2014-06-24 19:51:22 +00:00
* @ param int $field The index of the field to order by
* @ param int $orderType ASCENDING or DESCENDING
* @ param int $compareAs Comparison type : DEFAULT_COMPARISON , STRING_COMPARISON , INTEGER_COMPARISION ,
2009-09-20 02:53:15 +00:00
* or NUMERIC_COMPARISON , or the name of a user defined function that you want to use for doing the comparison .
*/
2014-06-24 19:51:22 +00:00
function OrderBy ( $field , $orderType , $compareAs = DEFAULT_COMPARISON ) {
2009-09-20 02:53:15 +00:00
$this -> field = $field ;
$this -> orderType = $orderType ;
$this -> compareAs = $compareAs ;
}
}
/**
* Implements the sorting defined by an array of OrderBy objects . This class
* is used by { @ link Flatfile :: selectWhere ()}
* @ access private
* @ package flatfile
*/
class Orderer {
2014-06-24 19:51:22 +00:00
/**
2009-09-20 02:53:15 +00:00
* @ var array Stores the OrderBy objects
2014-06-24 19:51:22 +00:00
* @ access private
2009-09-20 02:53:15 +00:00
*/
var $orderByList ;
2014-06-24 19:51:22 +00:00
2009-09-20 02:53:15 +00:00
/**
* Creates new Orderer that will provide a sort function
2014-06-24 19:51:22 +00:00
* @ param mixed $orderBy An OrderBy object or an array of them
* @ param array $rowSchema Option row schema
2009-09-20 02:53:15 +00:00
*/
function Orderer ( $orderBy , $rowSchema = null ) {
if ( ! is_array ( $orderBy ))
$orderBy = array ( $orderBy );
2014-06-24 19:51:22 +00:00
if ( $rowSchema ) {
2009-09-20 02:53:15 +00:00
// Fix the comparison types
2014-06-24 19:51:22 +00:00
foreach ( $orderBy as $index => $discard ) {
2009-09-20 02:53:15 +00:00
$item =& $orderBy [ $index ]; // PHP4
2014-06-24 19:51:22 +00:00
if ( $item -> compareAs == DEFAULT_COMPARISON ) {
2009-09-20 02:53:15 +00:00
$item -> compareAs = get_comparison_type_for_col_type ( $rowSchema [ $item -> field ]);
}
}
}
$this -> orderByList = $orderBy ;
}
2014-06-24 19:51:22 +00:00
2009-09-20 02:53:15 +00:00
/**
2014-06-24 19:51:22 +00:00
* Compares two table rows using the comparisons defined by the OrderBy
2009-09-20 02:53:15 +00:00
* objects . This function is of the type that can be used passed to usort () .
*/
function compare ( $row1 , $row2 ) {
return $this -> compare_priv ( $row1 , $row2 , 0 );
}
2014-06-24 19:51:22 +00:00
2009-09-20 02:53:15 +00:00
/**
* @ access private
*/
2014-06-24 19:51:22 +00:00
function compare_priv ( $row1 , $row2 , $index ) {
2009-09-20 02:53:15 +00:00
$orderBy = $this -> orderByList [ $index ];
$cmpfunc = $orderBy -> compareAs ;
2014-06-24 19:51:22 +00:00
if ( $cmpfunc == DEFAULT_COMPARISON ) {
2009-09-20 02:53:15 +00:00
$cmpfunc = STRING_COMPARISON ;
}
$cmp = $orderBy -> orderType * $cmpfunc ( $row1 [ $orderBy -> field ], $row2 [ $orderBy -> field ]);
2014-06-24 19:51:22 +00:00
if ( $cmp == 0 ) {
2009-09-20 02:53:15 +00:00
if ( $index == ( count ( $this -> orderByList ) - 1 ))
return 0 ;
else
return $this -> compare_priv ( $row1 , $row2 , $index + 1 );
} else
return $cmp ;
}
}