Source code for file /openid/Auth/OpenID/SQLStore.php
Documentation is available at SQLStore.php
* SQL-backed OpenID stores.
* LICENSE: See the COPYING file included in this distribution.
* @copyright 2005 Janrain, Inc.
* @license http://www.gnu.org/copyleft/lesser.html LGPL
* Require the PEAR DB module because we'll need it for the SQL-based
* stores implemented here. We silence any errors from the inclusion
* because it might not be present, and a user of the SQL stores may
* supply an Auth_OpenID_DatabaseConnection instance that implements
global $__Auth_OpenID_PEAR_AVAILABLE;
$__Auth_OpenID_PEAR_AVAILABLE =
@include_once 'DB.php';
require_once 'Auth/OpenID/Interface.php';
* This is the parent class for the SQL stores, which contains the
* logic common to all of the SQL stores.
* The table names used are determined by the class variables
* settings_table_name, associations_table_name, and
* nonces_table_name. To change the name of the tables used, pass new
* table names into the constructor.
* To create the tables with the proper schema, see the createTables
* This class shouldn't be used directly. Use one of its subclasses
* instead, as those contain the code necessary to use a specific
* database. If you're an OpenID integrator and you'd like to create
* an SQL-driven store that wraps an application's database
* abstraction, be sure to create a subclass of
* {@link Auth_OpenID_DatabaseConnection} that calls the application's
* database abstraction calls. Then, pass an instance of your new
* database connection class to your SQLStore subclass constructor.
* All methods other than the constructor and createTables should be
* considered implementation details.
* This creates a new SQLStore instance. It requires an
* established database connection be given to it, and it allows
* overriding the default table names.
* @param connection $connection This must be an established
* connection to a database of the correct type for the SQLStore
* subclass you're using. This must either be an PEAR DB
* connection handle or an instance of a subclass of
* Auth_OpenID_DatabaseConnection.
* @param string $settings_table This is an optional parameter to
* specify the name of the table used for this store's settings.
* The default value is 'oid_settings'.
* @param associations_table: This is an optional parameter to
* specify the name of the table used for storing associations.
* The default value is 'oid_associations'.
* @param nonces_table: This is an optional parameter to specify
* the name of the table used for storing nonces. The default
$associations_table =
null,
global $__Auth_OpenID_PEAR_AVAILABLE;
$this->settings_table_name =
"oid_settings";
$this->associations_table_name =
"oid_associations";
$this->nonces_table_name =
"oid_nonces";
// Check the connection object type to be sure it's a PEAR
'auth_openid_databaseconnection')))) {
$this->connection =
$connection;
// Be sure to set the fetch mode so the results are keyed on
// column name instead of column index. This is a PEAR
// constant, so only try to use it if PEAR is present. Note
// that Auth_Openid_Databaseconnection instances need not
// implement ::setFetchMode for this reason.
if ($__Auth_OpenID_PEAR_AVAILABLE) {
$this->connection->setFetchMode(DB_FETCHMODE_ASSOC);
$this->settings_table_name =
$settings_table;
if ($associations_table) {
$this->associations_table_name =
$associations_table;
$this->nonces_table_name =
$nonces_table;
$this->max_nonce_age =
6 *
60 *
60;
// Be sure to run the database queries with auto-commit mode
// turned OFF, because we want every function to run in a
// transaction, implicitly. As a rule, methods named with a
// leading underscore will NOT control transaction behavior.
// Callers of these methods will worry about transactions.
$this->connection->autoCommit(false);
// Create an empty SQL strings array.
// Call this method (which should be overridden by subclasses)
// to populate the $this->sql array with SQL strings.
// Verify that all required SQL statements have been set, and
// raise an error if any expected SQL strings were either
list
($missing, $empty) =
$this->_verifySQL();
// Add table names to queries.
$this->connection->query("SELECT * FROM %s LIMIT 0",
* Returns true if $value constitutes a database error; returns
* Converts a query result to a boolean. If the result is a
* database error according to $this->isError(), this returns
* false; otherwise, this returns true.
* This method should be overridden by subclasses. This method is
* called by the constructor to set values in $this->sql, which is
* an array keyed on sql name.
* Resets the store by removing all records from the store's
$this->connection->query(sprintf("DELETE FROM %s",
$this->associations_table_name));
$this->connection->query(sprintf("DELETE FROM %s",
$this->nonces_table_name));
$this->connection->query(sprintf("DELETE FROM %s",
$this->settings_table_name));
$required_sql_keys =
array(
foreach ($required_sql_keys as $key) {
} else if (!$this->sql[$key]) {
return array($missing, $empty);
'value' =>
$this->nonces_table_name,
'keys' =>
array('nonce_table',
'value' =>
$this->associations_table_name,
'keys' =>
array('assoc_table',
'value' =>
$this->settings_table_name,
'keys' =>
array('settings_table',
foreach ($replacements as $item) {
foreach ($this->sql[$k] as $part_key =>
$part_value) {
$this->sql[$k][$part_key] =
sprintf($part_value,
$this->sql[$k] =
sprintf($this->sql[$k], $value);
$this->connection->autoCommit(true);
$this->connection->autoCommit(false);
$r =
$this->connection->query($this->sql['nonce_table']);
if (!$this->tableExists($this->associations_table_name)) {
$r =
$this->connection->query($this->sql['assoc_table']);
$r =
$this->connection->query($this->sql['settings_table']);
return $this->connection->getOne($this->sql['get_auth']);
function _create_auth($str)
return $this->connection->query($this->sql['create_auth'],
$value =
$this->_get_auth();
$this->_create_auth($auth_key_s);
$this->connection->commit();
$fmt =
"Expected %d-byte string for auth key. Got key of length %d";
function _set_assoc($server_url, $handle, $secret, $issued,
return $this->connection->query($this->sql['set_assoc'],
$this->connection->commit();
$this->connection->rollback();
function _get_assoc($server_url, $handle)
$result =
$this->connection->getRow($this->sql['get_assoc'],
array($server_url, $handle));
function _get_assocs($server_url)
$result =
$this->connection->getAll($this->sql['get_assocs'],
if ($this->_get_assoc($server_url, $handle) ==
null) {
$this->sql['remove_assoc'],
array($server_url, $handle)))) {
$this->connection->commit();
$this->connection->rollback();
$assoc =
$this->_get_assoc($server_url, $handle);
$assocs =
$this->_get_assocs($server_url);
if (!$assocs ||
(count($assocs) ==
0)) {
foreach ($assocs as $assoc_row) {
$assoc_row['assoc_type']);
$assoc->secret =
$this->blobDecode($assoc->secret);
if ($assoc->getExpiresIn() ==
0) {
$associations[] =
array($assoc->issued, $assoc);
foreach ($associations as $key =>
$assoc) {
$issued[$key] =
$assoc[0];
$assocs[$key] =
$assoc[1];
// return the most recently issued one.
list
($issued, $assoc) =
$associations[0];
function _add_nonce($nonce, $expires)
$sql =
$this->sql['add_nonce'];
$result =
$this->connection->query($sql, array($nonce, $expires));
if ($this->_add_nonce($nonce, time())) {
$this->connection->commit();
$this->connection->rollback();
function _get_nonce($nonce)
$result =
$this->connection->getRow($this->sql['get_nonce'],
function _remove_nonce($nonce)
$this->connection->query($this->sql['remove_nonce'],
$row =
$this->_get_nonce($nonce);
$timestamp =
$row['expires'];
$nonce_age =
time() -
$timestamp;
if ($nonce_age >
$this->max_nonce_age) {
$this->_remove_nonce($nonce);
$this->connection->commit();
* "Octifies" a binary string by returning a string with escaped
* octal bytes. This is used for preparing binary data for
* PostgreSQL BYTEA fields.
for ($i =
0; $i <
strlen($str); $i++
) {
} else if (ord($ch) ==
0) {
* "Unoctifies" octal-escaped data from PostgreSQL and returns the
* resulting ASCII (possibly binary) string.
// Look to see if the next char is a backslash and
if ($str[$i +
1] !=
"\\") {
$octal_digits =
substr($str, $i +
1, 3);