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;
 }
Example #5
0
 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];
     }
 }
Example #13
0
 /**
  * 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;
 }
Example #15
0
 /**
  * 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);
 }
Example #25
0
 /**
  * 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;
 }