/** * Creates a new key * * @version 1.0 * @since 1.0 * * @param array $data | one or more arrays, each descrribing a key to create * => ARR @param int '' | Array index * => VAL @param string $tree | tree name for key (max 32 chars) * => VAL @param string $branch | branch name for key (max 32 chars) * => VAL @param string $name | name for key (max 32 chars) * => VAL @param string $descr | admin description for key (max 255 chars) * * @return bool | False on failure. True on success. */ public function createKeyMulti($data) { global $fox; $db = new FOX_db(); // Make sure that none of the keys to be added already exist // ========================================================= $add_keys = array(); foreach ($data 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"]; $descr = $key["descr"]; $add_keys[$tree][$branch][$name]["descr"] = $descr; } unset($key, $tree, $branch, $name); $add_data = array(); foreach ($add_keys as $tree_name => $branches) { foreach ($branches as $branch_name => $key_arrays) { $key_names = array_keys($key_arrays); // The foreach() function provides the full "key_name"=>"value" // pair in $key_arrays, so we need to use array_keys() to extract // the key names $args = array(array("col" => "tree", "op" => "=", "val" => $tree_name), array("col" => "branch", "op" => "=", "val" => $branch_name), array("col" => "name", "op" => "=", "val" => $key_names)); $columns = array("mode" => "include", "col" => array("key_id")); $ctrl = array("format" => "col"); 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 there is no DB entry, we can add the key to our $add_keys array if (!$result) { foreach ($key_arrays as $key_name => $vars) { $add_data[] = array("tree" => $tree_name, "branch" => $branch_name, "name" => $key_name, "descr" => $vars["descr"]); } } else { throw new FOX_exception(array('numeric' => 1, 'text' => "FOX_uKeyType::createKeyMulti - Attempted to create a key that is already in the database.", 'data' => array("tree" => $tree_name, "branch" => $branch_name, "key" => $key_name), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => null)); } } } unset($tree_name, $branches, $branch_name, $key_arrays, $key_names, $key_name, $vars); // Add the new keys to the database // ================================ try { $result = $db->runInsertQueryMulti(self::$struct, $add_data, $columns = null, $ctrl = null); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 1, 'text' => "DB insert exception", 'data' => array("add_data" => $add_date), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } // NOTE: Because we add all keys as a single query, we cannot add their key_id's to the cache // because 1) mySQL only returns an insert ID when the table's primary key is a single auto // increment column, and 2) it only does it for single insert queries. return $result; }
/** * Registers one or more "Page Module" <=> "Target" relationships * * @version 1.0 * @since 1.0 * * @param array $data | Array of row arrays * => ARR @param int '' | Individual row array * => VAL @param string $location | Display location. * => VAL @param int/string $target | Module target. Must be (int) for pages, (string) for all other locations. * => VAL @param string $tab_title | Title for the module's tab (not used for pages). * => VAL @param int $tab_position | Tab position (0-255) (not used for pages). * => VAL @param int $module_id | Page module id. * => VAL @param string $php_class | PHP class for the page module. * * @return int | Exception on failure. Int number of rows changed on success. */ public function addTargetMulti($data) { $db = new FOX_db(); $struct = self::_struct(); $insert_data = array(); // Process each row // =========================================================== foreach ($data as $row) { if (!is_array($row) || empty($row["location"]) || empty($row["target"]) || empty($row["module_id"]) || empty($row["php_class"])) { throw new FOX_exception(array('numeric' => 1, 'text' => "Missing value in data array", 'data' => $row, 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => null)); } if ($row["location"] == 'page') { if (!is_int($row["target"])) { throw new FOX_exception(array('numeric' => 2, 'text' => "Attempted to use non-int value as a page target", 'data' => $row, 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => null)); } $insert_data[] = array("location" => $row["location"], "target" => (int) $row["target"], "module_id" => $row["module_id"], "php_class" => $row["php_class"]); } else { if (empty($row["tab_title"]) || empty($row["tab_position"])) { throw new FOX_exception(array('numeric' => 3, 'text' => "Non-page targets require tab_title and tab_position to be set", 'data' => $row, 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => null)); } if (!is_int($row["tab_position"])) { throw new FOX_exception(array('numeric' => 4, 'text' => "Attempted to use non-int value as tab position", 'data' => $row, 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => null)); } $insert_data[] = array("location" => $row["location"], "target" => (string) $row["target"], "tab_title" => $row["tab_title"], "tab_position" => (int) $row["tab_position"], "module_id" => $row["module_id"], "php_class" => $row["php_class"]); } } unset($row); // Lock the cache // =========================================================== try { $cache_image = self::lockCache(); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 5, 'text' => "Error locking cache", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } // Update the database // =========================================================== $columns = null; $ctrl = null; try { $rows_changed = $db->runInsertQueryMulti($struct, $insert_data, $columns, $ctrl); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 6, 'text' => "Error reading from database", 'data' => array('insert_data' => $insert_data, 'columns' => $columns, 'ctrl' => $ctrl), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } // Rebuild the cache image // =========================================================== foreach ($insert_data as $row) { $row_data = array("module_id" => $row["module_id"], "php_class" => $row["php_class"]); if (array_key_exists("tab_title", $row)) { $row_data["tab_title"] = $row["tab_title"]; } if (array_key_exists("tab_position", $row)) { $row_data["tab_position"] = $row["tab_position"]; } $cache_image["data"][$row["location"]][$row["target"]] = $row_data; } unset($row); // 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' => 7, '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; }
/** * 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) ) }
/** * 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 or replaces a module's entire policy. * * @version 1.0 * @since 1.0 * * @param int $module_id | module_id * * @param array $data | Array of type_id arrays * => ARR @param string $type_id | type_id array * => ARR @param string $branch_id | branch_id array * => ARR @param int $key_id | key_id array * => VAL @param bool/int/float/string/array/obj $ctrl_val | control value * * @return bool | Exception on failure. True on success. */ public function setPolicy($module_id, $data) { $db = new FOX_db(); $struct = $this->_struct(); if (empty($module_id)) { throw new FOX_exception(array('numeric' => 1, 'text' => "Empty or incorrect module_id", 'data' => array("module_id" => $module_id, "data" => $data), 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => null)); } if (empty($data) || !is_array($data)) { throw new FOX_exception(array('numeric' => 2, 'text' => "Empty or malformed data array", 'data' => array("module_id" => $module_id, "data" => $data), 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => null)); } // Lock the module_id's cache page // =========================================================== try { 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)); } // @@@@@@ BEGIN TRANSACTION @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ try { $db->beginTransaction(); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 4, 'text' => "Couldn't initiate transaction", 'data' => array("module_id" => $module_id, "data" => $data), 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child)); } // Clear all entries for the module_id from the db // =========================================================== $args = array(array("col" => "module_id", "op" => "=", "val" => $module_id)); try { $db->runDeleteQuery($struct, $args, $ctrl = null); } catch (FOX_exception $child) { try { $db->rollbackTransaction(); } catch (FOX_exception $child_2) { throw new FOX_exception(array('numeric' => 5, 'text' => "Error while deleting from the database. Error rolling back.", 'data' => array('rollback_exception' => $child_2, "module_id" => $module_id), 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child)); } throw new FOX_exception(array('numeric' => 6, 'text' => "Error while deleting from the database. Successful rollback.", 'data' => array("module_id" => $module_id), 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child)); } // Flatten the heirarchical $data array into an array of row arrays // while calculating the cache flags // ================================================================ $update_cache = array(); $insert_data = array(); foreach ($data as $type_id => $branch_ids) { $update_cache["type_id"][$type_id] = true; foreach ($branch_ids as $branch_id => $key_ids) { $update_cache["branch_id"][$type_id][$branch_id] = true; foreach ($key_ids as $key_id => $ctrl_val) { $update_cache["keys"][$type_id][$branch_id][$key_id] = $ctrl_val; $insert_data[] = array("module_id" => $module_id, "type_id" => $type_id, "branch_id" => $branch_id, "key_id" => $key_id, "ctrl_val" => $ctrl_val); } unset($key_id, $ctrl_val); } unset($branch_id, $key_ids); } unset($type_id, $branch_ids); // Write to db // =========================================================== try { $db->runInsertQueryMulti($struct, $insert_data, $columns = null, $ctrl = null); } catch (FOX_exception $child) { try { $db->rollbackTransaction(); } catch (FOX_exception $child_2) { throw new FOX_exception(array('numeric' => 7, 'text' => "Error while writing to the database. Error rolling back.", 'data' => array('insert_data' => $insert_data, 'rollback_exception' => $child_2), 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child)); } throw new FOX_exception(array('numeric' => 8, 'text' => "Error while writing to the database. Successful rollback.", 'data' => $insert_data, 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child)); } // @@@@@@ END TRANSACTION @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ try { $db->commitTransaction(); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 9, 'text' => "Error commiting transaction to database", 'data' => $insert_data, 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child)); } // 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' => 10, 'text' => "Cache set error", 'data' => array("module_id" => $module_id, "update_data" => $update_cache), 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child)); } // Write the temp class cache to the class cache $this->cache[$module_id] = $update_cache; return true; }
/** * 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 ) } }
/** * Registers ownership of one or more slugs to a FoxFire page module * * @version 1.0 * @since 1.0 * * @param array $data | Array of row arrays * => ARR @param int '' | Individual row array * => VAL @param string $module_type | module type * => VAL @param int $module_id | id of the module * => VAL @param string $php_class | PHP class for the module * => VAL @param int $module_slug | module module_slug * * @return bool | Exception on failure. True on success. */ public function addSlugMulti($data) { $db = new FOX_db(); $struct = self::_struct(); $columns = null; $ctrl = null; try { $db->runInsertQueryMulti($struct, $data, $columns, $ctrl); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 1, 'text' => "Error writing to database", 'data' => array('data' => $data, 'columns' => $columns, 'ctrl' => $ctrl), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } // Fetch the persistent cache image // =================================================== try { $cache_image = self::readCache(); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 2, 'text' => "Cache read error", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } // Rebuild the cache image // =================================================== foreach ($data as $row) { $row_data = array("module_id" => $row["module_id"], "php_class" => $row["php_class"]); $cache_image["data"][$row["module_type"]][$row["module_slug"]] = $row_data; } unset($row, $row_data); // Update the persistent cache // =================================================== try { self::writeCache($cache_image); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 3, 'text' => "Cache write error", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } // Update the class cache $this->cache = $cache_image; return true; }
/** * Creates a new user class * * @version 1.0 * @since 1.0 * * @param array $data | * => VAL @param string $name | Name of this user class * => VAL @param int $is_default | Default class users are placed into when signing-up, if true. * => VAL @param int $transfer_to | Class users are placed in when moved out of this class by the system * => VAL @param int $tag_who | 0 = off, 1 = friends, 2 = all users * => VAL @param int $in_what | 0 = off, 1 = in own items, 2 = in friends items, 3 = in friends^2 items, 4 = in all items * => VAL @param int $tag_self | 0 = off, 1 = in own items, 2 = in friends items, 3 = in friends^2 items, 4 = in all items * => VAL @param int $can_comment | 0 = off, 1 = own items, 2 = friends items, 3 = friends^2 items, 4 = all items * => VAL @param int $can_view | 0 = default, 1 = override friends, 2 = override private * => VAL @param int $ghost | (make user invisible) 0 = off, 1 = from public, 2 = from friends^2, 3 = from friends * @return bool | False on failure. True on success. */ public function addClass($data) { // Trap missing *required* fields. empty() returns true for unset, null, or zero // variables, isset returns true for unset or null variables (but not zero). if (empty($data["name"]) || empty($data["is_default"]) || empty($data["transfer_to"]) || isset($data["tag_who"]) || isset($data["in_what"]) || isset($data["tag_self"]) || isset($data["can_comment"]) || isset($data["can_view"]) || isset($data["ghost"])) { echo "\n Missing required parameter in FOX_userClass::addClass\n"; echo "Data array was: \n"; var_dump($data); die; } $data = array($data); // Must wrap our data in an array because // runInsertQueryMulti can handle multiple inserts at once $db = new FOX_db(); try { $this->id = $db->runInsertQueryMulti(self::$struct, $data, $columns = null, $ctrl = null); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 1, 'text' => "DB insert exception", 'data' => $data, 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } return $this->id; }