diff --git a/hadron/class_baseplugins.php b/hadron/class_baseplugins.php new file mode 100644 index 0000000..b5b60a7 --- /dev/null +++ b/hadron/class_baseplugins.php @@ -0,0 +1,99 @@ +perms = $perms; + } + + public function add($name, $callback) + { + $this->hooks[$name] = $callback; + } + + public function run($name, &$vars1 = null, &$vars2 = null, &$vars3 = null, &$vars4 = null, &$vars5 = null) + { + return $this->hooks[$name]($vars1,$vars2,$vars3,$vars4,$vars5); + } + + public function check($name) + { + if(isset($this->perms[$name]) && $this->perms[$name]==1) return true; + return false; + } +} + +class BasePlugins +{ + protected $plugins = []; + protected $runQueue = []; + protected $current = null; + protected $nohooks = false; + + public function __construct() + { + $this->plugins = []; + $this->runQueue = []; + $this->nohooks = false; + } + + public function hook($name, &$vars1 = null, &$vars2 = null, &$vars3 = null, &$vars4 = null, &$vars5 = null) + { + if(isset($this->runQueue[$name]) && count($this->runQueue[$name])!=0) + { + $queue = $this->runQueue[$name]; + foreach($queue as $plugin) $ret = $this->plugins[$plugin]->run($name,$vars1,$vars2,$vars3,$vars4,$vars5); + return $ret; + } + return null; + } + + public function bind($name, $callback) + { + if($this->nohooks) return; + + $current = &$this->plugins[$this->current]; + $current->add($name, $callback); + $this->runQueue[$name][] = $this->current; + } + + public function loadPluginFromArray($name, $autoclose = false, $callback = null) + { + $this->plugins[$name] = new Plugin; + + // Switch the current context to this plugin.. + $this->current = $name; + if($callback!=null) $exec($this); + if($autoclose) $this->current = null; + } + + public function dump() + { + return [ + 'plugins' => $this->plugins, + 'runQueue' => $this->runQueue, + 'nohooks' => $this->nohooks + ]; + } +} \ No newline at end of file diff --git a/hadron/class_container.php b/hadron/class_container.php new file mode 100644 index 0000000..654d226 --- /dev/null +++ b/hadron/class_container.php @@ -0,0 +1,172 @@ +error = new Error($this); + $this->plugins = new BasePlugins; + $this->settings = ['cache_templates' => true,'cache_expiry' => ONE_MONTH]; + } + + public function init(array $config = []) + { + // Go through the available database engines + switch($config['database_engine']) + { + case "mysqli": $engine = "mysqli"; break; + default: $engine = 'mysqli'; + } + + // Load up the database class + require_once(HADRON_BASE."/database/class_{$engine}.php"); + $this->db = new Database($this); + $this->db->connect($config['database_host'], $config['database_username'], $config['database_password']); + $this->db->select_db($config['database_name']); + $this->db->set_prefix($config['table_prefix']); + + $this->tmpls = new Templates($this); + $this->plugins->hook("hadron_start"); + + $this->cache = new Cache($this, $config); + + if(extension_loaded('pthreads')) + { + require_once(HADRON_BASE."/threading.php"); + $this->worker = new HadronWorker; + $this->tasks = []; + } + } + + public function initLang($lang, $path = null, $dir = null) + { + if($path==null) $path = dirname(HADRON_BASE."/languages"); + $this->langs = new Language($this, $path, $lang, $dir); + } + + public function setPluginHandler($plugins) + { + $this->plugins = $plugins; + } + + public function getDatabase() + { + if($this->db==null) return false; + return $this->db; + } + + public function getTemplates() + { + if($this->tmpls==null) return false; + return $this->tmpls; + } + + public function getPlugins() + { + if($this->plugins==null) return false; + return $this->plugins; + } + + public function getLanguages() + { + if($this->langs==null) return false; + return $this->langs; + } + + public function getCache() + { + if($this->cache==null) return false; + return $this->cache; + } + + public function getErrors() + { + if($this->error==null) return false; + return $this->error; + } + + public function addShutdownEvent($callback) + { + register_shutdown_function($callback); + } + + public function addParallelTask($callback) + { + if(extension_loaded('pthreads')) + { + $this->worker->stack($this->tasks[] = new HadronTask($callback)); + $this->worker->start(); + } + else register_shutdown_function($callback, false); + } + + public function runParallelTask($callback) + { + $tid = count($this->tasks) - 1; + if(extension_loaded('pthreads')) + { + + $this->worker->stack($this->tasks[$tid] = new HadronTask($callback)); + $this->worker->start(); + } + else $this->tasks[$tid] = $callback(false); + return $tid; + } + + public function pollParallelTask($tid) + { + if(!$this->tasks[$tid] instanceof HadronTask) return $this->tasks[$tid]->getResult(); + return $this->tasks[$tid]; + // finish this later + } + + public function waitForParallelTask($tid) + { + if(!$this->tasks[$tid] instanceof HadronTask) + { + $this->tasks[$tid]->wait(); + return $this->tasks[$tid]->getResult(); + } + return $this->tasks[$tid]; + } + + function __destruct() + { + $this->cache->commit(); + } +} \ No newline at end of file diff --git a/hadron/database/class_mysqli.php b/hadron/database/class_mysqli.php new file mode 100644 index 0000000..72c7adb --- /dev/null +++ b/hadron/database/class_mysqli.php @@ -0,0 +1,1173 @@ + $entry) + { + // TO-DO: Fetch these from the Main Hadron Container. + global $db, $error; + if($entry=="AND" && is_numeric($key)) $wstring .= " AND "; + elseif($entry=="OR" && is_numeric($key)) $wstring .= " OR "; + elseif(is_array($entry) && isset($entry['type']) && $entry['type']=="IN" && is_numeric($key)) + { + if(!is_array($entry) || !isset($entry['field'], $entry['values'])) + die($error->getError(500,"Database Error: Illegal use of IN in a WHERE field.")); + $values = ""; + foreach($entry['values'] as $value) $values .= $db->sanitise($value).","; + $wstring .= "{$entry['field']} IN ('".rtrim($values,',')."')"; + } + elseif(is_numeric($key)) $wstring .= " ".$entry." "; + else $wstring .= "{$key}="."'".$db->sanitise($entry)."'"; + } + return $wstring; +} + +// This class holds fields for use in table creations +final class fields +{ + public $name = null; + public $type = null; + public $size = null; + public $isNull = false; + public $increment = false; + public $fDefault = false; + public $primary = false; + + /** + * + * $name - A string holding the name of the field. + * $type - A string holding what the type of the field is. + * $size - An integer holding what the size of the field is. + * $increment - A boolean value saying whether this field is to automatically increment or not. + * $default - The default value which this field will have. + * + **/ + function __construct($name, $type, $size = null, $increment = false, $default = false) + { + $this->name = $name; + $this->type = $type; + + // If no size is given then, fallback to default value + if($type=='int' && $size==null) $size = 11; + elseif($type=='tinyint' && $size==null) $size = 1; + elseif($type=='varchar' && $size==null) $size = 100; + elseif($type=='text' && $size!=null) $size = null; + + $this->size = $size; + if($increment) $this->primary = true; + $this->increment = $increment; + $this->fDefault = $default; + } + + function output($con = null) + { + $type = $this->type; + if($this->size!=null) $type .= '('.$this->size.')'; + if(!$this->isNull) $null = ' NOT'; + else $null = ""; + + // Do we have a default value specified? + if($this->fDefault!==false) + { + if(ini_get('magic_quotes_gpc')) $default = stripslashes($this->fDefault); + $default = mysqli_real_escape_string($con, $this->fDefault); + $default = " DEFAULT '{$default}'"; + } + else $default = ""; + + // Do we want to automatically increment the value with each row? + if($this->increment) $inc = ' AUTO_INCREMENT'; + else $inc = ""; + return "`{$this->name}` {$type}{$null} NULL{$default}{$inc}"; + } +} + +final class Query +{ + // Add a locking system here.. + + private $str = null; + private $prefix = ""; + private $addition = false; + private $tables = []; + + public function setPrefix($prefix) { $this->prefix = $prefix; } + + public function buildSelect($columns, $table, $where = null, $limit = null, $order = null, $options = array()) + { + if(is_array($columns)) { + $first = true; + foreach($columns as $com) { + if(!$first) $comstring .= ','.$com; + else { + $comstring = $com; + $first = false; + } + } + $columns = $comstring; + } else $columns = '*'; + + // Has a WHERE clause been provided? + if($where==null) $where = ''; + elseif(is_array($where)) $where = parseWhere($where); + else $where = " WHERE {$where}"; + + // Has a LIMIT clause been provided? + if($limit==null) $limit = ''; + else $limit = " LIMIT {$limit}"; + + // Does someone want this in a specific order? + if($order==null) $order = ''; + elseif(is_array($order)) + { + $ostring = " ORDER BY "; + $last = count($order); + $i = 1; + foreach($order as $key => $item) + { + $ostring .= " {$key} {$item}"; + if($last!=$i) $ostring .= ","; + $i++; + } + $order = $ostring; + } + else $order = " ORDER BY {$order}"; + + if(isset($options, $options['distinct']) && $options['distinct']) $distinct = "DISTINCT "; + else $distinct = ""; + + if($this->addition) $this->str .= " SELECT {$distinct}{$columns} FROM {$this->prefix}{$table}{$where}{$order}{$limit}"; + else $this->str .= " SELECT {$distinct}{$columns} FROM {$this->prefix}{$table}{$where}{$order}{$limit}"; + } + + function buildJoin($table, $table2, $tmain, $tmain2, $where = null) + { + // Has a WHERE clause been provided? + if($where==null) $where = ""; + elseif(is_array($where)) $where = parseWhere($where); + else $where = " WHERE {$where}"; + + if($this->addition) $this->str .= " LEFT JOIN {$this->prefix}{$table2} AS {$table2} ON {$table}.{$tmain}={$table2}.{$tmain2}{$where}"; + else $this->str = " LEFT JOIN {$this->prefix}{$table2} AS {$table2} ON {$table}.{$tmain}={$table2}.{$tmain2}{$where}"; + } + + function buildInnerJoin($table, $table2, $tmain, $tmain2, $where = null, $options = null) + { + // Has a WHERE clause been provided? + if($where==null) $where = ""; + elseif(is_array($where)) $where = parseWhere($where); + else $where = " WHERE {$where}"; + + // Extra options.. + $h1 = $this->prefix.$table2; + if($options==null) $options = ""; + else { + if(!is_array($options)) $options = [$options]; + $o = ""; + foreach($options as $key => $value) + { + if($key=='post-keyword' && $value instanceof Query) + { + $res = $value->output(); + if($res!=null) $h1 = " ({$res})"; + $intables = $value->getTables(); + if(count($intables) > 0) + { + foreach($intables as $cols) + $columns = str_replace("{$cols}.",$this->prefix.$cols.'.',$columns); + } + $value->flush(); + } + } + $options = &$o; + } + + if($this->addition) $this->str .= " INNER JOIN {$h1} AS {$table2} ON {$table}.{$tmain}={$table2}.{$tmain2}{$where}"; + else $this->str = " INNER JOIN {$h1} AS {$table2} ON {$table}.{$tmain}={$table2}.{$tmain2}"; + } + + public function add() + { + $this->addition = true; + } + + public function addTable($table) + { + $this->tables[] = $table; + } + + public function getTables() + { + return $this->tables; + } + + public function output() { return $this->str; } + public function flush() { $this->str = null; $this->addition = false; } +} + +final class AsyncResource +{ + public $db; + public $main; + + public $id; + public $executed = false; + public $query; + public $result = null; + + public $multi_query = false; + + public function __construct($query, $db, $main) + { + $this->query = $query; + $this->db = $db; + $this->main = $main; + } + + public function execute() + { + if($this->executed) return false; + $this->executed = true; + + $result = mysqli_query($this->db->getConnection(), $this->query, MYSQLI_ASYNC); + if(!$result) { + $error = $this->main->getErrors(); + $error->query(mysqli_error($this->db->getConnection()), true); + exit; + } + + $this->db->count++; + } + + // Coming Soon.. + public function poll() + { + return true; + + if(!$this->executed) $this->execute(); + } + + public function getResult() + { + if(!$this->executed) $this->execute(); + if($this->result!==null) return $this->result; + + $conpool = [$this->db->getConnection()]; + $error = []; + $reject = []; + if(!mysqli_poll($conpool, $error, $reject, 10)) + die("SQL Error: The polling period has timed out."); + $this->result = mysqli_reap_async_query($this->db->getConnection()); + return $this->result; + } +} + +// The main database abstraction layer +final class database// implements int_database +{ + // The handle for the database connection + public $con = null; + + // Name of the database engine + public $engine = "mysqli"; + + // Table prefix.. + public $prefix = ""; + protected $dbname = null; + private $query = null; + protected $main = null; + + // This is to count the number of queries + public $count = 0; + public $asyncQueue = []; + public $asyncCount = 0; + + // Query builder.. + function __construct($main) + { + $this->main = $main; + $this->query = new Query; + } + function getQuery() { return $this->query; } + function getConnection() { return $this->con; } + + function connect($host,$user,$pass) + { + if(!$this->con = mysqli_connect($host,$user,$pass)) + die("Database Error: Unable to connect to the database.
+ May be due to a configuration issue or the database server itself.
+ ".mysqli_error().""); + return true; + } + + /** + * + * $name - The name of the database which you wish to select. + * + **/ + function select_db($name) + { + if(!mysqli_select_db($this->con,$name)) + die("Database Error: Unable to select the database.
+ May be due to a configuration issue or the database server itself.
+ ".mysqli_error($this->con).""); + $this->dbname = $name; + return true; + } + + function set_prefix($prefix = "") + { + $this->prefix = $prefix; + $this->query->setPrefix($prefix); + } + + function create_table($name,$fields,$primary = null) + { + $last = count($fields); + $i = 1; + $data = ""; + if(!is_array($fields)) $fields = [$fields]; + + // Loop through the fields.. + foreach($fields as $field) + { + if($last!=$i) $data.= $field->output($this->con).','; + else $data .= $field->output($this->con); + if($field->primary && $primary==null) $primary = $field->name; + $i++; + } + + // Primary key.. + if($primary==null) $primary = ""; + else $primary = ", PRIMARY KEY ({$primary})"; + + // Table prefix.. + $prefix = &$this->prefix; + + // Execute this.. + $query = mysqli_query($this->con, "CREATE TABLE IF NOT EXISTS {$prefix}{$name} ({$data}{$primary}) ENGINE=MyISAM DEFAULT CHARSET=utf8 ;"); + $this->count++; + if(!$query) { + $error = $this->main->getErrors(); + $error->custom("Database Error: Unable to insert '{$prefix}{$name}' table into the database.\n".mysqli_error($this->con).""); + } + return $query; + } + + /** + * + * $table - The table which you wish to insert data into. + * $values - An array of values which you wish to insert into the table. + * + **/ + function insert($table,$values) + { + if(!is_array($values)) $values = array($values); + $first = true; + foreach($values as $key => $value) + { + if(!$first) { + $columns .= ",`".$this->sanitise($key)."`"; + $content .= ",'".$this->sanitise($value)."'"; + } else { + $columns = "`".$this->sanitise($key)."`"; + $content = "'".$this->sanitise($value)."'"; + $first = false; + } + } + // Table prefix.. + $prefix = &$this->prefix; + + // Execute this.. + $query = mysqli_query($this->con, "INSERT INTO {$prefix}{$table} ({$columns}) VALUES ({$content})"); + $this->count++; + if(!$query) { + $error = $this->main->getErrors(); + $error->custom("Database Error: Unable to insert data into the {$prefix}{$table} table.\n".mysqli_error($this->con).""); + } + return $query; + } + + /** + * + * $table - The table which you wish to insert data into. + * $values - An array of values which you wish to insert into the table. + * $where - Existing column to delete. + * + **/ + function force_insert($table, $values, $where = null) + { + if($where!=null) $where = " WHERE {$where}"; + elseif(is_array($where)) $where = parseWhere($where); + else $where = ""; + + // Table prefix.. + $prefix = &$this->prefix; + + // Execute this.. + $query = mysqli_query($this->con, "DELETE FROM {$prefix}{$table}{$where}"); + + if(!is_array($values)) $values = array($values); + $first = true; + foreach($values as $key => $value) + { + if(!$first) { + $columns .= ",".$this->sanitise($key); + $content .= ",'".$this->sanitise($value)."'"; + } else { + $columns = $this->sanitise($key); + $content = "'".$this->sanitise($value)."'"; + $first = false; + } + } + + // Execute this.. + $query = mysqli_query($this->con, "INSERT INTO {$prefix}{$table} ({$columns}) VALUES ({$content})"); + $this->count++; + if(!$query) { + $error = $this->main->getErrors(); + $error->custom("Database Error: Unable to insert data into the {$prefix}{$table} table.\n".mysqli_error($this->con).""); + } + return $query; + } + + function delete($table, $where = null) + { + if($where!=null) $where = " WHERE {$where}"; + elseif(is_array($where)) $where = parseWhere($where); + else $where = ""; + + // Table prefix.. + $prefix = &$this->prefix; + + // Execute this.. + $query = mysqli_query($this->con, "DELETE FROM {$prefix}{$table}{$where}"); + $this->count++; + if(!$query) { + $error = $this->main->getErrors(); + $error->custom("Database Error: Unable to delete data into the {$prefix}{$table} table.\n".mysqli_error($this->con).""); + } + return $query; + } + + /** + * May be deprecated when it's job is taken over by other more cross-engine methods. + * $query - The raw query which you wish to execute. + * $critical - Whether this is an important query to halt program execution over, if it fails. + **/ + function query($query, $critical = false) + { + $result = mysqli_query($this->con, $query); + if(!$result) { + $error = $this->main->getErrors(); + $error->query(mysqli_error($this->con), $critical); + } + trigger_error("You are not permitted to execute raw queries.", E_USER_DEPRECATED); + $this->count++; + return $result; + } + + /** + * $query - The raw query which you wish to execute. + * $critical - Whether this is an important query to halt program execution over, if it fails. + **/ + function __invoke($query) + { + $query = str_replace('{$prefix}',$this->prefix,$query); + $result = mysqli_query($this->con, $query); + if(!$result) { + $error = $this->main->getErrors(); + $error->query(mysqli_error($this->con), true); + } + + $this->count++; + return $result; + } + + function queue($query, $bulk = null) + { + // When the queue is empty, execute this immediately.. + $res = new AsyncResource($query, $this, $this->main); + if(count($this->asyncQueue)==0) $res->execute(); + + // Using asyncCount to emulate "truly asynchronous" queries.. + $this->asyncQueue[$this->asyncCount] = $res; + $this->asyncCount++; + + if($bulk===true) $res->multi_query = true; + return $res; + } + + function reap_async(AsyncResource $res = null) + { + if($res==null) $res = $this->asyncQueue[$this->asyncCount]; + + if($res->id!=0) + { + // Clear the backlog.. + $queue = &$this->asyncQueue; + foreach($queue as $query) + { + if($query->id < $res->id) $query->getResult(); + else break; + } + } + //unset() // Remove this from the queue.. TO-DO: Should we use a real queue for this..? + return $res->getResult(); + } + + function poll(AsyncResource $res = null) + { + if($res==null) $res = $this->asyncQueue[$this->asyncCount]; + if(!$res instanceof AsyncResource) return false; + + if($res->id!=0) + { + foreach($queue as $query) + { + if($query->id < $res->id) $query->getResult(); + else break; + } + } + $res->poll(); + } + + /*function pollAll() + { + $queue = &$this->asyncQueue; + foreach($queue as $query) + { + $query->poll(); + } + }*/ + + function executeAll() + { + $queue = $this->asyncQueue; + foreach($queue as $item) $item->getResult(); + } + + /** + * + * $string - A string which you wish to sanitise in preparation for a query. + * + **/ + function sanitise($string) + { + if(ini_get('magic_quotes_gpc')) $string = stripslashes($string); + $string = mysqli_real_escape_string($this->con,$string); + return $string; + } + + /** + * + * $result - A MySQLi resource variable. + * + **/ + function num_rows($result) { return mysqli_num_rows($result); } + + function row_count($table, $row = '*', $where = null, $options = array()) + { + if($where==null) $where = ""; + elseif(is_array($where)) $where = parseWhere($where); + else $where = " WHERE {$where}"; + + // Extra options.. + $h1 = ""; + if($options==null) $options = ""; + else { + if(!is_array($options)) $options = array($options); + $o = ""; + foreach($options as $key => $value) + { + if($key=='post-table' && $value instanceof Query) + { + $res = $value->output(); + if($res!=null) $h1 = ' '.$res; + $intables = $value->getTables(); + if(count($intables) > 0) + { + foreach($intables as $cols) $columns = str_replace("{$cols}.",$this->prefix.$cols.'.',$columns); + } + if(!isset($options['noFlush']) || !$options['noFlush']) $options['post-table']->flush(); + } + } + $options = &$o; + } + + // Table prefix.. + $prefix = &$this->prefix; + + // Execute this.. + $result = mysqli_query($this->con, "SELECT COUNT({$row}) AS count FROM {$prefix}{$table} AS {$table} {$where}{$h1}"); + $this->count++; + if(!$result) { + $error = $this->main->getErrors(); + $error->query(mysqli_error($this->con), true); + return false; + } + $data = mysqli_fetch_array($result, MYSQLI_ASSOC); + if($data) return $data['count']; + return 0; + } + + /** + * + * $columns - A variable holding a single column or an array of columns which you wish to fetch. + * $table - The table which you wish to fetch data from. + * $where - An optional parameter for specifying what conditions you wish for the content to match. + * $limit - Controls how many rows may be returned by the query. + * $order - The order in which the results are done in. + * $options - Additional options to use in this query. + * $critical - A true or false value over whether this is a query that is critical to the script's operation. + * + **/ + function get($columns, $table, $where = null, $limit = null, $order = null, $options = null) + { + if(is_array($columns)) { + $first = true; + $comstring = ""; + foreach($columns as $key => $com) { + if(!$first) $comstring .= ','; + if(!is_numeric($key)) $comstring .= "{$key} AS {$com}"; + else $comstring .= $com; + + $first = false; + } $columns = $comstring; + } + + // Has a WHERE clause been provided? + if($where==null) $where = ""; + elseif(is_array($where)) $where = parseWhere($where); + else $where = " WHERE {$where}"; + + // Does someone want this in a specific order? + if($order==null) $order = ""; + elseif(is_array($order)) + { + $ostring = " ORDER BY "; + $last = count($order); + $i = 1; + foreach($order as $key => $item) + { + $ostring .= " {$key} {$item}"; + if($last!=$i) $ostring .= ","; + $i++; + } + $order = $ostring; + } + else $order = " ORDER BY {$order}"; + + // Has a LIMIT clause been provided? + if($limit!=null) $order .= " LIMIT {$limit}"; + + // Extra options.. + $h1 = ""; + $async = false; + if($options==null) $options = ""; + else { + if(!is_array($options)) $options = array($options); + if(isset($options['post-table']) && $options['post-table'] instanceof Query) + { + $res = $options['post-table']->output(); + if($res!=null) $h1 = ' '.$res; + $intables = $options['post-table']->getTables(); + if(count($intables) > 0) + { + foreach($intables as $cols) $columns = str_replace("{$cols}.",$this->prefix.$cols.'.',$columns); + } + if(!isset($options['noFlush']) || !$options['noFlush']) $options['post-table']->flush(); + } + if(isset($options, $options['distinct']) && $options['distinct']) $columns = "DISTINCT {$columns}"; + if(isset($options, $options['groupby']) && $options['groupby']) $where .= " GROUP BY {$options['groupby']} "; + if(isset($options, $options['async']) && $options['async']) $async = true; + } + + // Table prefix.. + $prefix = &$this->prefix; + + // Execute this.. + if($async) $result = $this->queue("SELECT {$columns} FROM {$prefix}{$table} AS {$table}{$h1}{$where}{$order}"); + else + { + if(count($this->asyncQueue)!=0) $this->executeAll(); + $result = mysqli_query($this->con, "SELECT {$columns} FROM {$prefix}{$table} AS {$table}{$h1}{$where}{$order}"); + $this->count++; + } + + if(!$result) { + $error = $this->main->getErrors(); + $error->query(mysqli_error($this->con), true); + return false; + } + + if(!$async) + { + // Grab the number of rows.. + $c = $this->num_rows($result); + if($c==0) return 0; + if($limit==1) return mysqli_fetch_array($result, MYSQLI_ASSOC); + //if($c>1) + else + { + $res = array(); + /*while($row = mysqli_fetch_array($result)) $res[] = $row; + return $res;*/ + return mysqli_fetch_all($result, MYSQLI_ASSOC); + } + } + return $result; + } + + /** + * + * $columns - A variable holding a single column or an array of columns which you wish to fetch. + * $table - The table which you wish to fetch data from. + * $table2 - The second table which we're trying to join. + * $tmain - The primary key which we're using as a unique identifier. + * $tmain2 - The Table 2 equivalent which corresponds to $tmain. + * $where - An optional parameter for specifying what conditions you wish for the content to match. + * $limit - Controls how many rows may be returned by the query. + * $order - The order in which the results are done in. + * + **/ + function join($columns, $table, $table2, $tmain, $tmain2, $where = null, $limit = null, $order = null, $options = array()) + { + if(is_array($columns)) { + $first = true; + $comstring = ""; + foreach($columns as $key => $com) { + if(!$first) $comstring .= ','; + + if(!is_numeric($key)) $comstring .= "{$key} AS {$com}"; + else $comstring .= $com; + + $first = false; + } $columns = $comstring; + } + if($where==null) $where = ""; + elseif(is_array($where)) + { + $wstring = " WHERE "; + foreach($where as $key => $entry) + { + if($entry=="AND" && is_numeric($key)) $wstring .= " AND "; + elseif($entry=="OR" && is_numeric($key)) $wstring .= " OR "; + else $wstring .= $key."='{$entry}'"; + } + $where = $wstring; + } else $where = " WHERE {$where}"; + + if($limit==null) $limit = ""; + else $limit = " LIMIT {$limit}"; + + // Does someone want this in a specific order? + if($order==null) $order = ""; + elseif(is_array($order)) + { + $ostring = " ORDER BY"; + $last = count($order); + $i = 1; + foreach($order as $key => $item) + { + $ostring .= " {$key} {$item}"; + if($last!=$i) $ostring .= ","; + $i++; + } + $order = $ostring; + } else $order = " ORDER BY {$order}"; + + $async = false; + $distinct = ''; + if(isset($options)) + { + if(isset($options['distinct']) && $options['distinct']) $distinct = "DISTINCT "; + if(isset($options['async']) && $options['async']) $async = true; + } + + // Table prefix.. + $prefix = &$this->prefix; + + // Execute this.. + if($async) $result = $this->queue("SELECT {$distinct}{$columns} FROM {$prefix}{$table} AS {$table} LEFT JOIN {$prefix}{$table2} AS {$table2} ON {$table}.{$tmain}={$table2}.{$tmain2}{$where}{$order}{$limit}"); + else + { + if(count($this->asyncQueue)!=0) $this->executeAll(); + $result = mysqli_query($this->con, "SELECT {$distinct}{$columns} FROM {$prefix}{$table} AS {$table} LEFT JOIN {$prefix}{$table2} AS {$table2} ON {$table}.{$tmain}={$table2}.{$tmain2}{$where}{$order}{$limit}"); + $this->count++; + } + + if(!$result) { + $error = $this->main->getErrors(); + $error->query(mysqli_error($this->con), true); + return false; + } + if(!$async) + { + $c = $this->num_rows($result); + if($c==0) return 0; + /*if($c>1) { + $res = array(); + while($row = mysqli_fetch_array($result)) $res[] = $row; + $result = &$res; + } else $result = mysqli_fetch_array($result);*/ + if($limit==" LIMIT 1") return mysqli_fetch_array($result, MYSQLI_ASSOC); + else return mysqli_fetch_all($result, MYSQLI_ASSOC); + } + } + + /** + * + * Optimal for three joins. Use the query builder for more. + * + * $columns - A variable holding a single column or an array of columns which you wish to fetch. + * $tables - The tables which you wish to fetch data from. + * $tmain - An array of primary keys which you wish to use as identifiers. + * $where - An optional parameter for specifying what conditions you wish for the content to match. + * $limit - Controls how many rows may be returned by the query. + * $order - The order in which the results are done in. + * + **/ + function super_join($columns, $tables, $tmain, $where = null, $limit = null, $order = null, $options = array()) + { + $snippet = ""; + $first = true; + $rtables = array(); + $rrtables = array(); + foreach($tables as $key => $table) + { + $rtables[] = "#{$table}.#"; + $rrtables[] = "{$this->prefix}{$table}."; + if($first) { + $snippet .= "{$this->prefix}{$table} AS {$table}"; + $first = false; + } else { + $cur = $tmain[$tables[$key - 1]]; + if(is_array($cur)) $snippet .= " LEFT JOIN {$this->prefix}{$table} AS {$table} ON ".$tables[$key - 1].".".$cur[$table]."={$table}.{$tmain[$table]}"; + elseif(is_array($tmain[$table]) && isset($tmain[$tables[$key - 1]])) + $snippet .= " LEFT JOIN {$this->prefix}{$table} AS {$table} ON ".$tables[$key - 1].".{$cur}={$table}.".$tmain[$tables[$key - 1]]; + else $snippet .= " LEFT JOIN {$this->prefix}{$table} AS {$table} ON ".$tables[$key - 1].".{$cur}={$table}.{$tmain[$table]}"; + } + } + + if(is_array($columns)) { + $first = true; + foreach($columns as $key => $com) { + if(!$first) $comstring .= ','.$com; + else { + if(!is_numeric($key)) $comstring = "{$key} AS {$com}"; + else $comstring = $com; + $first = false; + } + } $columns = $comstring; + } + if($where==null) $where = ""; + elseif(is_array($where)) + { + $wstring = " WHERE "; + foreach($where as $key => $entry) + { + if($entry=="AND") $wstring .= " AND "; + elseif($entry=="OR") $wstring .= " OR "; + else $wstring .= $key."='{$entry}'"; + } + $where = $wstring; + } + else $where = " WHERE {$where}"; + if($limit==null) $limit = ""; + else $limit = " LIMIT {$limit}"; + + // Does someone want this in a specific order? + if($order==null) $order = ""; + elseif(is_array($order)) + { + $ostring = " ORDER BY"; + $last = count($order); + $i = 1; + foreach($order as $key => $item) + { + $ostring .= " {$key} {$item}"; + if($last!=$i) $ostring .= ","; + $i++; + } + $order = $ostring; + } + else $order = " ORDER BY {$order}"; + + $async = false; + $distinct = ""; + if(isset($options)) + { + if(isset($options['distinct']) && $options['distinct']) $distinct = "DISTINCT "; + if(isset($options['async']) && $options['async']) $async = true; + } + + // Execute this.. + if($async) $result = $this->queue("SELECT {$distinct}{$columns} FROM {$snippet}{$where}{$order}{$limit}"); + else + { + if(count($this->asyncQueue)!=0) $this->executeAll(); + $result = mysqli_query($this->con, "SELECT {$distinct}{$columns} FROM {$snippet}{$where}{$order}{$limit}"); + $this->count++; + } + + if(!$result) { + $error = $this->main->getErrors(); + $error->query(mysqli_error($this->con), true); + return false; + } + + if(!$async) + { + $c = $this->num_rows($result); + if($c==0) return 0; + if($c>1) { + $res = array(); + $count = false; + while($row = mysqli_fetch_array($result, MYSQLI_ASSOC)) $res[] = $row; + $result = &$res; + } else $result = mysqli_fetch_array($result, MYSQLI_ASSOC); + } + return $result; + } + + /** + * + * $result - A MySQLi resource variable. + * + **/ + function fetch_array($result, $type = MYSQLI_ASSOC) { return mysqli_fetch_array($result, $type); } + + function fetch_all($result, $type = MYSQLI_ASSOC) { return mysqli_fetch_all($result, $type); } + + /** + * + * $result - A MySQLi resource variable. + * + **/ + function loop($result, $type = MYSQLI_ASSOC) + { + $data = array(); + while($row = mysqli_fetch_array($result, $type)) $data[] = $row; + return $data; + } + + /** + * + * $table - The name of the table which you wish to query. + * $update - A string containing the data which is being updated. + * $where - A string holding the location of the data which you wish to update. + * $critical - A true or false value over whether this is a query that is critical to the script's operation. + * + **/ + function update($table, $update, $where = null, $shutdown = false) + { + if($where==null) $where = ""; + elseif(is_array($where)) $where = parseWhere($where); + else $where = " WHERE {$where}"; + + // Table prefix.. + $prefix = &$this->prefix; + + // Execute this.. + if($shutdown) return register_shutdown_function(function($con) use($prefix, $table, $update, $where) + { + $result = mysqli_query($con, "UPDATE {$prefix}{$table} SET {$update}{$where}"); + $this->count++; + if(!$result) { + $error = $this->main->getErrors(); + $error->query(mysqli_error($con), true); + } + }, $this->con); + else $result = mysqli_query($this->con, "UPDATE {$prefix}{$table} SET {$update}{$where}"); + $this->count++; + if(!$result) { + $error = $this->main->getErrors(); + $error->query(mysqli_error($this->con), true); + } + return $result; + } + + /** + * + * $table - The name of the table which you wish to query. + * $update - A string containing the data which is being updated. + * $where - A string holding the location of the data which you wish to update. + * $current - A string holding the value of the field before updating. + * + **/ + function diff_update($table, $update, $where = null, $current = false) + { + // Has someone not provided the current state? + if($current) + { + // Let's split this into two bits.. + $up = explode("=", $update); + + // Did someone forget to use equals? + if(!isset($up[1])) { + $error = $this->main->getErrors(); + $error->query('There was no assignment operator in the $update variable', true); + return false; + } + $new = &$up[1]; + + // Strip all three kinds of string delimiters.. + $new = str_replace(array("'",'"','`'),'', $new); + + // Is it the same? Abort the function then. + if($new==$current) return false; + } + + // Has someone provided which areas to update? + if($where==null) $where = ""; + elseif(is_array($where)) $where = parseWhere($where); + else $where = " WHERE {$where}"; + + // Table prefix.. + $prefix = &$this->prefix; + + // Run this query.. + $result = mysqli_query($this->con, "UPDATE {$prefix}{$table} SET {$update}{$where}"); + + // Increment this.. + $this->count++; + + if(!$result) { + $error = $this->main->getErrors(); + $error->query(mysqli_error($this->con), true); + return false; + } + + return $result; + } + + /** + * + * $table - The name of the table which you wish to bulk query. + * $update - A multi-dimensional array holding each update to be executed in array form. + * $shutdown - A true or false value over whether this is a query which will be run after everything else. + * + **/ + function bulk_update($table, $update, $shutdown = false) + { + if(!is_array($update)) $update = array($update); + $query = ""; + + // Table prefix.. + $prefix = &$this->prefix; + + $last = count($update); + $i = 0; + + // Loop through the queries.. + foreach($update as $up) + { + $i++; + if(!isset($up['where'])) $up['where'] = ""; + elseif(is_array($up['where'])) $up['where'] = parseWhere($up['where']); + else $up['where'] = " WHERE {$up['where']}"; + $query .= "UPDATE {$prefix}{$table} SET {$up['data']}{$up['where']}"; + if($last!=$i) $query .= ';'; + } + + // Execute this.. + if($shutdown) register_shutdown_function(function($con, $query) use($prefix, $table){ + $result = mysqli_multi_query($this->con, $query); + while(mysqli_more_results($con)) mysqli_next_result($con); + $this->count++; + if(mysqli_error($this->con)) $this->main->getErrors()->query(mysqli_error($con), true); + }, $this->con); + else { + $result = mysqli_multi_query($this->con, $query); + while(mysqli_more_results($this->con)) mysqli_next_result($this->con); + $this->count++; + if(mysqli_error($this->con)) { + $error = $this->main->getErrors(); + $error->query(mysqli_error($this->con), true); + } + } + } + + /*function bulk_select() + { + + }*/ + + // Check whether this table exists.. + public function exists($name) + { + $this->count++; + if(!mysqli_query($this->con, "SELECT '{$this->prefix}{$name}' FROM information_schema.tables WHERE table_schema = '{$this->dbname}' AND table_name = '{$this->prefix}{$name}';")) + return false; + return true; + } + + public function addColumn($table, $column, $type, $order = null) + { + $error = $this->main->getErrors(); + + if($order==null) $order = ""; + else $order = ' '.$order; + + $this->count++; + if(!$query = mysqli_query($this->con, "ALTER TABLE '{$this->prefix}{$table}' ADD '{$column}' {$type}{$order};")) return false; + { + $error->query(mysqli_error($this->con), true); + return false; + } + return true; + } + + public function removeColumn($table, $column) + { + $error = $this->main->getErrors(); + $this->count++; + if(!$query = mysqli_query($this->con, "ALTER TABLE '{$this->prefix}{$table}' DROP '{$column}';")) + { + $error->query(mysqli_error($this->con), true); + return false; + } + return true; + } + + public function columnExists($table, $column) + { + $this->count++; + if(!mysqli_query("SELECT * FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = '{$this->dbname}' AND TABLE_NAME = '{$this->prefix}{$table}' AND COLUMN_NAME = '{$column}';", $this->con)) + return false; + return true; + } + + public function getColumns($table) + { + $this->count++; + return mysqli_query("SHOW COLUMNS FROM {$this->prefix}{$table}",$this->con); + } + + // Get the ID for the last row which was inserted. + function last_id() { return mysqli_insert_id($this->con); } + + // Is this really needed as we have an error handler. + function error() { return mysqli_error($this->con); } + + // Make sure the connection is closed when the object is destroyed + function __destruct() { mysqli_close($this->con); } +} \ No newline at end of file diff --git a/hadron/database/int_database.php b/hadron/database/int_database.php new file mode 100644 index 0000000..e4a7e22 --- /dev/null +++ b/hadron/database/int_database.php @@ -0,0 +1,50 @@ +events['lock']($this->tmpls); exit; } - if(!extension_loaded("mysql") && !extension_loaded("mysqli")) { $this->events['dbexts']($this->tmpls); exit; } + if(!extension_loaded("mysqli")) { $this->events['dbexts']($this->tmpls); exit; } } public function getTemplates() @@ -137,15 +137,9 @@ public function writeFile($path, $content = "") { if(is_writeable($path) || (!file_exists($path) && is_writeable(dirname($path))) || @chmod($path,0666)) { - // Create the file handle $hd = fopen($path,"w"); - - // Write to the file - fwrite($hd, $content); - - // Close the handle + fwrite($hd,$content); fclose($hd); - return true; } return false; diff --git a/hadron/install/class_templates.php b/hadron/install/class_templates.php index 75b66d9..c92dc3e 100644 --- a/hadron/install/class_templates.php +++ b/hadron/install/class_templates.php @@ -4,7 +4,7 @@ * Hadron Framework: Installation System: Simple Template Class. * Created by Azareal. * Licensed under the terms of the GPLv3. -* Copyright Azareal and Hadron Framework (c) 2013 - 2017 +* Copyright Azareal (c) 2013 - 2017 * **/ diff --git a/hadron/threading.php b/hadron/threading.php new file mode 100644 index 0000000..2603a02 --- /dev/null +++ b/hadron/threading.php @@ -0,0 +1,38 @@ +callback = $callback; + $this->data = null; + } + + public function run() + { + $this->data = $callback(); + $this->notify(); + } + + protected function getResult() + { + return $this->data; + } +} \ No newline at end of file