/** * Creates a new object type * * @version 1.0 * @since 1.0 * * @param array $data | * => VAL @param int $module_id | id for the module that owns this type. * => VAL @param string $type_slug | Slug name for this type. Must be unique to all other slugs. * => VAL @param string $name_admin | Admin name for this object type. Max 255 characters. * => VAL @param string $txt_admin | Admin description for this object type. * => VAL @param string $action_txt | Text shown to user in create object link. Max 255 characters. * => VAL @param string $name_user | Name shown to users for this object type. Max 255 characters. * => VAL @param string $txt_user | Description shown to users for this object type. * * @return bool/int | Exception on failure. $type_id of the new object type on success. */ public function addType($data) { $db = new FOX_db(); $columns = array("mode" => "exclude", "col" => array("type_id")); try { $db->runInsertQuery($this->_struct(), $data, $columns); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 1, 'text' => "Error writing to database", 'data' => array('data' => $data, 'columns' => $columns), 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child)); } // NOTE: The new type is *not* added to the "module_id_types" cache table in this function. This is to ensure // that if $cache->["module_id_types"]["module_id"] exists in the table, it contains an array of *all* // the type_ids for that module_id. This is more efficient than using a separate "module_id was cached" // table as we do in other classes, because new object types will rarely be added to the system. $type_id = $db->insert_id; // Update the cache // ===================================================================== try { $cache_image = self::readCache(); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 2, 'text' => "Cache read error", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child)); } // Rebuild the cache image $cache_image["slug_to_type_id"][$data["module_id"]][$data["type_slug"]] = $type_id; $cache_image["keys"][$type_id] = $data; try { self::writeCache($cache_image); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 3, 'text' => "Cache write error", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child)); } // Overwrite the class cache $this->cache = $cache_image; return $type_id; }
/** * Creates a new access level within an object type. * * @version 1.0 * @since 1.0 * * @param array $data | * => VAL @param int $module_id | Module that owns the object type that owns the access level. * => VAL @param int $type_id | Object type that owns the access level. * => VAL @param string $level_slug | Slug name for this level. Must be unique to all other slugs. * => VAL @param string $level_name | Name of the level. Max 64 characters. * => VAL @param string $level_desc | Description of the level. Max 255 characters. * => VAL @param int $rank | Rank of this level within the object type. 1-255 where 1 is the highest. * => VAL @param int $key_id | Key id required to access to this level * * @return int | Exception on failure. $level_id of the new level on success. */ public function addLevel($data) { $db = new FOX_db(); // Check that the rank doesn't already exist // ====================================================== $args = array(array("col" => "module_id", "op" => "=", "val" => $data["module_id"]), array("col" => "type_id", "op" => "=", "val" => $data["type_id"]), array("col" => "rank", "op" => "=", "val" => $data["rank"])); $ctrl = array("format" => "var", "count" => true); try { $already_exists = $db->runSelectQuery($this->_struct(), $args, $columns = null, $ctrl); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 1, 'text' => "Error reading from database", 'data' => array('args' => $args, 'ctrl' => $ctrl), 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child)); } if ($already_exists) { throw new FOX_exception(array('numeric' => 2, 'text' => "Object type already exists", 'data' => $data, 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child)); } else { // Add to the database // ====================================================== try { $db->runInsertQuery($this->_struct(), $data, $columns = null); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 3, 'text' => "Error writing to database", 'data' => $data, 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child)); } // NOTE: The new type is *not* added to the "type_levels" cache table in this function. This is to ensure // that if $cache->["type_levels"]["type_id"] exists in the table, it contains an array of *all* // the level_ids for that type_id. This is more efficient than using a separate "type_id was cached" // table as we do in other classes, because new type levels will rarely be added to the system. // Update the cache // ============================== $level_id = $db->insert_id; try { $cache_image = self::readCache(); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 4, 'text' => "Cache read error", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child)); } // Rebuild the cache image $cache_image["slug_to_level_id"][$data["module_id"]][$data["type_id"]][$data["level_slug"]] = $level_id; $cache_image["keys"][$level_id] = $data; try { self::writeCache($cache_image); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 5, 'text' => "Cache write error", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child)); } // Overwrite the class cache $this->cache = $cache_image; return (int) $level_id; } }
/** * Adds an event to the event log * * @version 1.0 * @since 1.0 * * @param array $event | Array holding data to be added to DB. An array in this form: key string for the column with value as null | int | string | array * => KEY @param string "tree" * => VAL @param int $tree | id of the event's tree * => KEY @param string "branch" * => VAL @param int $branch | id of the event's branch * => KEY @param string "node" * => VAL @param int $node | id of the event's node * => KEY @param string "user_id" * => VAL @param int $user_id | id of the user_id associated with this event. Use int 0 for a system event * => KEY @param string "level" * => VAL @param int $level | severity of this event. 1-255, where 1 is the most serious * => KEY @param string "date" * => VAL @param int $date | date and time the event occured, as linux datetime * => KEY @param string "summary" * => VAL @param string $summary | Human readable summary of the event. Max 128 characters. * => KEY @param string "data" * => VAL @param mixed $data | Full data associated with this event. Any PHP data type can be stored. * * @return bool/int | False on failure. ID of the created log entry on success. */ public function add($event) { if (empty($event)) { throw new FOX_exception(array('numeric' => 1, 'text' => "No event specified for addition", 'data' => $event, 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => null)); return false; } // Convert tree, branch, and node strings to ids // =================================================================== if (is_string($event["tree"]) && is_string($event["branch"]) && is_string($event["node"])) { try { $tree_id = $this->dict_tree->getToken($event["tree"]); $branch_id = $this->dict_branch->getToken($event["branch"]); $node_id = $this->dict_node->getToken($event["node"]); } catch (FOX_exception $child) { echo "Error reading dictionary"; throw new FOX_exception(array('numeric' => 2, 'text' => "Error reading dictionary", 'data' => array("tree_id" => $event["tree"], "branch_id" => $event["branch"], "node_id" => $event["node"]), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); return false; } } else { $tree_id = $event["tree"]; $branch_id = $event["branch"]; $node_id = $event["node"]; } // Check date if (!isset($event["date"])) { $event["date"] = time(); } // Add row to database // =================================================================== $db = new FOX_db(); $data = array("tree" => $tree_id, "branch" => $branch_id, "node" => $node_id, "user_id" => $event["user_id"], "level" => $event["level"], "date" => $event["date"], "summary" => $event["summary"], "data" => $event["data"]); try { $query_result = $db->runInsertQuery(self::$struct, $data, $columns = null, $ctrl = null); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 3, 'text' => "Error writing to database", 'data' => $data, 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); return false; } return $db->insert_id; }
/** * Adds one or more keys to one or more groups' keyrings * * @version 1.0 * @since 1.0 * * @param int $group_id | id of the group as int. Multiple groups as array of int. * @param int/array $key_id | id of the key as int. Multiple keys as array of int. * @return bool | False on failure. True on success. */ public function addKey($group_id, $key_id) { global $fox; $db = new FOX_db(); // Force a load of the entire class cache from the persistent cache try { self::loadCache(); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 1, 'text' => "loadCache exception", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } // CASE 1: Single group_id, single key // ================================================================= if (!is_array($group_id) && !is_array($key_id)) { // If the group already has the key, return true to indicate no db rows were changed if (self::hasKey($group_id, $key_id)) { return true; } else { $data = array("group_id" => $group_id, "key_id" => $key_id); try { $result = $db->runInsertQuery(self::$struct, $data, $columns = null); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 2, 'text' => "Db insert exception", 'data' => $data, 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } if ($result) { // Update the cache try { $cache_ok = self::saveCache(); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 3, 'text' => "saveCache exception", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } if ($cache_ok) { return $result; } else { return false; } } else { return $result; } } } // CASE 2: Single group_id, multiple keys // ================================================================= if (!is_array($group_id) && is_array($key_id)) { $keys_to_add = array(); // Create an array of "to be added" keys the user doesn't have. Note this algorithm // also eliminates duplicate keys, so we don't have to use array_unique() to avoid // a failed query if duplicate keys are present in $key_id foreach ($key_id as $key) { if (!self::hasKey($group_id, $key)) { $keys_to_add[] = $key; } } unset($key); // Check that there are actually keys to add, because running an insert query // with an empty data array will cause an SQL error if (count($keys_to_add) > 0) { // Add the new keys to the database $data = array(); foreach ($keys_to_add as $key) { $data[] = array("group_id" => $group_id, "key_id" => $key); } unset($key); try { $result = $db->runInsertQueryMulti(self::$struct, $data, $columns = null, $ctrl = null); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 4, 'text' => "DB insert exception", 'data' => $data, 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } // Update the cache if ($result) { foreach ($keys_to_add as $key) { $this->cache["keys"][$group_id][$key] = true; } unset($key); 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 $result; } else { return false; } } else { return $result; } } else { return true; } } // CASE 3: Multiple group_id's, single key // ================================================================= if (is_array($group_id) && !is_array($key_id)) { $groups_to_add = array(); // Create an array of groups to be given the key that don't have the key yet foreach ($group_id as $group) { if (!self::hasKey($group, $key_id)) { $groups_to_add[] = $group; } } unset($group); // Check that there are actually keys to add, because running an insert query // with an empty data array will cause an SQL error if (count($groups_to_add) > 0) { // Add the new keys to the database $data = array(); foreach ($groups_to_add as $group) { $data[] = array("group_id" => $group, "key_id" => $key_id); } unset($group); try { $result = $db->runInsertQueryMulti(self::$struct, $data, $columns = null, $ctrl = null); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 6, 'text' => "DB insert exception", 'data' => $data, 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } // Update the cache if ($result) { foreach ($groups_to_add as $group) { $this->cache["keys"][$group][$key_id] = true; } unset($group); try { $cache_ok = self::saveCache(); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 7, 'text' => "saveCache exception", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } if ($cache_ok) { return $result; } else { return false; } } else { return $result; } } else { return true; } } // CASE 4: Multiple group_id's, multiple keys (all groups get same keys) // ================================================================= if (is_array($group_id) && is_array($key_id)) { // Create an array of "missing keys" that need to be added. Note this algorithm // also eliminates duplicate keys, so we don't have to use array_unique() to avoid // a failed query if duplicate keys are present in $key_id $keys_to_add = array(); foreach ($group_id as $group) { foreach ($key_id as $key) { if (!self::hasKey($group, $key)) { $keys_to_add[$group][] = $key; } } } unset($group, $key); // Check that there are actually keys to add, because running an insert query // with an empty data array will cause an SQL error if (count($keys_to_add) > 0) { // Add the new keys to the database $data = array(); foreach ($keys_to_add as $group => $keys) { foreach ($keys as $key) { $data[] = array("group_id" => $group, "key_id" => $key); } } unset($group, $key, $keys); try { $result = $db->runInsertQueryMulti(self::$struct, $data, $columns = null, $ctrl = null); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 8, 'text' => "DB insert exception", 'data' => $data, 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } // Update the cache if ($result) { foreach ($keys_to_add as $group => $keys) { foreach ($keys as $key) { $this->cache["keys"][$group][$key] = true; } } unset($group, $key, $keys); try { $cache_ok = self::saveCache(); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 1, 'text' => "saveCache exception", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } if ($cache_ok) { return $result; } else { return false; } } else { return $result; } } else { return true; } // ENDOF: if( count($keys_to_add) > 0 ) } // ENDOF: if( is_array($group_id) && is_array($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; } }
/** * Adds one or more users to one or more groups * * @version 1.0 * @since 1.0 * * @param int/array $user_id | Single user_id as int. Multiple user_id's as array of ints. * @param int/array $group_id | Single group id as int. Multiple group ids as array of int. * @return bool | False on failure. True on success. */ public function addToGroup($user_id, $group_id) { global $fox; $db = new FOX_db(); // CASE 1: Single user_id, single group_id // ================================================================= if (!is_array($user_id) && !is_array($group_id)) { // Check if the user is already a member of the group if (self::inGroup($user_id, $group_id)) { return true; } // Get the group's keyring try { $gk = new FOX_uGroupKeyRing(); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 1, 'text' => "FOX_uGroupKeyRing constructor exception", 'data' => array("group_id" => $group_id), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } try { $group_keyring = $gk->getKeys($group_id); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 2, 'text' => "FOX_uGroupKeyRing getKeys exception", 'data' => array("group_id" => $group_id), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } // @@@@@@ BEGIN TRANSACTION @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ if ($db->beginTransaction()) { // Add the user-group pair to the group members table $data = array("user_id" => $user_id, "group_id" => $group_id); try { $group_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)); } // Grant the user the group's keyring if ($group_keyring) { $ks = new FOX_uKeyRing(); try { $keys_ok = $ks->grantKey($user_id, $group_keyring); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 4, 'text' => "FOX_uKeyRing exception", 'data' => array("user_id" => $user_id, "group_keyring" => $group_keyring), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } } else { // Handle groups with no keys in their keyring $keys_ok = true; } // If all operations were successful, commit the transaction if ($group_ok && $keys_ok) { try { $commit_ok = $db->commitTransaction(); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 5, 'text' => "commitTransaction exception", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } // Update the cache if ($commit_ok) { // Load, update, writeback $this->cache[$user_id] = $fox->cache->get("FOX_uGroupMember", $user_id); $this->cache[$user_id]["keys"][$group_id] = true; $cache_ok = $fox->cache->set("FOX_uGroupMember", $user_id, $this->cache[$user_id]); return $cache_ok; } else { return false; } } else { 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)); } return false; } } else { // If we couldn't start a transaction, return false return false; } // @@@@@@ END TRANSACTION @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ } // CASE 2: Single user_id, multiple groups // ================================================================= if (!is_array($user_id) && is_array($group_id)) { // Load all of the user's "to be added" groups into the cache try { self::load($user_id, $group_id); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 7, 'text' => "FOX_uGroupMember load exception", 'data' => array("user_id" => $user_id, "group_id" => $group_id), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } $groups_to_add = array(); // Create an array of all the groups the user needs to be added to foreach ($group_id as $group) { if (!$this->cache[$user_id]["keys"][$group]) { $groups_to_add[] = $group; } } unset($group, $in_cache); // If the user is already a member of all the requested groups, quit if (empty($groups_to_add)) { return true; } // Get combined keyring of groups to add the user to try { $gk = new FOX_uGroupKeyRing(); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 8, 'text' => "FOX_uGroupKeyRing constructor exception", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } try { $keyring = $gk->getKeys($groups_to_add); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 9, 'text' => "FOX_uGroupKeyRing getKeys exception", 'data' => array("groups_to_add" => $groups_to_add), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } // @@@@@@ BEGIN TRANSACTION @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ try { $transaction_started = $db->beginTransaction(); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 10, 'text' => "beginTransaction exception", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } if ($transaction_started) { // Add the user-group pairs to the group members table $data = array(); foreach ($groups_to_add as $group) { $data[] = array("user_id" => $user_id, "group_id" => $group); } unset($group); try { $group_ok = $db->runInsertQueryMulti(self::$struct, $data, $columns = null, $ctrl = null); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 11, 'text' => "DB insert exception", 'data' => $data, 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } // Grant the user the groups' combined keyrings if ($keyring) { $ks = new FOX_uKeyRing(); try { $keys_ok = $ks->grantKey($user_id, $keyring); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 12, 'text' => "FOX_uKeyRing grantKey exception", 'data' => array("user_id" => $user_id, "group_id" => $group_id), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } } else { // Handle none of the groups having any keys on their keyring $keys_ok = true; } // If all operations were successful, commit the transaction if ($group_ok && $keys_ok) { try { $commit_ok = $db->commitTransaction(); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 13, 'text' => "commitTransaction exception", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } // Update the cache if ($commit_ok) { // Load, update, writeback $this->cache[$user_id] = $fox->cache->get("FOX_uGroupMember", $user_id); foreach ($groups_to_add as $group) { $this->cache[$user_id]["keys"][$group] = true; } unset($group); $cache_ok = $fox->cache->set("FOX_uGroupMember", $user_id, $this->cache[$user_id]); return $cache_ok; } else { return false; } } else { try { $db->rollbackTransaction(); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 14, 'text' => "rollbackTransaction exception", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } return false; } } else { // If we couldn't start a transaction, return false return false; } // @@@@@@ END TRANSACTION @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ } // CASE 3: Multiple user_id's, single group // ================================================================= if (is_array($user_id) && !is_array($group_id)) { // Load all of the user's to be added to the group into the cache try { self::load($user_id, $group_id); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 15, 'text' => "FOX_uGroupMember load exception", 'data' => array("user_id" => $user_id, "group_id" => $group_id), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } $users_to_add = array(); // Create an array of "to be added" users that aren't members of the group yet foreach ($user_id as $user) { if (!$this->cache[$user]["keys"][$group_id]) { $users_to_add[] = $user; } } unset($user, $in_cache); // If there are no users that are not already in the group, quit if (empty($users_to_add)) { return true; } // Get the group's keyring try { $gk = new FOX_uGroupKeyRing(); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 16, 'text' => "FOX_uGroupKeyRing constructor exception", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } try { $group_keyring = $gk->getKeys($group_id); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 17, 'text' => "FOX_uGroupKeyRing getKeys exception", 'data' => array("group_id" => $group_id), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } // @@@@@@ BEGIN TRANSACTION @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ try { $transaction_started = $db->beginTransaction(); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 18, 'text' => "beginTransaction exception", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } if ($transaction_started) { // Add the user-group pairs to the groupstore db table $data = array(); foreach ($users_to_add as $user) { $data[] = array("user_id" => $user, "group_id" => $group_id); } unset($user); try { $group_ok = $db->runInsertQueryMulti(self::$struct, $data, $columns = null, $ctrl = null); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 19, 'text' => "DB insert exception", 'data' => $data, 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } // Grant the group's keyring to each user if ($group_keyring) { $ks = new FOX_uKeyRing(); $keys_ok = true; foreach ($users_to_add as $user) { try { $grant_ok = $ks->grantKey($user, $group_keyring); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 20, 'text' => "FOX_uKeyRing grantKey exception", 'data' => array("user" => $user, "group_key_ring" => $group_keyring), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } if (!$grant_ok) { $keys_ok = false; } } unset($user); } else { // Handle the group having no keys on its keyring $keys_ok = true; } // If all operations were successful, commit the transaction if ($group_ok && $keys_ok) { try { $commit_ok = $db->commitTransaction(); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 21, 'text' => "commitTransaction exception", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } // Update the cache if ($commit_ok) { $all_ok = true; foreach ($users_to_add as $user) { // Load, update, writeback $this->cache[$user] = $fox->cache->get("FOX_uGroupMember", $user); $this->cache[$user]["keys"][$group_id] = true; $cache_ok = $fox->cache->set("FOX_uGroupMember", $user, $this->cache[$user]); if (!$cache_ok) { $all_ok = false; } } unset($user); return $all_ok; } else { return false; } } else { try { $db->rollbackTransaction(); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 22, 'text' => "rollbackTransaction exception", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } return false; } } else { // If we couldn't start a transaction, return false return false; } // @@@@@@ END TRANSACTION @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ } // CASE 4: Multiple user_id's, multiple groups // ================================================================= if (is_array($user_id) && is_array($group_id)) { // Load all of the user-group pairs to be added into the cache try { self::load($user_id, $group_id); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 23, 'text' => "FOX_uGroupMember load exception", 'data' => array("user_id" => $user_id, "group_id" => $group_id), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } // Create an array of user-group pairs that need to be added $groups_to_add = array(); foreach ($user_id as $user) { foreach ($group_id as $group) { if (!$this->cache[$user]["keys"][$group]) { $groups_to_add[$user][] = $group; } } } unset($user, $group); // @@@@@@ BEGIN TRANSACTION @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ try { $transaction_started = $db->beginTransaction(); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 24, 'text' => "beginTransaction exception", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } if ($transaction_started) { $all_ok = true; try { $gk = new FOX_uGroupKeyRing(); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 25, 'text' => "FOX_uGroupKeyRing constructor exception", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } foreach ($user_id as $user) { if ($groups_to_add[$user]) { // Add the user-group pairs to the groupstore db table $data = array(); $add_group_ids = array(); foreach ($groups_to_add[$user] as $group) { $data[] = array("user_id" => $user, "group_id" => $group); $add_group_ids[] = $group; } unset($group); try { $groups_ok = $db->runInsertQueryMulti(self::$struct, $data, $columns = null, $ctrl = null); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 26, 'text' => "DB insert exception", 'data' => $data, 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } // Get the groups' combined keyring try { $keyring = $gk->getKeys($add_group_ids); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 27, 'text' => "FOX_uGroupKeyRing getKeys exception", 'data' => array("add_group_ids" => $add_group_ids), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } // Grant the user the groups' combined keyrings if ($keyring) { $ks = new FOX_uKeyRing(); try { $keys_ok = $ks->grantKey($user, $keyring); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 28, 'text' => "FOX_uketRing grantKey exception", 'data' => array("user" => $user, "keyring" => $keyring), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } } else { // Handle none of the groups having any keys on their keyring $keys_ok = true; } if ($groups_ok && $keys_ok) { $user_count++; } else { $all_ok = false; } } } unset($user); // If all operations completed successfully, commit the transaction if ($all_ok && $user_count >= 1) { try { $commit_ok = $db->commitTransaction(); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 29, 'text' => "commitTransaction exception", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } // Update the cache if ($commit_ok) { $all_ok = true; foreach ($user_id as $user) { // Load, update, writeback $this->cache[$user] = $fox->cache->get("FOX_uGroupMember", $user); foreach ($group_id as $group) { $this->cache[$user]["keys"][$group] = true; } $cache_ok = $fox->cache->set("FOX_uGroupMember", $user, $this->cache[$user]); if (!$cache_ok) { $all_ok = false; } } unset($user, $group); return $all_ok; } else { return false; } } elseif ($all_ok && $user_count < 1) { try { $db->rollbackTransaction(); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 30, 'text' => "rollbackTransaction exception", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } return true; } else { try { $db->rollbackTransaction(); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 31, 'text' => "beginTransaction exception", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } return false; } } else { // If we couldn't start a transaction, return false return false; } // @@@@@@ END TRANSACTION @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ } }
/** * Creates a new key, adding it to the database and cache. * * @version 1.0 * @since 1.0 * * @param int/array $user_id | Single user_id as int. Multiple user_id's as array of ints. * @param int/array $key_id | Single key_id as int. Multiple key_id's as array of ints. * @return bool | False on failure. True on success but no db rows changed. Int number of rows changed on success. */ public function grantKey($user_id, $key_id) { global $fox; $db = new FOX_db(); // CASE 1: Single user_id, single key // ================================================================= if (!is_array($user_id) && !is_array($key_id)) { // If the user already has the key, return true to indicate no db rows were changed if (self::hasKey($user_id, $key_id)) { return true; } else { $data = array("user_id" => $user_id, "key_id" => $key_id); try { $rows_changed = $db->runInsertQuery(self::$struct, $data, $columns = null); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 1, 'text' => "DB insert exception", 'data' => array("data" => $data), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } if ($rows_changed) { // Load the user's keyring into the class cache from the persistent cache $this->cache[$user_id] = $fox->cache->get("FOX_uKeyRing", $user_id); // Add the new key $this->cache[$user_id]["keys"][$key_id] = true; // Update the persistent cache $cache_ok = $fox->cache->set("FOX_uKeyRing", $user_id, $this->cache[$user_id]); if ($cache_ok) { return $rows_changed; } else { return false; } } else { return $rows_changed; } } } // CASE 2: Single user_id, multiple keys // ================================================================= if (!is_array($user_id) && is_array($key_id)) { // Load the user's entire keyring into the cache (if not cached already) try { self::getKeys($user_id); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 2, 'text' => "FOX_uKeyRing getKeys exception", 'data' => array("user_id" => $user_id), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } // Create an array of "to be added" keys the user doesn't have. $keys_to_add = array(); foreach ($key_id as $key) { if (!$this->cache[$user_id]["keys"][$key]) { // This test condition gets both missing $keys_to_add[] = $key; // keys (null) and negative keys (false) } } unset($key); if (count($keys_to_add) > 0) { // Add the new keys to the database $data = array(); foreach ($keys_to_add as $key) { $data[] = array("user_id" => $user_id, "key_id" => $key); } unset($key); try { $rows_changed = $db->runInsertQueryMulti(self::$struct, $data, $columns = null, $ctrl = 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)); } // Update the cache if ($rows_changed) { // Load the user's keyring into the class cache from the persistent cache $this->cache[$user_id] = $fox->cache->get("FOX_uKeyRing", $user_id); // Add the new keys to the class cache foreach ($keys_to_add as $key) { $this->cache[$user_id]["keys"][$key] = true; } unset($key); // Update the persistent cache from the class cache $cache_ok = $fox->cache->set("FOX_uKeyRing", $user_id, $this->cache[$user_id]); if ($cache_ok) { return $rows_changed; } else { return false; } } else { return $rows_changed; } } else { return true; } // ENDOF: if( count($keys_to_add) > 0 ) } // CASE 3: Multiple user_id's, single key // ================================================================= if (is_array($user_id) && !is_array($key_id)) { $users_to_add = array(); // Create an array of "to be added" users that don't have the key foreach ($user_id as $user) { try { $has_key = self::hasKey($user, $key_id); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 4, 'text' => "FOX_uKeyRing hasKey exception", 'data' => array("user" => $user, "key_id" => $key_id), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } if (!$has_key) { $users_to_add[] = $user; } } unset($user); if (count($users_to_add) > 0) { // Add the new keys to the database $data = array(); foreach ($users_to_add as $user) { $data[] = array("user_id" => $user, "key_id" => $key_id); } unset($user); try { $rows_changed = $db->runInsertQueryMulti(self::$struct, $data, $columns = null, $ctrl = null); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 5, 'text' => "DB insert exception", 'data' => $data, 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } // Update the cache if ($rows_changed) { $all_ok = true; foreach ($users_to_add as $user) { // Load the user's keyring into the class cache from the persistent cache $this->cache[$user] = $fox->cache->get("FOX_uKeyRing", $user); // Add the new key to the class cache $this->cache[$user]["keys"][$key_id] = true; // Update the persistent cache from the class cache $cache_ok = $fox->cache->set("FOX_uKeyRing", $user, $this->cache[$user]); if (!$cache_ok) { $all_ok = false; } } unset($user); if ($all_ok) { return $rows_changed; } else { return false; } } else { return $rows_changed; } } else { return true; } // ENDOF: if( count($users_to_add) > 0 ) } // CASE 4: Multiple user_id's, multiple keys (all users get same keys) // ================================================================= if (is_array($user_id) && is_array($key_id)) { // Load each user's full keyring into the cache (if not cached already) try { self::getKeysMulti($user_id); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 6, 'text' => "FOX_uKeyRing getKeys exception", 'data' => array("user_id" => $user_id), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } // Create an array of keys that need to be added to each user_id $keys_to_add = array(); foreach ($user_id as $user) { foreach ($key_id as $key) { if (!$this->cache[$user]["keys"][$key]) { // This test condition gets both missing $keys_to_add[$user][] = $key; // keys (null) and negative keys (false) } } unset($key); } unset($user); // Add the new keys to the database if (count($keys_to_add) > 0) { $data = array(); foreach ($keys_to_add as $user => $keys) { foreach ($keys as $key) { $data[] = array("user_id" => $user, "key_id" => $key); } unset($key); } unset($user, $keys); try { $rows_changed = $db->runInsertQueryMulti(self::$struct, $data, $columns = null, $ctrl = null); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 7, 'text' => "DB insert exception", 'data' => $data, 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } // Update the cache if ($rows_changed) { $all_ok = true; foreach ($keys_to_add as $user => $keys) { // Load the user's keyring into the class cache from the persistent cache $this->cache[$user] = $fox->cache->get("FOX_uKeyRing", $user); // Add the new keys to the class cache foreach ($keys as $key) { $this->cache[$user]["keys"][$key] = true; } unset($key); // Update the persistent cache from the class cache $cache_ok = $fox->cache->set("FOX_uKeyRing", $user, $this->cache[$user]); if (!$cache_ok) { $all_ok = false; } } unset($user, $keys); if ($all_ok) { return $rows_changed; } else { return false; } } else { return $rows_changed; } } else { return true; } // ENDOF: if( count($keys_to_add) > 0 ) } }