public function __construct($args = null) { $args_default = array('max_offset' => 2147483646, 'server' => array('ip' => '127.0.0.1', 'port' => 6379, 'database' => 15, 'alias' => 'first')); $args = FOX_sUtil::parseArgs($args, $args_default); foreach ($args as $key => $var) { $this->{$key} = $var; } unset($key, $var); // Handle process-id binding // =========================================================== if (FOX_sUtil::keyExists('process_id', $args)) { // Binding to a reference is important. It makes the cache engine $process_id // update if the FOX_mCache is changed, which we do during unit testing. $this->process_id =& $args['process_id']; } else { global $fox; $this->process_id = $fox->process_id; } $this->has_libs = true; if ($this->enable == true) { require_once FOX_PATH_BASE . '/lib/predis/autoload.php'; $this->engine = new Predis\Client($this->server); $this->is_active = true; } }
/** * Recursively builds a clipped tree structure * * @version 1.0 * @since 1.0 * * @return array | Exception on failure. Trie structure on success. */ function render() { // CASE 1: This is a root node or intermediate node // =============================================================== if ($this->depth < $this->base->max_depth) { if (!is_array($this->trie) || FOX_sUtil::keyExists($this->base->null_token, $this->trie)) { return array(); } else { foreach ($this->trie as $key => $data) { try { $child_node = new FOX_trie_clip_iterator(array('base' => $this->base, 'trie' => $data, 'depth' => $this->depth + 1)); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 1, 'text' => "Error creating child node", 'data' => array('current_node' => array('trie' => $this->trie, 'depth' => $this->depth), 'child_node' => array('args' => $data, 'depth' => $this->depth + 1, "value" => $key)), 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child)); } try { $reduced = $child_node->render(); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 2, 'text' => "Error reducing child node", 'data' => array('current_node' => array('trie' => $this->trie, 'depth' => $this->depth), 'child_node' => array('args' => $data, 'depth' => $this->depth + 1, "value" => $key)), 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child)); } $this->children[$key] = $reduced; } unset($key, $data); } return $this->children; } else { return array(); } }
public function __construct($args = null) { // Handle dependency-injection for unit tests if (FOX_sUtil::keyExists('process_id', $args)) { // Binding to a reference is important. It makes the cache engine $process_id // update if the FOX_mCache is changed, which we do during unit testing. $this->process_id =& $args['process_id']; } else { global $fox; $this->process_id = $fox->process_id; } if (FOX_sUtil::keyExists('max_offset', $args)) { $this->max_offset = $args['max_offset']; } else { $this->max_offset = 2147483646; // (32-bit maxint) } if (function_exists("apc_store")) { $this->has_libs = true; if ($this->enable == true) { $this->is_active = true; } } else { $this->has_libs = false; $this->is_active = false; } }
/** * Implodes an array of heirarchical datastore keys into a single query $args array * * @version 1.0 * @since 1.0 * * @param array $trie | Trie structure * * @param array $columns | Array of column names * * @param array $ctrl | Control args * => VAL @param string $null_token | String to use as null token * * @return bool | Exception on failure. True on success. */ function __construct($trie, $columns, $ctrl = null) { $this->trie = $trie; $this->columns = $columns; $this->max_depth = count($columns); $ctrl_default = array('null_token' => '*'); $this->ctrl = FOX_sUtil::parseArgs($ctrl, $ctrl_default); $this->null_token = $this->ctrl['null_token']; return true; }
public function ajax_api() { $paths = FOX_sUtil::glob_recursive(FOX_PATH_AJAX . "/*.js"); $urls = FOX_sUtil::pluginPathToURL($paths); foreach ($urls as $url) { $hash = md5($url); wp_register_script($hash, $url); wp_enqueue_script($hash); } unset($url); }
public function __construct($args = null) { // Handle process-id binding // =========================================================== if (FOX_sUtil::keyExists('process_id', $args)) { // Binding to a reference is important. It makes the cache engine $process_id // update if the FOX_mCache is changed, which we do during unit testing. $this->process_id =& $args['process_id']; } else { global $fox; $this->process_id = $fox->process_id; } }
/** * Implodes an array of heirarchical datastore keys into a single query $args array * * @version 1.0 * @since 1.0 * * @param array $trie | Trie structure * @param array $columns | Array of column names * * @param array $ctrl | Control args * => VAL @param string $null_token | String to use as null token * * @return array | Exception on failure. True on success. */ function __construct($trie, $columns, $ctrl = null) { $this->trie = $trie; $this->columns = $columns; $ctrl_default = array('null_token' => '*', 'mode' => 'control'); $this->ctrl = FOX_sUtil::parseArgs($ctrl, $ctrl_default); $this->null_token = $this->ctrl['null_token']; $this->mode = $this->ctrl['mode']; if ($this->mode == 'data') { $this->data_key = array_pop($this->columns); } $this->max_depth = count($this->columns) - 1; try { $result = $this->build(); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 1, 'text' => "Error during build process", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child)); } return $result; }
/** * Implodes an array of heirarchical datastore keys into a single query $args array * * @version 1.0 * @since 1.0 * * @param array $columns | Array of column names * * @param array $args | Array of key arrays * => ARR @param int '' | Array containing "column_name"=>"value" * * @param array $ctrl | Control args * => VAL @param bool $optimize | True to optimize the $args matrix * => VAL @param string $prefix | Prefix to add to column names * => VAL @param bool $trap_null | Throw an exception if one or more walks * in the args array collapses to "WHERE 1 = 1" * * @return array | Exception on failure. True on success. */ function __construct($struct, $columns, $args, $ctrl = null) { $this->struct = $struct; $this->columns = $columns; $this->args = $args; $this->max_depth = count($columns) - 1; $ctrl_default = array('prefix' => '', 'optimize' => true, 'trap_null' => true, 'hash_token_vals' => true, 'null_token' => '*', 'mode' => 'matrix'); $this->ctrl = FOX_sUtil::parseArgs($ctrl, $ctrl_default); if ($this->ctrl['hash_token_vals'] == true) { $this->hash_table = new FOX_hashTable(); } $this->null_token = $this->ctrl['null_token']; $this->mode = $this->ctrl['mode']; try { $result = $this->build(); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 1, 'text' => "Error during build process", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child)); } return $result; }
public function event($data) { foreach ($this->events as $event) { // This is probably one of the few situations in all of modern computer science where // a massive "elseif" chain is the optimal solution. // Ordered by frequency of use, for best performance if (FOX_sUtil::keyExists('pid', $event) && $event['pid'] != $data['pid']) { continue; } elseif (FOX_sUtil::keyExists('text', $event) && $event['text'] != $data['text']) { continue; } elseif (FOX_sUtil::keyExists('class', $event) && $event['class'] != $data['class']) { continue; } elseif (FOX_sUtil::keyExists('function', $event) && $event['function'] != $data['function']) { continue; } elseif (FOX_sUtil::keyExists('file', $event) && $event['file'] != $data['file']) { continue; } elseif (FOX_sUtil::keyExists('line', $event) && $event['line'] != $data['line']) { continue; } else { if ($event['type'] == 'log') { $this->log_buffer[] = array('pid' => $data['pid'], 'file' => $data['file'], 'class' => $data['class'], 'function' => $data['function'], 'line' => $data['line'], 'text' => $data['text']); return array(); } else { // Events are emitted by class instances. Pass the class instance that emitted the event, and all // currently defined variables within the *function inside the class instance* that emitted the // event, to the function sent in as the event handler; then take the results (if any) returned // by the event handler function and use them to overwrite the variables within the function // inside the class instance that emitted the event. return $event['modifier']($data['parent'], $data['vars']); } } } unset($event); // Handle not matching on any events return array(); }
/** * Validates a trie structure * * @version 1.0 * @since 1.0 * * @param array $data | trie structure to validate * * @param array $ctrl | Control parameters * => VAL @param int $order | Order of trie structure * => VAL @param string $mode | Operation mode 'control' | 'data' * => VAL @param bool $allow_wildcard | Allow wildcards (universal selector) to be used in control tries * => VAL @param string $wildcard_token | String to use as wildcard token * => VAL @param int $clip_order | Order to clip keys at when in 'data' mode * * @return bool/array | Exception on failure, (bool)true on success, (array)data_array on failure. */ public function validateTrie($data, $ctrl = null) { $ctrl_default = array('order' => $this->order, 'mode' => 'control', 'allow_wildcard' => false, 'wildcard_token' => '*', 'clip_order' => false); $ctrl = FOX_sUtil::parseArgs($ctrl, $ctrl_default); if ($ctrl['order'] > $this->order || $ctrl['order'] < 0) { throw new FOX_exception(array('numeric' => 1, 'text' => "Specified order is not valid", 'data' => array("order" => $ctrl['order'], "class_order" => $this->order), 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => null)); } if ($ctrl['mode'] != 'data' && $ctrl['mode'] != 'control') { throw new FOX_exception(array('numeric' => 2, 'text' => "Invalid 'mode' parameter", 'data' => array('ctrl' => $ctrl), 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => null)); } if ($ctrl['mode'] == 'data' && !is_int($ctrl['clip_order'])) { throw new FOX_exception(array('numeric' => 3, 'text' => "The 'clip_order' parameter must be set when operating in 'data' mode", 'data' => array('ctrl' => $ctrl), 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => null)); } if ($ctrl['mode'] == 'data' && $ctrl['allow_wildcard'] != false) { throw new FOX_exception(array('numeric' => 4, 'text' => "Wildcard selectors cannot be used in 'data' mode", 'data' => array('ctrl' => $ctrl), 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => null)); } try { if ($ctrl['order'] == 0) { // We're at L0 in a walk return true; } if (is_array($data) && !empty($data)) { foreach ($data as $parent_id => $children) { if (!($ctrl['allow_wildcard'] == true && $parent_id == $ctrl['wildcard_token'])) { $check_result = self::validateKey(array('type' => $this->order_dict[$ctrl['order']]['type'], 'format' => 'scalar', 'var' => $parent_id)); if ($check_result !== true) { return array('numeric' => 1, 'message' => $check_result, 'key' => $ctrl['order'], 'val' => $parent_id); } } $child_result = self::validateTrie($children, array('order' => $ctrl['order'] - 1, 'mode' => $ctrl['mode'], 'allow_wildcard' => $ctrl['allow_wildcard'], 'clip_order' => $ctrl['clip_order'])); if ($child_result !== true) { if (FOX_sUtil::keyExists('trace', $child_result)) { $trace = array_merge($child_result['trace'], array($ctrl['order'] => $parent_id)); } else { $trace = array($ctrl['order'] => $parent_id); } return array('numeric' => 2, 'message' => $child_result['message'], 'key' => $ctrl['order'], 'val' => $parent_id, 'trace' => $trace); } } unset($parent_id, $children); } else { if ($ctrl['mode'] == 'control') { if (!is_array($data) && (!is_bool($data) || $data === false)) { $message = "Each walk in a control trie must terminate with either (bool)true, "; $message .= "or an empty array, or must extend to the L1 key."; return array('numeric' => 3, 'message' => $message, 'key' => $ctrl['order'], 'val' => $parent_id); } else { return true; } } elseif ($ctrl['mode'] == 'data') { if ($ctrl['order'] == $ctrl['clip_order'] - 1) { if (!is_array($data) && (!is_bool($data) || $data === false)) { $message = "Each walk in a data trie, that terminates at the clip_order, must "; $message .= "terminate with an empty array."; return array('numeric' => 4, 'message' => $message, 'key' => $ctrl['order'], 'val' => $parent_id); } else { return true; } } else { $message = "Each walk in a data trie must terminate either at the clip_order "; $message .= "or at the L1 key."; return array('numeric' => 5, 'message' => $message, 'key' => $ctrl['order'], 'val' => $parent_id); } } } // ENDOF: if( is_array($data) && !empty($data) ) } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 5, 'text' => "Error in validator", 'data' => array("columns" => $this->order_dict), 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child)); } return true; }
/** * Returns all type_ids owned by a module * * @version 1.0 * @since 1.0 * @param int $module_id| Single module_id as int. * @return array | Exception on failure. False on nonexistent. Array of type_ids on success. */ public function getTypes($module_id) { $db = new FOX_db(); $result = array(); // If the module_id doesn't exist in the class cache array, fetch it from the persistent cache if (!FOX_sUtil::keyExists($module_id, $this->cache["module_id_types"])) { try { self::loadCache(); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 1, 'text' => "Cache read error", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child)); } // If the module_id doesn't exist in the persistent cache, load it from the db if (!FOX_sUtil::keyExists($module_id, $this->cache["module_id_types"])) { $columns = array("mode" => "include", "col" => array("type_id")); $ctrl = array("format" => "col"); try { $db_result = $db->runSelectQueryCol($this->_struct(), "module_id", "=", $module_id, $columns, $ctrl); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 2, 'text' => "Error reading from database", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child)); } // Update the cache // ============================== if ($db_result) { try { $cache_image = self::readCache(); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 3, 'text' => "Cache read error", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child)); } // Rebuild the cache image foreach ($db_result as $type_id) { $result[] = $type_id; $cache_image["module_id_types"][$module_id][$type_id] = true; } unset($type_id); try { self::writeCache($cache_image); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 4, 'text' => "Cache write error", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child)); } // Overwrite the class cache $this->cache = $cache_image; } else { // The module_id doesn't exist return false; } } } // Build the result array $type_ids = $this->cache["module_id_types"][$module_id]; $result = array_keys($type_ids); return $result; }
/** * Checks if a group grants a specific key * * @version 1.0 * @since 1.0 * * @param int $group_id | id of the group * @param int $key_id | id of the key * @return bool | True if group has key. False if group does not have key. */ public function hasKey($group_id, $key_id) { if (FOX_sUtil::keyExists($key_id, $this->cache["keys"][$group_id])) { return $this->cache["keys"][$group_id][$key_id]; } else { try { $this->load($group_id, $key_id); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 1, 'text' => "FOX_uGroupKeyRing load exception", 'data' => array("group_id" => $group_id, "key_id" => $key_id), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } return $this->cache["keys"][$group_id][$key_id]; } }
/** * Creates a single group * * @version 1.0 * @since 1.0 * * @param string $name | name of group (max 32 chars) * @param string $title | title of group (max 128 chars) * @param string $caption | caption of group * @param bool $is_default | if set true, this group is the default group * @param int $icon | media_id of image to use as icon for the group * @return bool | False on failure. Created group's id on success. */ public function createGroup($data) { if (!FOX_sUtil::keyExists('name', $data) || empty($data['name'])) { throw new FOX_exception(array('numeric' => 1, 'text' => "Missing or invalid 'name' key", 'data' => $data, 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => null)); } if (!FOX_sUtil::keyExists('is_default', $data) || $data['is_default'] === null) { $data['is_default'] = false; } // IMPORTANT: Default group flag rules // ========================================== // 1) Only one group can be the default group // 2) There must always be a default group $db = new FOX_db(); $ctrl = array("format" => "var", "count" => true); try { $groups_count = $db->runSelectQuery(self::$struct, $args = null, $columns = null, $ctrl); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 1, 'text' => "DB select exception", 'data' => array("ctrl" => $ctrl), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } // CASE 1: No other groups exist // ============================================================================= if ($groups_count == 0) { $data["is_default"] = true; // Force $is_default flag to be true // Insert new group into the db try { $insert_ok = $db->runInsertQuery(self::$struct, $data, $columns = null); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 2, 'text' => "DB insert exception", 'data' => array("data" => $data), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } $new_group_id = $db->insert_id; if ($insert_ok && $new_group_id) { $result = true; } else { $result = false; } } elseif ($data['is_default'] == true && $groups_count != 0) { // Find $group_id of current default group $args = array(array("col" => "is_default", "op" => "=", "val" => "1")); $columns = array("mode" => "include", "col" => "group_id"); $ctrl = array("format" => "var"); try { $old_default = $db->runSelectQuery(self::$struct, $args, $columns, $ctrl); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 3, 'text' => "DB select exception", 'data' => array("args" => $args, "columns" => $columns, "ctrl" => $ctrl), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } // @@@@@@ BEGIN TRANSACTION @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ try { $started_transaction = $db->beginTransaction(); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 2, 'text' => "beginTransaction exception", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } if ($started_transaction) { // Insert new group into the db try { $insert_ok = $db->runInsertQuery(self::$struct, $data, $columns = null); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 3, 'text' => "DB insert exception", 'data' => $data, 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } $new_group_id = $db->insert_id; // Remove remove default flag from old group $unset_default = array("is_default" => false); try { $unset_ok = $db->runUpdateQueryCol(self::$struct, $unset_default, "group_id", "=", $old_default); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 4, 'text' => "DB update exception", 'data' => array("data" => $unset_default, "col" => "group_id", "op" => "=", "val" => $old_default), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } // If all queries were successful, commit the transaction if ($insert_ok && $new_group_id && $unset_ok) { try { $result = $db->commitTransaction(); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 5, 'text' => "commitTransaction exception", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } } else { //echo "\ninsert_ok:$insert_ok new_group_id: $new_group_id old_default:$old_default unset_ok:$unset_ok"; try { $db->rollbackTransaction(); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 6, 'text' => "rollbackTransaction exception", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } $result = false; } } else { $result = false; } // @@@@@@ END TRANSACTION @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ } else { // Insert new group into the db try { $insert_ok = $db->runInsertQuery(self::$struct, $data, $columns = null); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 7, 'text' => "DB insert exception", 'data' => array("data" => $data), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } $new_group_id = $db->insert_id; if ($insert_ok && $new_group_id) { $result = true; } else { $result = false; } } // Update the cache // ========================================= if ($new_group_id && $result) { try { self::loadCache(); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 4, 'text' => "loadCache exception", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } $this->cache["ids"][$data['name']] = $new_group_id; if ($data['is_default']) { $this->cache["default_id"] = $new_group_id; } try { $cache_ok = self::saveCache(); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 5, 'text' => "saveCache exception", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } if ($cache_ok) { return $new_group_id; } else { return false; } } else { return false; } }
/** * Deletes one or more trees from the datastore * * @version 1.0 * @since 1.0 * * @param string/array $trees | Single tree as string. Multiple trees as array of string. * @return int | Exception on failure. Number of db rows changed on success. */ public function dropTree($trees) { $db = new FOX_db(); $struct = $this->_struct(); // Lock the cache // =========================================================== try { $cache_image = self::lockCache(); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 1, 'text' => "Error locking cache", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child)); } // Update the database // =========================================================== $args = array(array("col" => "tree", "op" => "=", "val" => $trees)); try { $rows_changed = $db->runDeleteQuery($struct, $args); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 2, 'text' => "Error deleting from database", 'data' => array('args' => $args), 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child)); } if (!is_array($trees)) { $trees = array($trees); } // Rebuild the cache image // =========================================================== foreach ($trees as $tree) { unset($cache_image["keys"][$tree]); unset($cache_image["branches"][$tree]); unset($cache_image["trees"][$tree]); } unset($tree); // Clear empty walks $cache_image["branches"] = FOX_sUtil::arrayPrune($cache_image["branches"], 1); $cache_image["keys"] = FOX_sUtil::arrayPrune($cache_image["keys"], 2); // Write the image back to the persistent cache, releasing our lock // =========================================================== try { self::writeCache($cache_image); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 3, 'text' => "Cache write error", 'data' => array('cache_image' => $cache_image), 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child)); } // Update the class cache $this->cache = $cache_image; return (int) $rows_changed; }
/** * Fetches a key, branch, tree, or an entire user's keystore from the key cache. * * If an object is not in the cache yet, it will be retrieved from the database * and added to the cache. Multiple items in the *lowest level group* specified * can be retrieved in a single query by passing their names or id's as an array. * * WRONG: get( $id=1, $tree = array(3, 6, 7, 2), $branch=7, $key="gender") * ^^^^^^^^^^^^^^^^^^^^^^^^ * RIGHT: get( $id=1, $tree=2, $branch=7, $key=array("fans","likes","gender") * * @version 1.0 * @since 1.0 * * @param int/array $user_id | Single $user_id as int. Multiple as array of ints. * @param int/array $tree | Single $tree as int. Multiple as array of ints. * @param int/array $branch | Single $branch as int. Multiple as array of ints. * @param string/array $key | Single key name as string. Multiple as array of strings. * @param bool &$valid | True if the object exists. False if not. * @param array &$error | Array containing numeric and text error information * @return bool | False on failure. True on success. */ public function get($user_id, $tree = null, $branch = null, $key = null, &$valid = null) { global $rad; $db = new FOX_db(); $args = array(); // Key or group of keys // ============================= if ($user_id && $tree && $branch && $key) { if (is_array($user_id) || is_array($tree) || is_array($branch)) { throw new FOX_exception(array('numeric' => 1, 'text' => "Attempted to pass multiple user id's, tree's, or branches when specifying key", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => null)); } // If the user_id is not present in the class cache array, try to load it // from the persistent cache if (!$this->cache[$user_id]) { try { $this->cache[$user_id] = $rad->cache->get("FOX_uData", $user_id, $valid); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 2, 'text' => "Cache get exception", 'data' => array("user_id" => $user_id, "tree" => $tree, "branch" => $branch, "key" => $key), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } } // Single key if (!is_array($key)) { $single = true; $key = array($key); } else { $single = false; } // Find all the keys that have been requested but are not in the cache $missing_keys = array(); $branch_cached = FOX_sUtil::keyTrue($branch, $this->cache[$user_id]["branch"][$tree]); $tree_cached = FOX_sUtil::keyTrue($tree, $this->cache[$user_id]["tree"]); $user_cached = FOX_sUtil::keyTrue("all_cached", $this->cache[$user_id]); if (!$branch_cached && !$tree_cached && !$user_cached) { foreach ($key as $key_name) { if (!FOX_sUtil::keyExists($key_name, $this->cache[$user_id]["keys"][$tree][$branch])) { $missing_keys[] = $key_name; } } unset($key_name); } // Load missing keys if (count($missing_keys) != 0) { try { $this->load($user_id, $tree, $branch, $missing_keys, $skip_load = true); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 3, 'text' => "Load exception", 'data' => array("user_id" => $user_id, "tree" => $tree, "branch" => $branch, "missing_keys" => $missing_keys), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } } $result = array(); // Build an array of the requested keys foreach ($key as $key_name) { if (FOX_sUtil::keyExists($key_name, $this->cache[$user_id]["keys"][$tree][$branch])) { $result[$key_name] = $this->cache[$user_id]["keys"][$tree][$branch][$key_name]; } else { $result[$key_name] = null; } } unset($key_name); // Only set the $valid flag true if every requested key was successfully fetched if (count($result) == count($key)) { $valid = true; } else { $valid = false; } // If only one key was requested, and the key was successfully retrieved from the db, // lift the result array up one level if ($single == true && count($result) == 1) { $result = $result[$key[0]]; } return $result; } elseif ($user_id && $tree && $branch && !$key) { if (is_array($user_id) || is_array($tree)) { throw new FOX_exception(array('numeric' => 4, 'text' => "Attempted to pass multiple user id's or tree's when specifying branch", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => null)); } // If the user_id is not present in the class cache array, try to load it // from the persistent cache if (!$this->cache[$user_id]) { try { $this->cache[$user_id] = $rad->cache->get("FOX_uData", $user_id, $valid); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 5, 'text' => "Cache get exception", 'data' => array("user_id" => $user_id, "tree" => $tree, "branch" => $branch), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } } // Single branch if (!is_array($branch)) { $single = true; $branch = array($branch); } else { $single = false; } // Find all the branches that have been requested but are not in the cache $missing_branches = array(); foreach ($branch as $branch_name) { $branch_cached = FOX_sUtil::keyTrue($branch_name, $this->cache[$user_id]["branch"][$tree]); $tree_cached = FOX_sUtil::keyTrue($tree_name, $this->cache[$user_id]["tree"]); $user_cached = FOX_sUtil::keyTrue("all_cached", $this->cache[$user_id]); if (!$branch_cached && !$tree_cached && !$user_cached) { $missing_branches[] = $branch_name; } } unset($branch_name); // Load missing branches if (count($missing_branches) != 0) { try { $this->load($user_id, $tree, $missing_branches, null, $skip_load = true); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 6, 'text' => "Load exception", 'data' => array("user_id" => $user_id, "tree" => $tree, "missing_branches" => $missing_branches), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } } $result = array(); // Build an array of the requested branches foreach ($branch as $branch_name) { if (FOX_sUtil::keyExists($branch_name, $this->cache[$user_id]["keys"][$tree])) { $result[$branch_name] = $this->cache[$user_id]["keys"][$tree][$branch_name]; } else { $result[$branch_name] = null; } } unset($branch_name); // Only set the $valid flag true if every requested branch was successfully fetched if (count($result) == count($branch)) { $valid = true; } else { $valid = false; } // If only one branch was requested, and the branch was successfully retrieved from the db, // lift the result array up one level if ($single == true && count($result) == 1) { $result = $result[$branch[0]]; } return $result; } elseif ($user_id && $tree && !$branch && !$key) { if (is_array($user_id)) { throw new FOX_exception(array('numeric' => 7, 'text' => "Attempted to pass multiple user id's when specifying tree", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => null)); } // If the user_id is not present in the class cache array, try to load it // from the persistent cache if (!$this->cache[$user_id]) { try { $this->cache[$user_id] = $rad->cache->get("FOX_uData", $user_id, $valid); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 8, 'text' => "Cache get exception", 'data' => array("user_id" => $user_id, "tree" => $tree), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } } // Single tree if (!is_array($tree)) { $single = true; $tree = array($tree); } else { $single = false; } // Find all the trees that have been requested but are not in the cache $missing_trees = array(); foreach ($tree as $tree_name) { $tree_cached = FOX_sUtil::keyTrue($tree_name, $this->cache[$user_id]["tree"]); $user_cached = FOX_sUtil::keyTrue("all_cached", $this->cache[$user_id]); if (!$tree_cached && !$user_cached) { $missing_trees[] = $tree_name; } } unset($tree_name); // Load missing trees if (count($missing_trees) != 0) { try { $this->load($user_id, $missing_trees, null, null, $skip_load = true); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 9, 'text' => "Load exception", 'data' => array("user_id" => $user_id, "missing_trees" => $missing_trees), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } } $result = array(); // Build an array of the requested trees foreach ($tree as $tree_name) { if (FOX_sUtil::keyExists($tree_name, $this->cache[$user_id]["keys"])) { $result[$tree_name] = $this->cache[$user_id]["keys"][$tree_name]; } else { $result[$tree_name] = null; } } unset($tree_name); // Only set the $valid flag true if every requested tree was successfully fetched if (count($result) == count($tree)) { $valid = true; } else { $valid = false; } // If only one tree was requested, and the tree was successfully retrieved from the db, // lift the result array up one level if ($single == true && count($result) == 1) { $result = $result[$tree[0]]; } return $result; } elseif ($user_id && !$tree && !$branch && !$key) { if (!is_array($user_id)) { $single = true; $user_id = array($user_id); } else { $single = false; } // Find all the user_id's that have been requested but are not in the cache $missing_trees = array(); foreach ($user_id as $current_user_id) { if (!FOX_sUtil::keyTrue("all_cached", $this->cache[$current_user_id])) { $missing_users[] = $current_user_id; } } unset($current_user_id); // Load missing user_id's if (count($missing_users) != 0) { try { $this->load($missing_users, null, null, null, $skip_load = true); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 10, 'text' => "Load exception", 'data' => array("missing_users" => $missing_users), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } } $result = array(); // Build an array of the requested users foreach ($user_id as $current_user_id) { if (FOX_sUtil::keyExists($current_user_id, $this->cache)) { $result[$current_user_id] = $this->cache[$current_user_id]["keys"]; } else { $result[$current_user_id] = null; } } unset($current_user_id); // Only set the $valid flag true if every requested tree was successfully fetched if (count($result) == count($user_id)) { $valid = true; } else { $valid = false; } // If only one user_id was requested, and the user_id was successfully retrieved from the db, // lift the result array up one level if (($single = true) && count($result) == 1) { $result = $result[$user_id[0]]; } return $result; } else { throw new FOX_exception(array('numeric' => 10, 'text' => "Bad input args", 'data' => array("user_id" => $user_id, "tree" => $tree, "branch" => $branch, "key" => $key), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => null)); } }
/** * Deletes an item from the cache * * @version 1.0 * @since 1.0 * * @param string $key | Name of key * @return bool | False on failure. True on success. */ public function delete($key) { if (FOX_sUtil::keyExists($key, $this->cache)) { unset($this->cache[$key]); return true; } else { return false; } }
/** * Strips ASCII and Latin1 control characters. Passes spaces. * * @version 1.0 * @since 1.0 * * @param string $input | input string to process * @param array $ctrl | control parameters * @return string | the processed string */ public function printableCharacter($input, $ctrl = null, &$valid = null, &$error = null) { $ctrl_default = array("null_input" => "null", "min_len" => 0, "max_len" => 50000); // crash on very large strings. For example, preg_replace() crashes // at about 94,000 characters. $ctrl = FOX_sUtil::parseArgs($ctrl, $ctrl_default); if ($input === null) { if ($ctrl["null_input"] == "null") { $valid = true; return null; } elseif ($ctrl["null_input"] == "trap") { $valid = false; $error = "null input value"; return null; } } else { // Make absolutely sure PHP treats the input data as a string $result = (string) $input; // We can't use the [:print:] character class because its a POSIX regex class and it's // not available in PHP's PCRE regex implementation (POSIX was deprecated in PHP 5.3). // Remove ASCII control characters $result = preg_replace('[\\x00-\\x1F\\x7F]', '', $result); // Remove Latin1 control characters $result = preg_replace('[\\x80-\\x9F]', '', $result); $len = strlen($result); // Handle string being zero length after trimming off padding characters if ($len == 0) { if ($ctrl["null_input"] == "null") { $valid = true; return null; } elseif ($ctrl["null_input"] == "trap") { $valid = false; $error = "null input value"; return null; } } // Truncate strings that exceed the max length if ($len > $ctrl["max_len"]) { $valid = true; $result = substr($result, 0, $ctrl["max_len"]); return $result; } elseif ($len < $ctrl["min_len"]) { $valid = false; $error = "string exceeds min_len"; return $result; } else { $valid = true; return $result; } } }
/** * Locks the class' entire namespace, giving the locking PID exclusive control of it. * * @version 1.0 * @since 1.0 * * @param array $ctrl | Control parameters * => VAL @param int $seconds | Time in seconds from present time until lock expires * * @return mixed | Exception on failure. True on success. */ public function lockNamespace($ctrl = null) { if ($this->debug_on) { extract($this->debug_handler->event(array('pid' => $this->process_id, 'text' => "method_start", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars()))))); } $struct = $this->_struct(); if ($struct['cache_strategy'] != 'paged') { throw new FOX_exception(array('numeric' => 1, 'text' => "This method can only be used on classes that use a paged cache", 'data' => array('struct' => $struct), 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => null)); } $ctrl_default = array('seconds' => 5); $ctrl = FOX_sUtil::parseArgs($ctrl, $ctrl_default); try { $result = $this->mCache->lockNamespace(array('process_id' => $this->process_id, 'engine' => $struct["cache_engine"], 'namespace' => $struct["cache_namespace"], 'seconds' => $ctrl['seconds'])); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 2, 'text' => "Error in mCache->lockNamespace()", 'data' => array('struct' => $struct), 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child)); } if ($this->debug_on) { extract($this->debug_handler->event(array('pid' => $this->process_id, 'text' => "method_end", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars()))))); } return $result; }
/** * Drops one or more items of the specified level from ALL WALKS in the datastore. * * @version 1.0 * @since 1.0 * @param int $level | Level to drop items from * @param int/string/array $items | Single item as int/string, multiple as array of int/string. * * @return int | Exception on failure. Number of rows changed on success. */ public function dropGlobal($level, $items, $ctrl = null) { if (!$this->init) { throw new FOX_exception(array('numeric' => 0, 'text' => "Descendent class must call init() before using class methods", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => null)); } if ($this->debug_on) { extract($this->debug_handler->event(array('pid' => $this->process_id, 'text' => "method_start", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars()))))); } $col = "L" . $level . "_col"; $ctrl_default = array("validate" => true); $ctrl = FOX_sUtil::parseArgs($ctrl, $ctrl_default); // Validate // =================================================== if ($ctrl['validate'] != false) { if ($this->debug_on) { extract($this->debug_handler->event(array('pid' => $this->process_id, 'text' => "validate_start", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars()))))); } // Each variable has to be validated individually. If we spin the variables // into a trie, PHP will automatically convert strings that map to ints ("17") // into (int) keys, which will defeat the validators $struct = $this->_struct(); try { $validator = new FOX_dataStore_validator($struct); // If a single item is sent in, we validate it *before* spinning it into an array, // so we can trap strings that PHP automatically converts to ints ("17") if (!is_array($items)) { $is_valid = $validator->validateKey(array('type' => $struct['columns'][$this->{$col}]['php'], 'format' => 'scalar', 'var' => $items)); } else { foreach ($items as $key => $val) { $is_valid = $validator->validateKey(array('type' => $struct['columns'][$this->{$col}]['php'], 'format' => 'scalar', 'var' => $val)); // Break the loop if we hit an invalid key if ($is_valid !== true) { break; } } unset($key, $val); } } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 1, 'text' => "Error in validator", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child)); } // This structure has to be outside the validator try-catch block to prevent it from // catching the exceptions we throw (which would cause confusing exception chains) if ($is_valid !== true) { throw new FOX_exception(array('numeric' => 2, 'text' => "Invalid item", 'data' => $is_valid, 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => null)); } if ($this->debug_on) { extract($this->debug_handler->event(array('pid' => $this->process_id, 'text' => "validate_end", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars()))))); } } // ENDOF: if($ctrl['validate'] != false){ // Lock the entire cache namespace // =========================================================== if ($this->debug_on) { extract($this->debug_handler->event(array('pid' => $this->process_id, 'text' => "persistent_cache_lock_start", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars()))))); } try { self::lockNamespace(); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 3, 'text' => "Error locking cache namespace", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child)); } if ($this->debug_on) { extract($this->debug_handler->event(array('pid' => $this->process_id, 'text' => "persistent_cache_lock_end", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars()))))); } if ($this->debug_on) { extract($this->debug_handler->event(array('pid' => $this->process_id, 'text' => "db_delete_start", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars()))))); } $args = array(array("col" => $this->{$col}, "op" => "=", "val" => $items)); try { $rows_changed = $this->db->runDeleteQuery($struct, $args, $ctrl = null); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 4, 'text' => "Error while deleting from database", 'data' => $args, 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child)); } if ($this->debug_on) { extract($this->debug_handler->event(array('pid' => $this->process_id, 'text' => "db_delete_end", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars()))))); } // Since this operation affects ALL L5 pages, we have to flush the // entire cache namespace if ($this->debug_on) { extract($this->debug_handler->event(array('pid' => $this->process_id, 'text' => "persistent_cache_flush_start", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars()))))); } try { self::flushCache(); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 5, 'text' => "Cache flush error", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child)); } if ($this->debug_on) { extract($this->debug_handler->event(array('pid' => $this->process_id, 'text' => "persisent_cache_flush_end", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars()))))); } if ($this->debug_on) { extract($this->debug_handler->event(array('pid' => $this->process_id, 'text' => "method_end", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars()))))); } return (int) $rows_changed; }
/** * Checks if a user is a member of a group * * @version 1.0 * @since 1.0 * * @param int $user_id | Single $user_id as int. * @param int $group_id | Single $group_id as int. * @return bool | True if user is a member of the group. False if not. */ public function inGroup($user_id, $group_id) { global $fox; // If the user-group pair has an entry in the class cache array, return its value (true // if the user has the key, false if they don't) if (FOX_sUtil::keyExists($group_id, $this->cache[$user_id]["keys"])) { $result = $this->cache[$user_id]["keys"][$group_id]; } elseif ($this->cache[$user_id]["all_cached"] == true) { $result = false; } else { $this->cache[$user_id] = $fox->cache->get("FOX_uGroupMember", $user_id); if (FOX_sUtil::keyExists($group_id, $this->cache[$user_id]["keys"])) { $result = $this->cache[$user_id]["keys"][$group_id]; } elseif ($this->cache[$user_id]["all_cached"] == true) { $result = false; } else { try { self::load($user_id, $group_id); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 1, 'text' => "FOX_uGroupMember load exception", 'data' => array("user_id" => $user_id, "group_id" => $group_id), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } $result = $this->cache[$user_id]["keys"][$group_id]; } } return $result; }
/** * Drops all keys from the database and cache for one or more type_ids belonging * to a single module id. * * @version 1.0 * @since 1.0 * * @param int $module_id | ID of the module * @param string/array $type_ids | Single type_id as string. Multiple type_ids as array of string. * * @return bool | Exception on failure. True on success. False on nonexistent. */ public function dropType($module_id, $type_ids) { $db = new FOX_db(); $struct = $this->_struct(); if (empty($module_id) || empty($type_ids)) { throw new FOX_exception(array('numeric' => 1, 'text' => "Empty control parameter", 'data' => array("module_id" => $module_id, "type_id" => $type_ids), 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => null)); } if (is_array($module_id)) { throw new FOX_exception(array('numeric' => 2, 'text' => "Attempted to pass multiple module id's", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => null)); } // Lock and load the module_id's cache page // =========================================================== try { $update_cache = self::lockCachePage($module_id); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 3, 'text' => "Error locking cache page", 'data' => array("module_id" => $module_id), 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child)); } // Drop affected type_ids from the db // =========================================================== $args = array(array("col" => "module_id", "op" => "=", "val" => $module_id), array("col" => "type_id", "op" => "=", "val" => $type_ids)); try { $rows_changed = $db->runDeleteQuery($struct, $args, $ctrl = null); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 4, 'text' => "Error while deleting from database", 'data' => array("module_id" => $module_id, "type_id" => $type_ids), 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child)); } // Rebuild the module_id's cache page image // =========================================================== if (!is_array($type_ids)) { $type_ids = array($type_ids); } foreach ($type_ids as $type_id) { unset($update_cache["keys"][$type_id]); unset($update_cache["branch_id"][$type_id]); unset($update_cache["type_id"][$type_id]); } unset($type_id); $update_cache["keys"] = FOX_sUtil::arrayPrune($update_cache["keys"], 2); $update_cache["branch_id"] = FOX_sUtil::arrayPrune($update_cache["branch_id"], 1); // Overwrite the module_id's cache page, releasing our lock // =========================================================== try { self::writeCachePage(array($module_id => $update_cache)); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 5, 'text' => "Cache set error", 'data' => array("module_id" => $module_id, "update_cache" => $update_cache), 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child)); } $this->cache[$module_id] = $update_cache; return (bool) $rows_changed; }
/** * Runs a DELETE query on one of the plugin's db tables. * * @version 1.0 * @since 1.0 * * @param array $struct | Structure of the db table, @see class FOX_db header for examples * * @param array $args | Args in the form: array("col"=>column_name, "op" => "<, >, =, !=", "val" => "int | string | array()") * => ARR @param int '' | Array index * => VAL @param string $col | Name of the column in the db table this key describes * => VAL @param string $op | SQL comparison operator to use: ">=" | "<=" | ">" | "<" | "=" | "!=" | "<>" * => VAL @param int/string/array $val | Value or values to test against. Single value as int/string. Multiple values as array. * * @param array $ctrl | Control parameters for the query * => VAL @param string $args_format | "default" to use standard format, "multi", "matrix", or "trie" * * @return int | Exception on failure. Int number of rows deleted on success. */ public function runDeleteQuery($struct, $args, $ctrl = null) { if ($this->debug_on) { extract($this->debug_handler->event(array('pid' => $this->process_id, 'text' => "method_start", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars()))))); } // Add default control params // ========================== $ctrl_default = array("args_format" => "default"); $ctrl = FOX_sUtil::parseArgs($ctrl, $ctrl_default); // Build query string // ======================= if ($this->debug_on) { extract($this->debug_handler->event(array('pid' => $this->process_id, 'text' => "build_query", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars()))))); } try { $query = $this->builder->buildDeleteQuery($struct, $args, $ctrl); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 1, 'text' => "Error in query generator", 'data' => array("struct" => $struct, "args" => $args, 'ctrl' => $ctrl), 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child)); } // Run on SQL server // ======================= if ($this->debug_on) { extract($this->debug_handler->event(array('pid' => $this->process_id, 'text' => "run_query", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars()))))); } try { $this->runner->runQuery($query, array('format' => 'var')); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 2, 'text' => "Error executing query on SQL server", 'data' => array("query" => $query), 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child)); } if ($this->debug_on) { extract($this->debug_handler->event(array('pid' => $this->process_id, 'text' => "method_end", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars()))))); } return $this->rows_affected; }
/** * Loads a monolithic class cache array from the persistent cache and locks the class * namespace until the timeout expires or the PID releases the lock by writing to the * cache. Read requests in the namespace will throw an exception until the lock expires. * Write and delete requests will remove the lock and clear/update the namespace. * * @version 1.0 * @since 1.0 * * @param string/array $keys | Single key as string. Multiple keys as array of strings. * * @param array $args | Control args * => VAL @param string $namespace | Class namespace * => VAL @param int $seconds | Time in seconds from present time until lock expires * => VAL @param string/array $pages | Single page as string. Multiple pages as array of string. * * @return int &$offset | Current namespace offset * @return mixed | Exception on failure. Mixed on success. */ public function lockCachePage($args, &$offset = null) { if (!is_array($args['pages'])) { $args['pages'] = array($args['pages']); } try { $cache_result = $this->getMulti($args["namespace"], $args['pages'], $offset); } catch (FOX_exception $child) { if ($child->data['numeric'] == 4) { throw new FOX_exception(array('numeric' => 1, 'text' => "Cache namespace is currently locked by another PID", 'data' => $child->data['data'], 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => null)); } else { throw new FOX_exception(array('numeric' => 2, 'text' => "Error in descendent::getMulti()", 'data' => $args, 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child)); } } $processed_result = array(); $locked_pages = array(); foreach ($args['pages'] as $page) { // Page has no cache entry // ============================================================= if (!FOX_sUtil::keyExists($page, $cache_result)) { // Write an empty array to the result $processed_result[$page] = array(); } elseif (!FOX_sUtil::keyExists("lock", $cache_result[$page])) { $processed_result[$page] = $cache_result[$page]; } else { $expiry_time = $cache_result[$page]['lock']['expire']; $current_time = microtime(true); if ($current_time > $expiry_time) { // If the lock has expired, the cache contents are no longer // valid. Return an empty cache array $processed_result[$page] = array(); } elseif ($cache_result[$page]['lock']['pid'] == $this->process_id) { // If the lock is owned by the current PID, just write back the lock array to the cache // with an updated timestamp, refreshing the lock. This provides important functionality, // letting a PID that has a lock on the page extend its lock time incrementally as it // works through a complex processing job. If the PID had to release and reset the lock // each time, the data would be venerable to being overwritten by other PID's. unset($cache_result[$page]['lock']); $processed_result[$page] = $cache_result[$page]; } else { // Othewise, the lock is still valid, so flag the key $locked_pages[$page] = $cache_result[$page]['lock']; } } } unset($page); // If any of the pages were already locked, throw an exception if (count($locked_pages) != 0) { throw new FOX_exception(array('numeric' => 3, 'text' => "One or more requested pages are currently locked", 'data' => $locked_pages, 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => null)); } // Build a cache image with the lock array added to each cache // page, and write it to the cache // ============================================================= $cache_image = array(); $lock_array = array('pid' => $this->process_id, 'expire' => microtime(true) + $args['seconds']); foreach ($processed_result as $page => $data) { // FoxFire data classes always use an array as their storage variable and // store scalar values into it as keys. They never use a single scalar // variable as their storage object. So the line below is valid. $data['lock'] = $lock_array; $cache_image[$page] = $data; } unset($page, $data); try { $this->setMulti($args["namespace"], $cache_image, $offset); } catch (FOX_exception $child) { if ($child->data['numeric'] == 5) { throw new FOX_exception(array('numeric' => 4, 'text' => "Namespace was flushed by another PID during page locking sequence.", 'data' => $child->data['data'], 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => null)); } elseif ($child->data['numeric'] == 4) { throw new FOX_exception(array('numeric' => 5, 'text' => "Namespace was locked by another PID during page locking sequence.", 'data' => $child->data['data'], 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => null)); } else { throw new FOX_exception(array('numeric' => 6, 'text' => "Error in descendent::setMulti()", 'data' => $cache_image, 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child)); } } return $processed_result; }
function test_pluginPathToURL() { // Single path as string // ============================================ $test = FOX_PATH_BASE . "/foo/bar.jpg"; $check = FOX_URL_BASE . "/foo/bar.jpg"; $result = FOX_sUtil::pluginPathToURL($test); $this->assertEquals($check, $result); // Multiple paths as array // ============================================ $test = array(FOX_PATH_BASE . "/foo/bar1.jpg", FOX_PATH_BASE . "/foo/bar2.jpg", FOX_PATH_BASE . "/foo/bar3.jpg"); $check = array(FOX_URL_BASE . "/foo/bar1.jpg", FOX_URL_BASE . "/foo/bar2.jpg", FOX_URL_BASE . "/foo/bar3.jpg"); $result = FOX_sUtil::pluginPathToURL($test); $this->assertEquals($check, $result); }
/** * Processes config variables passed via an HTML form * * @version 1.0 * @since 1.0 * * @param array $post | HTML form array * @return bool | Exception on failure. True on success. */ public function processHTMLForm($post) { if (empty($post['key_names'])) { throw new FOX_exception(array('numeric' => 1, 'text' => "No key names posted with form", 'data' => $post, 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => null)); } $san = new FOX_sanitize(); // Explode fields array into individual key names $options = explode(',', stripslashes($post['key_names'])); // Sanitize keys. Loft key-value pairs into a multidimensional array // ==================================================================== $processed_keys = array(); foreach ($options as $option) { $full_name = explode($this->key_delimiter, $option); // Process the raw form strings into proper key names $raw_tree = trim($full_name[0]); $raw_branch = trim($full_name[1]); $raw_key = trim($full_name[2]); // Passed by reference $tree_valid = null; $branch_valid = null; $key_valid = null; $tree_error = null; $branch_error = null; $key_error = null; try { $tree = $san->keyName($raw_tree, null, $tree_valid, $tree_error); $branch = $san->keyName($raw_branch, null, $branch_valid, $branch_error); $key = $san->keyName($raw_key, null, $key_valid, $key_error); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 2, 'text' => "Error in sanitizer function", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } if (!$tree_valid) { throw new FOX_exception(array('numeric' => 3, 'text' => "Called with invalid tree name", 'data' => array('raw_tree' => $raw_tree, 'san_error' => $tree_error), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => null)); } elseif (!$branch_valid) { throw new FOX_exception(array('numeric' => 4, 'text' => "Called with invalid branch name", 'data' => array('raw_branch' => $raw_branch, 'san_error' => $branch_error), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => null)); } elseif (!$key_valid) { throw new FOX_exception(array('numeric' => 5, 'text' => "Called with invalid key name", 'data' => array('raw_tree' => $raw_tree, 'raw_branch' => $raw_branch, 'raw_key' => $raw_key, 'san_error' => $key_error), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => null)); } // Manually generate the $post array keyname to avoid escaping added by PHP $post_key = $tree . $this->key_delimiter . $branch . $this->key_delimiter . $key; $processed_keys[$tree][$branch][$key] = FOX_sUtil::formVal($post[$post_key]); unset($full_name, $tree, $raw_tree, $branch, $raw_branch, $key, $raw_key); unset($tree_error, $branch_error, $key_error, $tree_valid, $branch_valid, $key_valid); } unset($option); // Assemble the processed keys into the right format for the // the database classes // =============================================================== $target_data = array(); if ($processed_keys["target"]["key"]["location"] == "page") { $target_data["location"] = (string) $processed_keys["target"]["key"]["location"]; $target_data["module_id"] = (int) $processed_keys["target"]["key"]["module_id"]; $target_data["target"] = (int) $processed_keys["target"]["key"]["page_id"]; } else { $target_data["location"] = (string) $processed_keys["target"]["key"]["location"]; $target_data["module_id"] = (int) $processed_keys["target"]["key"]["module_id"]; $target_data["target"] = (string) $processed_keys["target"]["key"]["slug"]; $target_data["tab_title"] = (string) $processed_keys["target"]["key"]["tab_title"]; $target_data["tab_position"] = (int) $processed_keys["target"]["key"]["tab_position"]; } $policy_data = array(); // Loft the keys into a heirarchical array and decode JSON-encoded fields // ====================================================================== foreach ($processed_keys["policy"] as $zone => $rules) { foreach ($rules as $rule => $rule_data) { $rule_decoded = json_decode($rule_data, true); if (!empty($rule_decoded)) { foreach ($rule_decoded as $key_type => $key_ids) { foreach ($key_ids as $key_id => $key_data) { // Since we're not handling $ctrl info for keys yet, we need to // manually set a value for the key. $policy_data[$zone][$rule][$key_type][$key_id] = true; } unset($key_id, $key_data); } unset($key_type, $key_ids); } } unset($rule, $rule_data, $rule_decoded); } unset($zone, $rules); // Update the target and policy classes // =============================================================== try { $this->target_class->setTarget($target_data); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 6, 'text' => "Error updating target data", 'data' => $target_data, 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } try { $this->policy_class->replaceL5((int) $target_data["module_id"], $policy_data); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 7, 'text' => "Error updating policy data", 'data' => array('module_id' => $target_data["module_id"], 'policy_data' => $policy_data), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } return true; }
/** * Removes one or more targets from the database and cache. * * @version 1.0 * @since 1.0 * @param string $location | Single location as string. * @param int/string/array targets | Single target as int or string. Multiple targets as array of int/string. * @return int | Exception on failure. Int number of db rows changed on success. */ public function dropTarget($location, $targets) { $db = new FOX_db(); $struct = self::_struct(); if (empty($location) || !is_string($location)) { throw new FOX_exception(array('numeric' => 1, 'text' => "Invalid location parameter", 'data' => array($location, $targets), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => null)); } if (empty($targets)) { throw new FOX_exception(array('numeric' => 2, 'text' => "Invalid targets parameter", 'data' => array($location, $targets), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => null)); } if (!is_array($targets)) { // Handle single int as input $targets = array($targets); } // Lock the cache // =========================================================== try { $cache_image = self::lockCache(); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 3, 'text' => "Error locking cache", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } // Update the database // =========================================================== $args = array(array("col" => "location", "op" => "=", "val" => $location), array("col" => "target", "op" => "=", "val" => $targets)); try { $rows_changed = $db->runDeleteQuery($struct, $args, $ctrl = null); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 4, 'text' => "Error deleting from database", 'data' => array('args' => $args), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } // Rebuild the cache image // =========================================================== foreach ($targets as $target) { if (FOX_sUtil::keyExists($target, $cache_image["data"][$location])) { unset($cache_image["data"][$location][$target]); // If deleting the target makes its parent location empty, remove // the parent location from the cache as well if (count($cache_image["data"][$location]) == 0) { unset($cache_image["data"][$location]); unset($cache_image["locations"][$location]); } } } unset($target); // Write the image back to the persistent cache, releasing our lock // =========================================================== try { self::writeCache($cache_image); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 5, 'text' => "Cache write error", 'data' => array('cache_image' => $cache_image), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } // Update the class cache $this->cache = $cache_image; return (int) $rows_changed; }
/** * Checks if a single user has a single key. If the key is not already cached, it will * be added to the class cache and the persistent cache. * * @version 1.0 * @since 1.0 * * @param int $user_id | user_id to check * @param int $key_id | key_id to check for * @return bool | True if user_id has key. False if not. */ public function hasKey($user_id, $key_id) { global $fox; $result = array(); // If the key has an entry in the class cache array, return its value (true // if the user has the key, false if they don't) if (FOX_sUtil::keyExists($key_id, $this->cache[$user_id]["keys"])) { $result = $this->cache[$user_id]["keys"][$key_id]; } elseif ($this->cache[$user_id]["all_cached"] == true) { $result = false; } else { $this->cache[$user_id] = $fox->cache->get("FOX_uKeyRing", $user_id); if (FOX_sUtil::keyExists($key_id, $this->cache[$user_id]["keys"])) { $result = $this->cache[$user_id]["keys"][$key_id]; } elseif ($this->cache[$user_id]["all_cached"] == true) { $result = false; } else { self::load($user_id, $key_id, $skip_load = true); $result = $this->cache[$user_id]["keys"][$key_id]; } } return $result; }
/** * Fetches one or more ids. * * @version 1.0 * @since 1.0 * @param int/array $ids | Single id as int. Multiple ids as array of int. * @return string/array | Exception on failure. String (single id). Array of string (multiple id's). */ public function getId($ids) { if (!$this->init) { throw new FOX_exception(array('numeric' => 0, 'text' => "Descendent class must call init() before using class methods", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => null)); } if (is_null($ids)) { throw new FOX_exception(array('numeric' => 1, 'text' => "null parameter passed as ids exception", 'data' => array("tokens" => $ids), 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => null)); } if (!is_array($ids)) { $ids = array($ids); $single = true; } else { $single = false; } // Fetch all ids currently stored in the class cache // ====================================================== $result = array(); $missing_ids = array(); foreach ($ids as $id) { if (FOX_sUtil::keyExists($id, $this->cache["ids"])) { $result[$id] = $this->cache["ids"][$id]; } else { $missing_ids[] = $id; } } unset($id); // Try to fetch missing ids from the persistent cache // ====================================================== if (count($missing_ids)) { try { $cache_ids = $this->cacheFetchId($missing_ids); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 2, 'text' => "Error in self::cacheFetchId()", 'data' => array("ids" => $missing_ids), 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child)); } if ($cache_ids) { $result = $result + $cache_ids; } $missing_ids = array_diff($missing_ids, array_keys($cache_ids)); } // Try to fetch missing ids from the database // ====================================================== if (count($missing_ids)) { try { $db_ids = $this->dbFetchId($missing_ids); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 3, 'text' => "Error in self::dbFetchId()", 'data' => array("ids" => $missing_ids), 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child)); } if ($db_ids) { $result = $result + $db_ids; } } if ($single == true) { return $result[$ids[0]]; } else { return $result; } }
/** * Fetches the ID's of one or more keys. * * @version 1.0 * @since 1.0 * * @param array $keys | one or more arrays, each descrrribing a key to retrieve * => ARR @param int '' | Array index * => VAL @param string $tree | tree name for key * => VAL @param string $branch | branch name for key * => VAL @param string/array $name | Single name as string. Multiple as array of strings. * * @param bool &$valid | True if all requested keys were found in the database. False if not. * @return bool/array | False on failure. Array of key ID's on success */ public function getKeyIDMulti($keys, &$valid = null) { global $fox; $valid = true; // Build a list of keys we need to fetch from the db. Remember, the class cache // array is loaded from the persistent cache every time the class is instantiated, // so if the requested keys are not in the class cache at this point, they will // have to be fetched from the db // ================================================================================ $missing_keys = array(); foreach ($keys as $key) { $tree = $key["tree"]; // This is easier to understand than using extract($key) $branch = $key["branch"]; // because it shows the variable names we're using $name = $key["name"]; if (!is_array($name)) { $name = array($name); } foreach ($name as $key_name) { if (!FOX_sUtil::keyExists($key_name, $this->cache["keys"][$tree][$branch])) { $missing_keys[$tree][$branch][$key_name] = true; } } } unset($key, $tree, $branch, $name, $key_name); // Load any missing keys from the database // ======================================= if (count($missing_keys) > 0) { $db = new FOX_db(); $key_ids = array(); foreach ($missing_keys as $tree_name => $branches) { foreach ($branches as $branch_name => $key_arrays) { foreach ($key_arrays as $key_name => $fake_var) { $args = array(array("col" => "tree", "op" => "=", "val" => $tree_name), array("col" => "branch", "op" => "=", "val" => $branch_name), array("col" => "name", "op" => "=", "val" => $key_name)); $columns = array("mode" => "include", "col" => array("key_id")); $ctrl = array("format" => "var"); try { $result = $db->runSelectQuery(self::$struct, $args, $columns, $ctrl); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 1, 'text' => "DB select exception", 'data' => array("args" => $args, "columns" => $columns, "ctrl" => $ctrl), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } if ($result) { $key_ids[$tree_name][$branch_name][$key_name] = $result; } else { // If the user has requested a non-existent key, set the // valid flag to false to indicate a problem $valid = false; } } } } unset($tree_name, $branches, $branch_name, $key_arrays, $key_names); // Update the cache // ================ if (count($key_ids) > 0) { // Update the class cache from the persistent cache try { self::loadCache(); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 2, 'text' => "loadCache exception", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } // Add keys fetched from the database to it foreach ($key_ids as $tree_name => $branches) { foreach ($branches as $branch_name => $key_names) { foreach ($key_names as $key_name => $val) { $this->cache["keys"][$tree_name][$branch_name][$key_name] = $val; } } } unset($tree_name, $branches, $branch_name, $key_names, $key_name, $val); // Write the updated class cache array to the persistent cache try { self::saveCache(); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 3, 'text' => "daveCache exception", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } } } // Build the results array // ======================= $result = array(); foreach ($keys as $key) { $tree = $key["tree"]; // This is easier to understand than using extract($key) $branch = $key["branch"]; // because it shows the variable names we're using $name = $key["name"]; $result[$tree][$branch][$name] = $this->cache["keys"][$tree][$branch][$name]; } unset($key, $tree, $branch, $name); return $result; }
/** * Prepares a SQL query for safe execution. Uses sprintf()-like syntax. * * @version 1.0 * @since 1.0 * * @param array $args | Query args array * => VAL @param string [0] | First key in array is query string in vsprintf() format * => VAL @param mixed [N] | Each successive key is a var referred to in the query string * * @return string | Prepared query string */ function prepare($query, $params = null) { // Force floats to be locale unaware $query = preg_replace('|(?<!%)%f|', '%F', $query); // Quote the strings, avoiding escaped strings like %%s $query = preg_replace('|(?<!%)%s|', "'%s'", $query); // Replace our %r raw string token with an unquoted %s $query = preg_replace('|(?<!%)%r|', "%s", $query); $escaped_params = array(); if ($params) { $cast = new FOX_cast(); foreach ($params as $param) { if (!FOX_sUtil::keyExists('escape', $param) || !FOX_sUtil::keyExists('val', $param) || !FOX_sUtil::keyExists('php', $param) || !FOX_sUtil::keyExists('sql', $param)) { $text = "SAFETY INTERLOCK TRIP [ANTI SQL-INJECTION] - All data objects passed to the "; $text .= "database driver must include 'val', 'escape', 'php', and 'sql' parameters. This "; $text .= "interlock cannot be disabled."; throw new FOX_exception(array('numeric' => 1, 'text' => $text, 'data' => $param, 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => null)); } try { $cast_val = $cast->PHPToSQL($param['val'], $param['php'], $param['sql']); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 2, 'text' => "Error while casting parameter", 'data' => array("val" => $param['val'], "php" => $param['php'], "sql" => $param['sql']), 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child)); } if ($param['escape'] !== false) { // NOTE: parameters are in reverse order from mysqli_real_escape_string() $escaped_params[] = mysql_real_escape_string($cast_val, $this->dbh); } else { $escaped_params[] = $cast_val; } } unset($param); } $result = vsprintf($query, $escaped_params); return $result; }