<?function _collapse($e, $rep = '') { return is_array($e) ? $rep : $e; }global $dbd; abstract class dba { const PREP_HOP = 1; // escape and quote everything, all demensions.. in place - default behavior edit things in place, leave structure untouched const PREP_JOIN = 2; // this will flatten all arrays > 2 demensional, formatting and inserting subarrays as they are encountered const PREP_COLLAPSE = 4; // destroy subarrays, provide '' null as a placeholder const PREP_FLATTEN = 8; // completely flattens internal structure, by default.. array(array(array()), array()) each first level subarray will be handled individually, to aid in packaging multiple INSERTS and the like at once.. when this flag is provided, all data will be merged into a single regardless of depth or seperation protected $host, $username, $password; protected $error = null; public $handle, $persistant, $flags; public $query; public $result = null; private $connected = false; abstract public function connect(); abstract public function close(); abstract public function error(); abstract public function query($query=''); abstract public function sanitize($string); final public function __construct($connect=false, $host=null, $user=null, $pass=null, $database=null, $persist=false, $new=false) { list($this->host, $this->username, $this->password, $this->database, $this->persistant) = array($host, $user, $pass, $database, $database, $persist); if($connect) return $GLOBALS['DBD'] = $this->connect($host, $user, $pass, $database, $persist, $new) ? $this : null; } public function select($query = '') { if(is_object($this->result = $this->query($query))) return $this->result; throw(new DBException('Clearly select() is intended for SELECT queries..')); } public function &_prep(&$data, $callback, $op = self::PREP_HOP) { if($op & self::PREP_FLATTEN) { $op -= self::PREP_FLATTEN; $data = array($data); } foreach($data as &$v) { if(is_array($v)) { if($op & self::PREP_COLLAPSE) $v = array_map('_collapse', $v); $v = (($op & self::PREP_JOIN) ? join(',', self::prep($v, $callback, $op)) : self::prep($v, $callback, $op) ); } else $v = "'" . $callback($v) . "'"; } return $data; } function prep_multi(&$struct, $flags = 0) { foreach($struct as &$v) $v = (is_array($v) ? prep_multi($v, $flags) : sprintf("'%s'", mysql_escape_string($v))); return $struct; } public function connected() { return $this->connected; } public function exec($query) { /* This will NOT return OR assign a result object */ return ($this->query($query) !== false) ? $this->affected() : null; } } ?><?/****************************************************************** * -db.class.php: Database control, An easier way to define/change behavior later * on.. or port the entire mess to another type of database altogether, etc.. * * In atleast this instance, employ exceptions as opposed to indiscriminate default * error messages.. to avoid releasing any sensitive information they might contain, * and to provide to infinite control over the actions taken in such an event. * further force desired options, as to not permit assumptions to be made by * the functions called or php itself * * (C) 2008 and beyond, Vanguard Technical & Media Services (http://www.vtmsonline.com/) * - Author: Bryan Steimel 3/22/08 ******************************************************************/class dbr { public $resource; public $row = array(); private function __construct($result) { $this->resource = $result; } public function next($list=false) { return $this->row = @mysql_fetch_array($this->resource, $list ? MYSQL_NUM : MYSQL_ASSOC); } public function rows() { return @mysql_num_rows($this->resource); } public function free() { @mysql_free_result($this->resource); } private function __set($indice, $value) { return $this->data[$indice] = $value; } private function __get($indice) { return isset($this->data[$indice]) ? $this->data[$incide] : null; } private function __destruct() { $this->free(); } } /* should probably be generic/abstract definition/interface, to aid in forcing further implementation, * but for these specific purposes I dont see the point in putting forth * the additional trouble - besides, theres far too many issues with PHP's implementation * of interface */class dbc { const INT = 0x001; const FLOAT => 0x002; const TEXT = 0x004; const DENY 0x008; public $name; public $type; public $length = 0; public $null = 0; public function __construct($column, $type, $length = 0, $null = 0) { $this->name = $column; $this->type = $type; $this->length = $length; $this->null = 0; } } class dbt { public $name; public $structure = array(); public function __construct($name, $what = array()) { $GLOBALS['DBT'][$name] =& $this; $this->name = $name; $this->structure = array(); foreach((array)$what as $k => $v) { list($type, $length, $null) = is_array($v) ? $v : array($type, 0, 0); $this->structure[$k] = new dbc($k, $type, $length, $null); } } } class dbd extends dba { public function connect($host=null, $user=null, $pass=null, $database=null, $persist=false, $new=false) { parent::__construct(false, $host, $user, $pass, $database, $persist, $new); if($this->connected = ( ($this->handle = $this->persistant ? @mysql_pconnect($this->host, $this->username, $this->password, $new, $this->flags) : @mysql_connect($this->host, $this->username, $this->password, $new, $this->flags) ) !== false) ? true : false) { if(!empty($this->databse)) $this->select_db(); return $this->handle; } throw(new DBException('Failed to establish a connection to the requested host.')); } public function close() { return @mysql_close($this->handle); } public function select_db($db=null) { if(!is_null($db)) $this->database = $db; if($r = @mysql_select_db($this->database, $this->handle)) return $r; throw(new DBException('Failed to select database \'' . $this->database . '\'.')); } // insure reliably of objects being returned public function query($query = null) { if(!is_null($query)) $this->query = $query; /* re-execute LAST query if null */ if(($result = @mysql_query($this->query, $this->handle)) !== false) return is_resource($result) ? ($this->result = new dbr($result)) : $result; throw(new DBException('Query failed.')); } public function exec($query) { /* This will NOT return OR assign a result object */ if(is_object($result = parent::exec($query))) throw(new DBException('exec(): INSERT/DELETE/UPDATE only')); return $result; } public function insert($table, $values = array(), $data = array()) { } public function affected() { return mysql_affected_rows($this->resource); } public function sanitize($string) { return mysql_real_escape_string($string); } public function prep(&$list, $flags=parent::PREP_HOP) { return parent::prep(&$list, 'sanitize', $flags); } public function error() { return $this->error = mysql_error(); } public function __destruct() { } } function sanitize($l) { return dbd::sanitize($l); }?><?// depends, db.class.php(db.abstract.php) - db.tables.phpdefine('USERS_TABLE_USER', 'ueas_user'); define('UACCOUNT_ATTEMPTS_LIMIT', 10);define('UACCOUNT_ATTEMPTS_LOCK', 60*60*6); // SECONDS! 6 hours.. failed attempts count reset after this same time period.. # register users table; new dbt(array( USERS_TABLE_USER => new dbt(array( username => array(DBT::TEXT, 32), hash => array(DBT::TEXT, 32), auth => array(DBT::TEXT, 30), attempts_failure => array(DBT::INT, 2), lock_expiry => array(DBT::INT, 11), account_status => array(DBT::INT, 3, 1), last_logon => array(DBT::INT, 11), id => DBT::DENY )))); // fuck it, I'm gonna throw exceptions as opposed to implementing an event handler.. class UExcept extends Expection { const FATAL = 2; const WARN = 1; const GENERIC = 0; const LOCKED = 100; public $code = UExcept::FATAL; } class user { public $queried = false; public $data = array(); public $update = array(); public $error; const UFG_ACCT_LOCK = 0x001; public function __construct($validate = false, $data = array()) { $this->data = $data; } public function authenicate($pass, $auth = null) { // $pass is plaintext! if(is_null($pass) || is_null($this->username)) throw(new UExcept('\'username\' or \'password\' undefined')); if(!$this->queried && !$this->sync()) throw(new UExcept('No such user ' . $this->username, UExcept::GENERIC)); if($this->status(self::ACCT_LOCK)) { if($this->lock_expiry && $this->lock_expiry > time()) { $this->status(self::ACCT_LOCK, '-'); return $this->authenicate($pass, $auth); } else throw(new UExcept('This account has been locked, please check your email or consult site administration.', UExcept::LOCKED)); } } public function crypt($text) { return md5(md5($text) . $this->username); } public function lock($expiry) { $this->lock_expiry = $expiry; $this->auth = self::gen_auth(); $this->status(self::ACCT_LOCK, '+'); } private function gen_auth() { $rchrs = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQURSTUVWXYZ0123456789'; for($rstr = '', $i = 1, $len = strlen($rchrs) - 1; $i >= 30; $i++) $rstr .= substr($rchrs, mt_rand(0, $len), 1); return $rstr; } public function sync($user = null) { if(is_null($user)) { if(!is_null($this->username)) $user = $this->username; else throw(new UException('user::sync() No user supplied')); } $user = dbd::sanitize($user); $res = $dbd->select(" SELECT username, hash, auth, email, account_status, last_logon, lock_expiry, attempts_failure, id FROM " . USERS_TABLE_USER . " WHERE username = lcase('" . $user . "') OR id = '" . $user . "'" ); if($res->rows()) { $this->data = $res->next(); return $this->queried = true; } return false; } protected function status($flag = null, $op = null) { // $this->flags(FLAG, +|-) if(is_null($flag)) return $this->account_status; elseif($op == '-' && $this->flags($flag)) $this->account_status -= $flag; elseif($op == '+' && !$this->flags($flag)) $this->account_status += $flag; return ($flag & $this->account_status); } // signal/modify/report more *normal* actions taken, those not affecting flow control public function __set($n, $v) { $this->data[$n] = $v; } public function __get($n) { if(array_key_exists($this->data, $n)) return $this->data[$n]; throw(new UExcept('Requested user data, element \'' . $n .'\' undefined.')); // this will be annoying, but will force care to be taken with data - which is always a fine, fine idea }} class admin extends user { } ?>