/** * Returns SQL appropriate for relationship joins and wheres * * @todo add support for multiple relationships and guids. * * @param string $column Column name the GUID should be checked against. * Provide in table.column format. * @param string $relationship Type of the relationship * @param int $relationship_guid Entity GUID to check * @param bool $inverse_relationship Is $relationship_guid the target of the relationship? * * @return mixed * @access private */ public function getEntityRelationshipWhereSql($column, $relationship = null, $relationship_guid = null, $inverse_relationship = false) { if ($relationship == null && $relationship_guid == null) { return ''; } $wheres = array(); $joins = array(); $group_by = ''; if ($inverse_relationship) { $joins[] = "JOIN {$this->db->getTablePrefix()}entity_relationships r on r.guid_one = {$column}"; } else { $joins[] = "JOIN {$this->db->getTablePrefix()}entity_relationships r on r.guid_two = {$column}"; } if ($relationship) { $wheres[] = "r.relationship = '" . $this->db->sanitizeString($relationship) . "'"; } if ($relationship_guid) { if ($inverse_relationship) { $wheres[] = "r.guid_two = '{$relationship_guid}'"; } else { $wheres[] = "r.guid_one = '{$relationship_guid}'"; } } else { // See #5775. Queries that do not include a relationship_guid must be grouped by entity table alias, // otherwise the result set is not unique $group_by = $column; } if ($where_str = implode(' AND ', $wheres)) { return array('wheres' => array("({$where_str})"), 'joins' => $joins, 'group_by' => $group_by); } return ''; }
/** * Get subscription records from the database * * Records are an object with two vars: guid and methods with the latter * being a comma-separated list of subscription relationship names. * * @param int $container_guid The GUID of the subscription target * @return array */ protected function getSubscriptionRecords($container_guid) { $container_guid = $this->db->sanitizeInt($container_guid); // create IN clause $rels = $this->getMethodRelationships(); if (!$rels) { return array(); } array_walk($rels, array($this->db, 'sanitizeString')); $methods_string = "'" . implode("','", $rels) . "'"; $db_prefix = $this->db->getTablePrefix(); $query = "SELECT guid_one AS guid, GROUP_CONCAT(relationship SEPARATOR ',') AS methods\n\t\t\tFROM {$db_prefix}entity_relationships\n\t\t\tWHERE guid_two = {$container_guid} AND\n\t\t\t\t\trelationship IN ({$methods_string}) GROUP BY guid_one"; return $this->db->getData($query); }
/** * {@inheritDoc} */ public function gc($max_lifetime) { $life = time() - $max_lifetime; $query = "DELETE FROM {$this->db->getTablePrefix()}users_sessions WHERE ts < '{$life}'"; return (bool) $this->db->deleteData($query); }
/** * Constructor * * @param Database $db The database * @param EntityTable $entities Entities table */ public function __construct(Database $db, EntityTable $entities) { $this->db = $db; $this->entities = $entities; $this->table = $this->db->getTablePrefix() . 'private_settings'; }
/** * The full name of the metastrings table, including prefix. * * @return string */ public function getTableName() { return $this->db->getTablePrefix() . "metastrings"; }
/** * Returns metadata name and value SQL where for entities. * NB: $names and $values are not paired. Use $pairs for this. * Pairs default to '=' operand. * * This function is reused for annotations because the tables are * exactly the same. * * @param string $e_table Entities table name * @param string $n_table Normalized metastrings table name (Where entities, * values, and names are joined. annotations / metadata) * @param array|null $names Array of names * @param array|null $values Array of values * @param array|null $pairs Array of names / values / operands * @param string $pair_operator ("AND" or "OR") Operator to use to join the where clauses for pairs * @param bool $case_sensitive Case sensitive metadata names? * @param array|null $order_by_metadata Array of names / direction * @param array|null $owner_guids Array of owner GUIDs * * @return false|array False on fail, array('joins', 'wheres') * @access private */ function getEntityMetadataWhereSql($e_table, $n_table, $names = null, $values = null, $pairs = null, $pair_operator = 'AND', $case_sensitive = true, $order_by_metadata = null, $owner_guids = null) { // short circuit if nothing requested // 0 is a valid (if not ill-conceived) metadata name. // 0 is also a valid metadata value for false, null, or 0 // 0 is also a valid(ish) owner_guid if (!$names && $names !== 0 && (!$values && $values !== 0) && (!$pairs && $pairs !== 0) && (!$owner_guids && $owner_guids !== 0) && !$order_by_metadata) { return ''; } // join counter for incremental joins. $i = 1; // binary forces byte-to-byte comparision of strings, making // it case- and diacritical-mark- sensitive. // only supported on values. $binary = $case_sensitive ? ' BINARY ' : ''; $access = _elgg_get_access_where_sql(array('table_alias' => 'n_table')); $return = array('joins' => array(), 'wheres' => array(), 'orders' => array()); // will always want to join these tables if pulling metastrings. $return['joins'][] = "JOIN {$this->db->getTablePrefix()}{$n_table} n_table on\n\t\t\t{$e_table}.guid = n_table.entity_guid"; $wheres = array(); // get names wheres and joins $names_where = ''; if ($names !== null) { if (!is_array($names)) { $names = array($names); } $sanitised_names = array(); foreach ($names as $name) { // normalise to 0. if (!$name) { $name = '0'; } $sanitised_names[] = '\'' . $this->db->sanitizeString($name) . '\''; } if ($names_str = implode(',', $sanitised_names)) { $return['joins'][] = "JOIN {$this->metastringsTable->getTableName()} msn on n_table.name_id = msn.id"; $names_where = "(msn.string IN ({$names_str}))"; } } // get values wheres and joins $values_where = ''; if ($values !== null) { if (!is_array($values)) { $values = array($values); } $sanitised_values = array(); foreach ($values as $value) { // normalize to 0 if (!$value) { $value = 0; } $sanitised_values[] = '\'' . $this->db->sanitizeString($value) . '\''; } if ($values_str = implode(',', $sanitised_values)) { $return['joins'][] = "JOIN {$this->metastringsTable->getTableName()} msv on n_table.value_id = msv.id"; $values_where = "({$binary}msv.string IN ({$values_str}))"; } } if ($names_where && $values_where) { $wheres[] = "({$names_where} AND {$values_where} AND {$access})"; } elseif ($names_where) { $wheres[] = "({$names_where} AND {$access})"; } elseif ($values_where) { $wheres[] = "({$values_where} AND {$access})"; } // add pairs // pairs must be in arrays. if (is_array($pairs)) { // check if this is an array of pairs or just a single pair. if (isset($pairs['name']) || isset($pairs['value'])) { $pairs = array($pairs); } $pair_wheres = array(); // @todo when the pairs are > 3 should probably split the query up to // denormalize the strings table. foreach ($pairs as $index => $pair) { // @todo move this elsewhere? // support shortcut 'n' => 'v' method. if (!is_array($pair)) { $pair = array('name' => $index, 'value' => $pair); } // must have at least a name and value if (!isset($pair['name']) || !isset($pair['value'])) { // @todo should probably return false. continue; } // case sensitivity can be specified per pair. // default to higher level setting. if (isset($pair['case_sensitive'])) { $pair_binary = $pair['case_sensitive'] ? ' BINARY ' : ''; } else { $pair_binary = $binary; } if (isset($pair['operand'])) { $operand = $this->db->sanitizeString($pair['operand']); } else { $operand = ' = '; } // for comparing $trimmed_operand = trim(strtolower($operand)); $access = _elgg_get_access_where_sql(array('table_alias' => "n_table{$i}")); // certain operands can't work well with strings that can be interpreted as numbers // for direct comparisons like IN, =, != we treat them as strings // gt/lt comparisons need to stay unencapsulated because strings '5' > '15' // see https://github.com/Elgg/Elgg/issues/7009 $num_safe_operands = array('>', '<', '>=', '<='); $num_test_operand = trim(strtoupper($operand)); if (is_numeric($pair['value']) && in_array($num_test_operand, $num_safe_operands)) { $value = $this->db->sanitizeString($pair['value']); } else { if (is_bool($pair['value'])) { $value = (int) $pair['value']; } else { if (is_array($pair['value'])) { $values_array = array(); foreach ($pair['value'] as $pair_value) { if (is_numeric($pair_value) && !in_array($num_test_operand, $num_safe_operands)) { $values_array[] = $this->db->sanitizeString($pair_value); } else { $values_array[] = "'" . $this->db->sanitizeString($pair_value) . "'"; } } if ($values_array) { $value = '(' . implode(', ', $values_array) . ')'; } // @todo allow support for non IN operands with array of values. // will have to do more silly joins. $operand = 'IN'; } else { if ($trimmed_operand == 'in') { $value = "({$pair['value']})"; } else { $value = "'" . $this->db->sanitizeString($pair['value']) . "'"; } } } } $name = $this->db->sanitizeString($pair['name']); // @todo The multiple joins are only needed when the operator is AND $return['joins'][] = "JOIN {$this->db->getTablePrefix()}{$n_table} n_table{$i}\n\t\t\t\t\ton {$e_table}.guid = n_table{$i}.entity_guid"; $return['joins'][] = "JOIN {$this->metastringsTable->getTableName()} msn{$i}\n\t\t\t\t\ton n_table{$i}.name_id = msn{$i}.id"; $return['joins'][] = "JOIN {$this->metastringsTable->getTableName()} msv{$i}\n\t\t\t\t\ton n_table{$i}.value_id = msv{$i}.id"; $pair_wheres[] = "(msn{$i}.string = '{$name}' AND {$pair_binary}msv{$i}.string\n\t\t\t\t\t{$operand} {$value} AND {$access})"; $i++; } if ($where = implode(" {$pair_operator} ", $pair_wheres)) { $wheres[] = "({$where})"; } } // add owner_guids if ($owner_guids) { if (is_array($owner_guids)) { $sanitised = array_map('sanitise_int', $owner_guids); $owner_str = implode(',', $sanitised); } else { $owner_str = (int) $owner_guids; } $wheres[] = "(n_table.owner_guid IN ({$owner_str}))"; } if ($where = implode(' AND ', $wheres)) { $return['wheres'][] = "({$where})"; } if (is_array($order_by_metadata)) { if (count($order_by_metadata) > 0 && !isset($order_by_metadata[0])) { // singleton, so fix $order_by_metadata = array($order_by_metadata); } foreach ($order_by_metadata as $order_by) { if (is_array($order_by) && isset($order_by['name'])) { $name = $this->db->sanitizeString($order_by['name']); if (isset($order_by['direction'])) { $direction = $this->db->sanitizeString($order_by['direction']); } else { $direction = 'ASC'; } $return['joins'][] = "JOIN {$this->db->getTablePrefix()}{$n_table} n_table{$i}\n\t\t\t\t\t\ton {$e_table}.guid = n_table{$i}.entity_guid"; $return['joins'][] = "JOIN {$this->metastringsTable->getTableName()} msn{$i}\n\t\t\t\t\t\ton n_table{$i}.name_id = msn{$i}.id"; $return['joins'][] = "JOIN {$this->metastringsTable->getTableName()} msv{$i}\n\t\t\t\t\t\ton n_table{$i}.value_id = msv{$i}.id"; $access = _elgg_get_access_where_sql(array('table_alias' => "n_table{$i}")); $return['wheres'][] = "(msn{$i}.string = '{$name}' AND {$access})"; if (isset($order_by['as']) && $order_by['as'] == 'integer') { $return['orders'][] = "CAST(msv{$i}.string AS SIGNED) {$direction}"; } else { $return['orders'][] = "msv{$i}.string {$direction}"; } $i++; } } } return $return; }
/** * Checks if mutex is locked * * @param string $namespace Namespace to use for the database table * @return bool */ public function isLocked($namespace) { $this->assertNamespace($namespace); return (bool) count($this->db->getData("SHOW TABLES LIKE '{$this->db->getTablePrefix()}{$namespace}_lock'")); }