diff options
author | Jaime Perez Crespo <jaime.perez@uninett.no> | 2016-06-02 12:08:49 +0200 |
---|---|---|
committer | Jaime Perez Crespo <jaime.perez@uninett.no> | 2016-06-02 12:08:49 +0200 |
commit | 8077719905f97ea7997a4fdeb079298b07f41f16 (patch) | |
tree | 429f7193693804b756a7f9c9d5006b901c79a682 /lib/SimpleSAML | |
parent | dbc3cbf0266ba325fe70eabad9e73e14cf0e58ef (diff) | |
download | simplesamlphp-8077719905f97ea7997a4fdeb079298b07f41f16.zip simplesamlphp-8077719905f97ea7997a4fdeb079298b07f41f16.tar.gz simplesamlphp-8077719905f97ea7997a4fdeb079298b07f41f16.tar.bz2 |
Reformat SimpleSAML_Auth_Store and fix phpdoc comments.
Diffstat (limited to 'lib/SimpleSAML')
-rw-r--r-- | lib/SimpleSAML/Store/SQL.php | 667 |
1 files changed, 343 insertions, 324 deletions
diff --git a/lib/SimpleSAML/Store/SQL.php b/lib/SimpleSAML/Store/SQL.php index 534f2ea..41ed260 100644 --- a/lib/SimpleSAML/Store/SQL.php +++ b/lib/SimpleSAML/Store/SQL.php @@ -1,331 +1,350 @@ <?php + /** - * A SQL datastore. + * A data store using a RDBMS to keep the data. * * @package SimpleSAMLphp */ -class SimpleSAML_Store_SQL extends SimpleSAML_Store { - - /** - * The PDO object for our database. - * - * @var PDO - */ - public $pdo; - - - /** - * Our database driver. - * - * @var string - */ - public $driver; - - - /** - * The prefix we should use for our tables. - * - * @var string - */ - public $prefix; - - - /** - * Associative array of table versions. - * - * @var array - */ - private $tableVersions; - - - /** - * Initialize the SQL datastore. - */ - protected function __construct() { - - $config = SimpleSAML_Configuration::getInstance(); - - $dsn = $config->getString('store.sql.dsn'); - $username = $config->getString('store.sql.username', NULL); - $password = $config->getString('store.sql.password', NULL); - $this->prefix = $config->getString('store.sql.prefix', 'simpleSAMLphp'); - - $this->pdo = new PDO($dsn, $username, $password); - $this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); - - $this->driver = $this->pdo->getAttribute(PDO::ATTR_DRIVER_NAME); - - if ($this->driver === 'mysql') { - $this->pdo->exec('SET time_zone = "+00:00"'); - } - - $this->initTableVersionTable(); - $this->initKVTable(); - } - - - /** - * Initialize table-version table. - */ - private function initTableVersionTable() { - - $this->tableVersions = array(); - - try { - $fetchTableVersion = $this->pdo->query('SELECT _name, _version FROM ' . $this->prefix . '_tableVersion'); - } catch (PDOException $e) { - $this->pdo->exec('CREATE TABLE ' . $this->prefix .'_tableVersion (_name VARCHAR(30) NOT NULL UNIQUE, _version INTEGER NOT NULL)'); - return; - } - - while ( ($row = $fetchTableVersion->fetch(PDO::FETCH_ASSOC)) !== FALSE) { - $this->tableVersions[$row['_name']] = (int)$row['_version']; - } - } - - - /** - * Initialize key-value table. - */ - private function initKVTable() { - - if ($this->getTableVersion('kvstore') === 1) { - // Table initialized - return; - } - - $text_t = 'TEXT'; - if ($this->driver === 'mysql') { - // TEXT data type has size constraints that can be hit at some point, so we use LONGTEXT instead - $text_t = 'LONGTEXT'; - } - $query = 'CREATE TABLE ' . $this->prefix . '_kvstore (_type VARCHAR(30) NOT NULL, _key VARCHAR(50) NOT NULL, _value '.$text_t.' NOT NULL, _expire TIMESTAMP, PRIMARY KEY (_key, _type))'; - $this->pdo->exec($query); - - $query = 'CREATE INDEX ' . $this->prefix . '_kvstore_expire ON ' . $this->prefix . '_kvstore (_expire)'; - $this->pdo->exec($query); - - $this->setTableVersion('kvstore', 1); - } - - - /** - * Get table version. - * - * @param string Table name. - * @return int The table version, which is 0 if the table doesn't exist. - */ - public function getTableVersion($name) { - assert('is_string($name)'); - - if (!isset($this->tableVersions[$name])) { - return 0; - } - - return $this->tableVersions[$name]; - } - - - /** - * Set table version. - * - * @param string $name Table name. - * @parav int $version Table version. - */ - public function setTableVersion($name, $version) { - assert('is_string($name)'); - assert('is_int($version)'); - - $this->insertOrUpdate($this->prefix . '_tableVersion', array('_name'), - array('_name' => $name, '_version' => $version)); - $this->tableVersions[$name] = $version; - } - - - /** - * Insert or update into a table. - * - * Since various databases implement different methods for doing this, - * we abstract it away here. - * - * @param string $table The table we should update. - * @param array $key The key columns. - * @param array $data Associative array with columns. - */ - public function insertOrUpdate($table, array $keys, array $data) { - assert('is_string($table)'); - - $colNames = '(' . implode(', ', array_keys($data)) . ')'; - $values = 'VALUES(:' . implode(', :', array_keys($data)) . ')'; - - switch ($this->driver) { - case 'mysql': - $query = 'REPLACE INTO ' . $table . ' ' . $colNames . ' ' . $values; - $query = $this->pdo->prepare($query); - $query->execute($data); - return; - case 'sqlite': - $query = 'INSERT OR REPLACE INTO ' . $table . ' ' . $colNames . ' ' . $values; - $query = $this->pdo->prepare($query); - $query->execute($data); - return; - } - - // Default implementation. Try INSERT, and UPDATE if that fails. - - $insertQuery = 'INSERT INTO ' . $table . ' ' . $colNames . ' ' . $values; - $insertQuery = $this->pdo->prepare($insertQuery); - try { - $insertQuery->execute($data); - return; - } catch (PDOException $e) { - $ecode = (string)$e->getCode(); - switch ($ecode) { - case '23505': // PostgreSQL - break; - default: - SimpleSAML\Logger::error('Error while saving data: ' . $e->getMessage()); - throw $e; - } - } - - $updateCols = array(); - $condCols = array(); - foreach ($data as $col => $value) { - - $tmp = $col . ' = :' . $col; - - if (in_array($col, $keys, TRUE)) { - $condCols[] = $tmp; - } else { - $updateCols[] = $tmp; - } - } - - $updateQuery = 'UPDATE ' . $table . ' SET ' . implode(',', $updateCols) . ' WHERE ' . implode(' AND ', $condCols); - $updateQuery = $this->pdo->prepare($updateQuery); - $updateQuery->execute($data); - } - - - /** - * Clean the key-value table of expired entries. - */ - private function cleanKVStore() { - - SimpleSAML\Logger::debug('store.sql: Cleaning key-value store.'); - - $query = 'DELETE FROM ' . $this->prefix . '_kvstore WHERE _expire < :now'; - $params = array('now' => gmdate('Y-m-d H:i:s')); - - $query = $this->pdo->prepare($query); - $query->execute($params); - } - - - /** - * Retrieve a value from the datastore. - * - * @param string $type The datatype. - * @param string $key The key. - * @return mixed|NULL The value. - */ - public function get($type, $key) { - assert('is_string($type)'); - assert('is_string($key)'); - - if (strlen($key) > 50) { - $key = sha1($key); - } - - $query = 'SELECT _value FROM ' . $this->prefix . '_kvstore WHERE _type = :type AND _key = :key AND (_expire IS NULL OR _expire > :now)'; - $params = array('type' => $type, 'key' => $key, 'now' => gmdate('Y-m-d H:i:s')); - - $query = $this->pdo->prepare($query); - $query->execute($params); - - $row = $query->fetch(PDO::FETCH_ASSOC); - if ($row === FALSE) { - return NULL; - } - - $value = $row['_value']; - if (is_resource($value)) { - $value = stream_get_contents($value); - } - $value = urldecode($value); - $value = unserialize($value); - - if ($value === FALSE) { - return NULL; - } - return $value; - } - - - /** - * Save a value to the datastore. - * - * @param string $type The datatype. - * @param string $key The key. - * @param mixed $value The value. - * @param int|NULL $expire The expiration time (unix timestamp), or NULL if it never expires. - */ - public function set($type, $key, $value, $expire = NULL) { - assert('is_string($type)'); - assert('is_string($key)'); - assert('is_null($expire) || (is_int($expire) && $expire > 2592000)'); - - if (rand(0, 1000) < 10) { - $this->cleanKVStore(); - } - - if (strlen($key) > 50) { - $key = sha1($key); - } - - if ($expire !== NULL) { - $expire = gmdate('Y-m-d H:i:s', $expire); - } - - $value = serialize($value); - $value = rawurlencode($value); - - $data = array( - '_type' => $type, - '_key' => $key, - '_value' => $value, - '_expire' => $expire, - ); - - - $this->insertOrUpdate($this->prefix . '_kvstore', array('_type', '_key'), $data); - } - - - /** - * Delete a value from the datastore. - * - * @param string $type The datatype. - * @param string $key The key. - */ - public function delete($type, $key) { - assert('is_string($type)'); - assert('is_string($key)'); - - if (strlen($key) > 50) { - $key = sha1($key); - } - - $data = array( - '_type' => $type, - '_key' => $key, - ); - - $query = 'DELETE FROM ' . $this->prefix . '_kvstore WHERE _type=:_type AND _key=:_key'; - $query = $this->pdo->prepare($query); - $query->execute($data); - } - +class SimpleSAML_Store_SQL extends SimpleSAML_Store +{ + + /** + * The PDO object for our database. + * + * @var PDO + */ + public $pdo; + + + /** + * Our database driver. + * + * @var string + */ + public $driver; + + + /** + * The prefix we should use for our tables. + * + * @var string + */ + public $prefix; + + + /** + * Associative array of table versions. + * + * @var array + */ + private $tableVersions; + + + /** + * Initialize the SQL data store. + */ + protected function __construct() + { + $config = SimpleSAML_Configuration::getInstance(); + + $dsn = $config->getString('store.sql.dsn'); + $username = $config->getString('store.sql.username', null); + $password = $config->getString('store.sql.password', null); + $this->prefix = $config->getString('store.sql.prefix', 'simpleSAMLphp'); + + $this->pdo = new PDO($dsn, $username, $password); + $this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + + $this->driver = $this->pdo->getAttribute(PDO::ATTR_DRIVER_NAME); + + if ($this->driver === 'mysql') { + $this->pdo->exec('SET time_zone = "+00:00"'); + } + + $this->initTableVersionTable(); + $this->initKVTable(); + } + + + /** + * Initialize the table-version table. + */ + private function initTableVersionTable() + { + $this->tableVersions = array(); + + try { + $fetchTableVersion = $this->pdo->query('SELECT _name, _version FROM '.$this->prefix.'_tableVersion'); + } catch (PDOException $e) { + $this->pdo->exec( + 'CREATE TABLE '.$this->prefix. + '_tableVersion (_name VARCHAR(30) NOT NULL UNIQUE, _version INTEGER NOT NULL)' + ); + return; + } + + while (($row = $fetchTableVersion->fetch(PDO::FETCH_ASSOC)) !== false) { + $this->tableVersions[$row['_name']] = (int) $row['_version']; + } + } + + + /** + * Initialize key-value table. + */ + private function initKVTable() + { + + if ($this->getTableVersion('kvstore') === 1) { + // Table initialized + return; + } + + $text_t = 'TEXT'; + if ($this->driver === 'mysql') { + // TEXT data type has size constraints that can be hit at some point, so we use LONGTEXT instead + $text_t = 'LONGTEXT'; + } + $query = 'CREATE TABLE '.$this->prefix. + '_kvstore (_type VARCHAR(30) NOT NULL, _key VARCHAR(50) NOT NULL, _value '.$text_t. + ' NOT NULL, _expire TIMESTAMP, PRIMARY KEY (_key, _type))'; + $this->pdo->exec($query); + + $query = 'CREATE INDEX '.$this->prefix.'_kvstore_expire ON '.$this->prefix.'_kvstore (_expire)'; + $this->pdo->exec($query); + + $this->setTableVersion('kvstore', 1); + } + + + /** + * Get table version. + * + * @param string $name Table name. + * + * @return int The table version, or 0 if the table doesn't exist. + */ + public function getTableVersion($name) + { + assert('is_string($name)'); + + if (!isset($this->tableVersions[$name])) { + return 0; + } + + return $this->tableVersions[$name]; + } + + + /** + * Set table version. + * + * @param string $name Table name. + * @param int $version Table version. + */ + public function setTableVersion($name, $version) + { + assert('is_string($name)'); + assert('is_int($version)'); + + $this->insertOrUpdate( + $this->prefix.'_tableVersion', + array('_name'), + array('_name' => $name, '_version' => $version) + ); + $this->tableVersions[$name] = $version; + } + + + /** + * Insert or update a key-value in the store. + * + * Since various databases implement different methods for doing this, we abstract it away here. + * + * @param string $table The table we should update. + * @param array $keys The key columns. + * @param array $data Associative array with columns. + */ + public function insertOrUpdate($table, array $keys, array $data) + { + assert('is_string($table)'); + + $colNames = '('.implode(', ', array_keys($data)).')'; + $values = 'VALUES(:'.implode(', :', array_keys($data)).')'; + + switch ($this->driver) { + case 'mysql': + $query = 'REPLACE INTO '.$table.' '.$colNames.' '.$values; + $query = $this->pdo->prepare($query); + $query->execute($data); + return; + case 'sqlite': + $query = 'INSERT OR REPLACE INTO '.$table.' '.$colNames.' '.$values; + $query = $this->pdo->prepare($query); + $query->execute($data); + return; + } + + // Default implementation. Try INSERT, and UPDATE if that fails. + + $insertQuery = 'INSERT INTO '.$table.' '.$colNames.' '.$values; + $insertQuery = $this->pdo->prepare($insertQuery); + try { + $insertQuery->execute($data); + return; + } catch (PDOException $e) { + $ecode = (string) $e->getCode(); + switch ($ecode) { + case '23505': // PostgreSQL + break; + default: + SimpleSAML\Logger::error('Error while saving data: '.$e->getMessage()); + throw $e; + } + } + + $updateCols = array(); + $condCols = array(); + foreach ($data as $col => $value) { + + $tmp = $col.' = :'.$col; + + if (in_array($col, $keys, true)) { + $condCols[] = $tmp; + } else { + $updateCols[] = $tmp; + } + } + + $updateQuery = 'UPDATE '.$table.' SET '.implode(',', $updateCols).' WHERE '.implode(' AND ', $condCols); + $updateQuery = $this->pdo->prepare($updateQuery); + $updateQuery->execute($data); + } + + + /** + * Clean the key-value table of expired entries. + */ + private function cleanKVStore() + { + + SimpleSAML\Logger::debug('store.sql: Cleaning key-value store.'); + + $query = 'DELETE FROM '.$this->prefix.'_kvstore WHERE _expire < :now'; + $params = array('now' => gmdate('Y-m-d H:i:s')); + + $query = $this->pdo->prepare($query); + $query->execute($params); + } + + + /** + * Retrieve a value from the data store. + * + * @param string $type The type of the data. + * @param string $key The key to retrieve. + * + * @return mixed|null The value associated with that key, or null if there's no such key. + */ + public function get($type, $key) + { + assert('is_string($type)'); + assert('is_string($key)'); + + if (strlen($key) > 50) { + $key = sha1($key); + } + + $query = 'SELECT _value FROM '.$this->prefix. + '_kvstore WHERE _type = :type AND _key = :key AND (_expire IS NULL OR _expire > :now)'; + $params = array('type' => $type, 'key' => $key, 'now' => gmdate('Y-m-d H:i:s')); + + $query = $this->pdo->prepare($query); + $query->execute($params); + + $row = $query->fetch(PDO::FETCH_ASSOC); + if ($row === false) { + return null; + } + + $value = $row['_value']; + if (is_resource($value)) { + $value = stream_get_contents($value); + } + $value = urldecode($value); + $value = unserialize($value); + + if ($value === false) { + return null; + } + return $value; + } + + + /** + * Save a value in the data store. + * + * @param string $type The type of the data. + * @param string $key The key to insert. + * @param mixed $value The value itself. + * @param int|null $expire The expiration time (unix timestamp), or null if it never expires. + */ + public function set($type, $key, $value, $expire = null) + { + assert('is_string($type)'); + assert('is_string($key)'); + assert('is_null($expire) || (is_int($expire) && $expire > 2592000)'); + + if (rand(0, 1000) < 10) { + $this->cleanKVStore(); + } + + if (strlen($key) > 50) { + $key = sha1($key); + } + + if ($expire !== null) { + $expire = gmdate('Y-m-d H:i:s', $expire); + } + + $value = serialize($value); + $value = rawurlencode($value); + + $data = array( + '_type' => $type, + '_key' => $key, + '_value' => $value, + '_expire' => $expire, + ); + + + $this->insertOrUpdate($this->prefix.'_kvstore', array('_type', '_key'), $data); + } + + + /** + * Delete an entry from the data store. + * + * @param string $type The type of the data + * @param string $key The key to delete. + */ + public function delete($type, $key) + { + assert('is_string($type)'); + assert('is_string($key)'); + + if (strlen($key) > 50) { + $key = sha1($key); + } + + $data = array( + '_type' => $type, + '_key' => $key, + ); + + $query = 'DELETE FROM '.$this->prefix.'_kvstore WHERE _type=:_type AND _key=:_key'; + $query = $this->pdo->prepare($query); + $query->execute($data); + } } |