<?php
/**
* Storage container for the oauth credentials, both server and consumer side.
* Based on MySQL
*
* @version $Id: OAuthStoreMySQL.php 76 2010-01-27 19:51:17Z brunobg@corollarium.com $
* @author Marc Worrell <marcw@pobox.com>
* @date Nov 16, 2007 4:03:30 PM
*
*
* The MIT License
*
* Copyright (c) 2007-2008 Mediamatic Lab
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
require_once dirname(__FILE__) . '/OAuthStoreAbstract.class.php';
abstract class OAuthStoreSQL extends OAuthStoreAbstract
{
/**
* Maximum delta a timestamp may be off from a previous timestamp.
* Allows multiple consumers with some clock skew to work with the same token.
* Unit is seconds, default max skew is 10 minutes.
*/
protected $max_timestamp_skew = 600;
/**
* Default ttl for request tokens
*/
protected $max_request_token_ttl = 3600;
/**
* Construct the OAuthStoreMySQL.
* In the options you have to supply either:
* - server, username, password and database (for a mysql_connect)
* - conn (for the connection to be used)
*
* @param array options
*/
function __construct ( $options = array() )
{
if (isset($options['conn']))
{
$this->conn = $options['conn'];
}
else
{
if (isset($options['server']))
{
$server = $options['server'];
$username = $options['username'];
if (isset($options['password']))
{
$this->conn = mysql_connect($server, $username, $options['password']);
}
else
{
$this->conn = mysql_connect($server, $username);
}
}
else
{
// Try the default mysql connect
$this->conn = mysql_connect();
}
if ($this->conn === false)
{
throw new OAuthException2('Could not connect to MySQL database: ' . mysql_error());
}
if (isset($options['database']))
{
if (!mysql_select_db($options['database'], $this->conn))
{
$this->sql_errcheck();
}
}
$this->query('set character set utf8');
}
}
/**
* Find stored credentials for the consumer key and token. Used by an OAuth server
* when verifying an OAuth request.
*
* @param string consumer_key
* @param string token
* @param string token_type false, 'request' or 'access'
* @exception OAuthException2 when no secrets where found
* @return array assoc (consumer_secret, token_secret, osr_id, ost_id, user_id)
*/
public function getSecretsForVerify ( $consumer_key, $token, $token_type = 'access' )
{
if ($token_type === false)
{
$rs = $this->query_row_assoc('
SELECT osr_id,
osr_consumer_key as consumer_key,
osr_consumer_secret as consumer_secret
FROM oauth_server_registry
WHERE osr_consumer_key = \'%s\'
AND osr_enabled = 1
',
$consumer_key);
if ($rs)
{
$rs['token'] = false;
$rs['token_secret'] = false;
$rs['user_id'] = false;
$rs['ost_id'] = false;
}
}
else
{
$rs = $this->query_row_assoc('
SELECT osr_id,
ost_id,
ost_usa_id_ref as user_id,
osr_consumer_key as consumer_key,
osr_consumer_secret as consumer_secret,
ost_token as token,
ost_token_secret as token_secret
FROM oauth_server_registry
JOIN oauth_server_token
ON ost_osr_id_ref = osr_id
WHERE ost_token_type = \'%s\'
AND osr_consumer_key = \'%s\'
AND ost_token = \'%s\'
AND osr_enabled = 1
AND ost_token_ttl >= NOW()
',
$token_type, $consumer_key, $token);
}
if (empty($rs))
{
throw new OAuthException2('The consumer_key "'.$consumer_key.'" token "'.$token.'" combination does not exist or is not enabled.');
}
return $rs;
}
/**
* Find the server details for signing a request, always looks for an access token.
* The returned credentials depend on which local user is making the request.
*
* The consumer_key must belong to the user or be public (user id is null)
*
* For signing we need all of the following:
*
* consumer_key consumer key associated with the server
* consumer_secret consumer secret associated with this server
* token access token associated with this server
* token_secret secret for the access token
* signature_methods signing methods supported by the server (array)
*
* @todo filter on token type (we should know how and with what to sign this request, and there might be old access tokens)
* @param string uri uri of the server
* @param int user_id id of the logged on user
* @param string name (optional) name of the token (case sensitive)
* @exception OAuthException2 when no credentials found
* @return array
*/
public function getSecretsForSignature ( $uri, $user_id, $name = '' )
{
// Find a consumer key and token for the given uri
$ps = parse_url($uri);
$host = isset($ps['host']) ? $ps['host'] : 'localhost';
$path = isset($ps['path']) ? $ps['path'] : '';
if (empty($path) || substr($path, -1) != '/')
{
$path .= '/';
}
// The owner of the consumer_key is either the user or nobody (public consumer key)
$secrets = $this->query_row_assoc('
SELECT ocr_consumer_key as consumer_key,
ocr_consumer_secret as consumer_secret,
oct_token as token,
oct_token_secret as token_secret,
ocr_signature_methods as signature_methods
FROM oauth_consumer_registry
JOIN oauth_consumer_token ON oct_ocr_id_ref = ocr_id
WHERE ocr_server_uri_host = \'%s\'
AND ocr_server_uri_path = LEFT(\'%s\', LENGTH(ocr_server_uri_path))
AND (ocr_usa_id_ref = \'%d\' OR ocr_usa_id_ref IS NULL)
AND oct_token_type = \'access\'
AND oct_name = \'%s\'
AND oct_token_ttl >= NOW()
ORDER BY ocr_usa_id_ref DESC, ocr_consumer_secret DESC, LENGTH(ocr_server_uri_path) DESC
LIMIT 0,1
', $host, $path, $user_id, $name
);
if (empty($secrets))
{
throw new OAuthException2('No server tokens available for '.$uri);
}
$secrets['signature_methods'] = explode(',', $secrets['signature_methods']);
return $secrets;
}
/**
* Get the token and token secret we obtained from a server.
*
* @param string consumer_key
* @param string token
* @param string token_type
* @param int user_id the user owning the token
* @param string name optional name for a named token
* @exception OAuthException2 when no credentials found
* @return array
*/
public function getServerTokenSecrets ( $consumer_key, $token, $token_type, $user_id, $name = '' )
{
if ($token_type != 'request' && $token_type != 'access')
{
throw new OAuthException2('Unkown token type "'.$token_type.'", must be either "request" or "access"');
}
// Take the most recent token of the given type
$r = $this->query_row_assoc('
SELECT ocr_consumer_key as consumer_key,
ocr_consumer_secret as consumer_secret,
oct_token as token,
oct_token_secret as token_secret,
oct_name as token_name,
ocr_signature_methods as signature_methods,
ocr_server_uri as server_uri,
ocr_request_token_uri as request_token_uri,
ocr_authorize_uri as authorize_uri,
ocr_access_token_uri as access_token_uri,
IF(oct_token_ttl >= \'9999-12-31\', NULL, UNIX_TIMESTAMP(oct_token_ttl) - UNIX_TIMESTAMP(NOW())) as token_ttl
FROM oauth_consumer_registry
JOIN oauth_consumer_token
ON oct_ocr_id_ref = ocr_id
WHERE ocr_consumer_key = \'%s\'
AND oct_token_type = \'%s\'
AND oct_token = \'%s\'
AND oct_usa_id_ref = %d
AND oct_token_ttl >= NOW()
', $consumer_key, $token_type, $token, $user_id
);
if (empty($r))
{
throw new OAuthException2('Could not find a "'.$token_type.'" token for consumer "'.$consumer_key.'" and user '.$user_id);
}
if (isset($r['signature_methods']) && !empty($r['signature_methods']))
{
$r['signature_methods'] = explode(',',$r['signature_methods']);
}
else
{
$r['signature_methods'] = array();
}
return $r;
}
/**
* Add a request token we obtained from a server.
*
* @todo remove old tokens for this user and this ocr_id
* @param string consumer_key key of the server in the consumer registry
* @param string token_type one of 'request' or 'access'
* @param string token
* @param string token_secret
* @param int user_id the user owning the token
* @param array options extra options, name and token_ttl
* @exception OAuthException2 when server is not known
* @exception OAuthException2 when we received a duplicate token
*/
public function addServerToken ( $consumer_key, $token_type, $token, $token_secret, $user_id, $options = array() )
{
if ($token_type != 'request' && $token_type != 'access')
{
throw new OAuthException2('Unknown token type "'.$token_type.'", must be either "request" or "access"');
}
// Maximum time to live for this token
if (isset($options['token_ttl']) && is_numeric($options['token_ttl']))
{
$ttl = 'DATE_ADD(NOW(), INTERVAL '.intval($options['token_ttl']).' SECOND)';
}
else if ($token_type == 'request')
{
$ttl = 'DATE_ADD(NOW(), INTERVAL '.$this->max_request_token_ttl.' SECOND)';
}
else
{
$ttl = "'9999-12-31'";
}
if (isset($options['server_uri']))
{
$ocr_id = $this->query_one('
SELECT ocr_id
FROM oauth_consumer_registry
WHERE ocr_consumer_key = \'%s\'
AND ocr_usa_id_ref = %d
AND ocr_server_uri = \'%s\'
', $consumer_key, $user_id, $options['server_uri']);
}
else
{
$ocr_id = $this->query_one('
SELECT ocr_id
FROM oauth_consumer_registry
WHERE ocr_consumer_key = \'%s\'
AND ocr_usa_id_ref = %d
', $consumer_key, $user_id);
}
if (empty($ocr_id))
{
throw new OAuthException2('No server associated with consumer_key "'.$consumer_key.'"');
}
// Named tokens, unique per user/consumer key
if (isset($options['name']) && $options['name'] != '')
{
$name = $options['name'];
}
else
{
$name = '';
}
// Delete any old tokens with the same type and name for this user/server combination
$this->query('
DELETE FROM oauth_consumer_token
WHERE oct_ocr_id_ref = %d
AND oct_usa_id_ref = %d
AND oct_token_type = LOWER(\'%s\')
AND oct_name = \'%s\'
',
$ocr_id,
$user_id,
$token_type,
$name);
// Insert the new token
$this->query('
INSERT IGNORE INTO oauth_consumer_token
SET oct_ocr_id_ref = %d,
oct_usa_id_ref = %d,
oct_name = \'%s\',
oct_token = \'%s\',
oct_token_secret= \'%s\',
oct_token_type = LOWER(\'%s\'),
oct_timestamp = NOW(),
oct_token_ttl = '.$ttl.'
',
$ocr_id,
$user_id,
$name,
$token,
$token_secret,
$token_type);
if (!$this->query_affected_rows())
{
throw new OAuthException2('Received duplicate token "'.$token.'" for the same consumer_key "'.$consumer_key.'"');
}
}
/**
* Delete a server key. This removes access to that site.
*
* @param string consumer_key
* @param int user_id user registering this server
* @param boolean user_is_admin
*/
public function deleteServer ( $consumer_key, $user_id, $user_is_admin = false )
{
if ($user_is_admin)
{
$this->query('
DELETE FROM oauth_consumer_registry
WHERE ocr_consumer_key = \'%s\'
AND (ocr_usa_id_ref = %d OR ocr_usa_id_ref IS NULL)
', $consumer_key, $user_id);
}
else
{
$this->query('
DELETE FROM oauth_consumer_registry
WHERE ocr_consumer_key = \'%s\'
AND ocr_usa_id_ref = %d
', $consumer_key, $user_id);
}
}
/**
* Get a server from the consumer registry using the consumer key
*
* @param string consumer_key
* @param int user_id
* @param boolean user_is_admin (optional)
* @exception OAuthException2 when server is not found
* @return array
*/
public function getServer ( $consumer_key, $user_id, $user_is_admin = false )
{
$r = $this->query_row_assoc('
SELECT ocr_id as id,
ocr_usa_id_ref as user_id,
ocr_consumer_key as consumer_key,
ocr_consumer_secret as consumer_secret,
ocr_signature_methods as signature_methods,
ocr_server_uri as server_uri,
ocr_request_token_uri as request_token_uri,
ocr_authorize_uri as authorize_uri,
ocr_access_token_uri as access_token_uri
FROM oauth_consumer_registry
WHERE ocr_consumer_key = \'%s\'
AND (ocr_usa_id_ref = %d OR ocr_usa_id_ref IS NULL)
', $consumer_key, $user_id);
if (empty($r))
{
throw new OAuthException2('No server with consumer_key "'.$consumer_key.'" has been registered (for this user)');
}
if (isset($r['signature_methods']) && !empty($r['signature_methods']))
{
$r['signature_methods'] = explode(',',$r['signature_methods']);
}
else
{
$r['signature_methods'] = array();
}
return $r;
}
/**
* Find the server details that might be used for a request
*
* The consumer_key must belong to the user or be public (user id is null)
*
* @param string uri uri of the server
* @param int user_id id of the logged on user
* @exception OAuthException2 when no credentials found
* @return array
*/
public function getServerForUri ( $uri, $user_id )
{
// Find a consumer key and token for the given uri
$ps = parse_url($uri);
$host = isset($ps['host']) ? $ps['host'] : 'localhost';
$path = isset($ps['path']) ? $ps['path'] : '';
if (empty($path) || substr($path, -1) != '/')
{
$path .= '/';
}
// The owner of the consumer_key is either the user or nobody (public consumer key)
$server = $this->query_row_assoc('
SELECT ocr_id as id,
ocr_usa_id_ref as user_id,
ocr_consumer_key as consumer_key,
ocr_consumer_secret as consumer_secret,
ocr_signature_methods as signature_methods,
ocr_server_uri as server_uri,
ocr_request_token_uri as request_token_uri,
ocr_authorize_uri as authorize_uri,
ocr_access_token_uri as access_token_uri
FROM oauth_consumer_registry
WHERE ocr_server_uri_host = \'%s\'
AND ocr_server_uri_path = LEFT(\'%s\', LENGTH(ocr_server_uri_path))
AND (ocr_usa_id_ref = \'%d\' OR ocr_usa_id_ref IS NULL)
ORDER BY ocr_usa_id_ref DESC, consumer_secret DESC, LENGTH(ocr_server_uri_path) DESC
LIMIT 0,1
', $host, $path, $user_id
);
if (empty($server))
{
throw new OAuthException2('No server available for '.$uri);
}
$server['signature_methods'] = explode(',', $server['signature_methods']);
return $server;
}
/**
* Get a list of all server token this user has access to.
*
* @param int usr_id
* @return array
*/
public function listServerTokens ( $user_id )
{
$ts = $this->query_all_assoc('
SELECT ocr_consumer_key as consumer_key,
ocr_consumer_secret as consumer_secret,
oct_id as token_id,
oct_token as token,
oct_token_secret as token_secret,
oct_usa_id_ref as user_id,
ocr_signature_methods as signature_methods,
ocr_server_uri as server_uri,
ocr_server_uri_host as server_uri_host,
ocr_server_uri_path as server_uri_path,
ocr_request_token_uri as request_token_uri,
ocr_authorize_uri as authorize_uri,
ocr_access_token_uri as access_token_uri,
oct_timestamp as timestamp
FROM oauth_consumer_registry
JOIN oauth_consumer_token
ON oct_ocr_id_ref = ocr_id
WHERE oct_usa_id_ref = %d
AND oct_token_type = \'access\'
AND oct_token_ttl >= NOW()
ORDER BY ocr_server_uri_host, ocr_server_uri_path
', $user_id);
return $ts;
}
/**
* Count how many tokens we have for the given server
*
* @param string consumer_key
* @return int
*/
public function countServerTokens ( $consumer_key )
{
$count = $this->query_one('
SELECT COUNT(oct_id)
FROM oauth_consumer_token
JOIN oauth_consumer_registry
ON oct_ocr_id_ref = ocr_id
WHERE oct_token_type = \'access\'
AND ocr_consumer_key = \'%s\'
AND oct_token_ttl >= NOW()
', $consumer_key);
return $count;
}
/**
* Get a specific server token for the given user
*
* @param string consumer_key
* @param string token
* @param int user_id
* @exception OAuthException2 when no such token found
* @return array
*/
public function getServerToken ( $consumer_key, $token, $user_id )
{
$ts = $this->query_row_assoc('
SELECT ocr_consumer_key as consumer_key,
ocr_consumer_secret as consumer_secret,
oct_token as token,
oct_token_secret as token_secret,
oct_usa_id_ref as usr_id,
ocr_signature_methods as signature_methods,
ocr_server_uri as server_uri,
ocr_server_uri_host as server_uri_host,
ocr_server_uri_path as server_uri_path,
ocr_request_token_uri as request_token_uri,
ocr_authorize_uri as authorize_uri,
ocr_access_token_uri as access_token_uri,
oct_timestamp as timestamp
FROM oauth_consumer_registry
JOIN oauth_consumer_token
ON oct_ocr_id_ref = ocr_id
WHERE ocr_consumer_key = \'%s\'
AND oct_usa_id_ref = %d
AND oct_token_type = \'access\'
AND oct_token = \'%s\'
AND oct_token_ttl >= NOW()
', $consumer_key, $user_id, $token);
if (empty($ts))
{
throw new OAuthException2('No such consumer key ('.$consumer_key.') and token ('.$token.') combination for user "'.$user_id.'"');
}
return $ts;
}
/**
* Delete a token we obtained from a server.
*
* @param string consumer_key
* @param string token
* @param int user_id
* @param boolean user_is_admin
*/
public function deleteServerToken ( $consumer_key, $token, $user_id, $user_is_admin = false )
{
if ($user_is_admin)
{
$this->query('
DELETE oauth_consumer_token
FROM oauth_consumer_token
JOIN oauth_consumer_registry
ON oct_ocr_id_ref = ocr_id
WHERE ocr_consumer_key = \'%s\'
AND oct_token = \'%s\'
', $consumer_key, $token);
}
else
{
$this->query('
DELETE oauth_consumer_token
FROM oauth_consumer_token
JOIN oauth_consumer_registry
ON oct_ocr_id_ref = ocr_id
WHERE ocr_consumer_key = \'%s\'
AND oct_token = \'%s\'
AND oct_usa_id_ref = %d
', $consumer_key, $token, $user_id);
}
}
/**
* Set the ttl of a server access token. This is done when the
* server receives a valid request with a xoauth_token_ttl parameter in it.
*
* @param string consumer_key
* @param string token
* @param int token_ttl
*/
public function setServerTokenTtl ( $consumer_key, $token, $token_ttl )
{
if ($token_ttl <= 0)
{
// Immediate delete when the token is past its ttl
$this->deleteServerToken($consumer_key, $token, 0, true);
}
else
{
// Set maximum time to live for this token
$this->query('
UPDATE oauth_consumer_token, oauth_consumer_registry
SET ost_token_ttl = DATE_ADD(NOW(), INTERVAL %d SECOND)
WHERE ocr_consumer_key = \'%s\'
AND oct_ocr_id_ref = ocr_id
AND oct_token = \'%s\'
', $token_ttl, $consumer_key, $token);
}
}
/**
* Get a list of all consumers from the consumer registry.
* The consumer keys belong to the user or are public (user id is null)
*
* @param string q query term
* @param int user_id
* @return array
*/
public function listServers ( $q = '', $user_id )
{
$q = trim(str_replace('%', '', $q));
$args = array();
if (!empty($q))
{
$where = ' WHERE ( ocr_consumer_key like \'%%%s%%\'
OR ocr_server_uri like \'%%%s%%\'
OR ocr_server_uri_host like \'%%%s%%\'
OR ocr_server_uri_path like \'%%%s%%\')
AND (ocr_usa_id_ref = %d OR ocr_usa_id_ref IS NULL)
';
$args[] = $q;
$args[] = $q;
$args[] = $q;
$args[] = $q;
$args[] = $user_id;
}
else
{
$where = ' WHERE ocr_usa_id_ref = %d OR ocr_usa_id_ref IS NULL';
$args[] = $user_id;
}
$servers = $this->query_all_assoc('
SELECT ocr_id as id,
ocr_usa_id_ref as user_id,
ocr_consumer_key as consumer_key,
ocr_consumer_secret as consumer_secret,
ocr_signature_methods as signature_methods,
ocr_server_uri as server_uri,
ocr_server_uri_host as server_uri_host,
ocr_server_uri_path as server_uri_path,
ocr_request_token_uri as request_token_uri,
ocr_authorize_uri as authorize_uri,
ocr_access_token_uri as access_token_uri
FROM oauth_consumer_registry
'.$where.'
ORDER BY ocr_server_uri_host, ocr_server_uri_path
', $args);
return $servers;
}
/**
* Register or update a server for our site (we will be the consumer)
*
* (This is the registry at the consumers, registering servers ;-) )
*
* @param array server
* @param int user_id user registering this server
* @param boolean user_is_admin
* @exception OAuthException2 when fields are missing or on duplicate consumer_key
* @return consumer_key
*/
public function updateServer ( $server, $user_id, $user_is_admin = false )
{
foreach (array('consumer_key', 'server_uri') as $f)
{
if (empty($server[$f]))
{
throw new OAuthException2('The field "'.$f.'" must be set and non empty');
}
}
if (!empty($server['id']))
{
$exists = $this->query_one('
SELECT ocr_id
FROM oauth_consumer_registry
WHERE ocr_consumer_key = \'%s\'
AND ocr_id <> %d
AND (ocr_usa_id_ref = %d OR ocr_usa_id_ref IS NULL)
', $server['consumer_key'], $server['id'], $user_id);
}
else
{
$exists = $this->query_one('
SELECT ocr_id
FROM oauth_consumer_registry
WHERE ocr_consumer_key = \'%s\'
AND (ocr_usa_id_ref = %d OR ocr_usa_id_ref IS NULL)
', $server['consumer_key'], $user_id);
}
if ($exists)
{
throw new OAuthException2('The server with key "'.$server['consumer_key'].'" has already been registered');
}
$parts = parse_url($server['server_uri']);
$host = (isset($parts['host']) ? $parts['host'] : 'localhost');
$path = (isset($parts['path']) ? $parts['path'] : '/');
if (isset($server['signature_methods']))
{
if (is_array($server['signature_methods']))
{
$server['signature_methods'] = strtoupper(implode(',', $server['signature_methods']));
}
}
else
{
$server['signature_methods'] = '';
}
// When the user is an admin, then the user can update the user_id of this record
if ($user_is_admin && array_key_exists('user_id', $server))
{
if (is_null($server['user_id']))
{
$update_user = ', ocr_usa_id_ref = NULL';
}
else
{
$update_user = ', ocr_usa_id_ref = '.intval($server['user_id']);
}
}
else
{
$update_user = '';
}
if (!empty($server['id']))
{
// Check if the current user can update this server definition
if (!$user_is_admin)
{
$ocr_usa_id_ref = $this->query_one('
SELECT ocr_usa_id_ref
FROM oauth_consumer_registry
WHERE ocr_id = %d
', $server['id']);
if ($ocr_usa_id_ref != $user_id)
{
throw new OAuthException2('The user "'.$user_id.'" is not allowed to update this server');
}
}
// Update the consumer registration
$this->query('
UPDATE oauth_consumer_registry
SET ocr_consumer_key = \'%s\',
ocr_consumer_secret = \'%s\',
ocr_server_uri = \'%s\',
ocr_server_uri_host = \'%s\',
ocr_server_uri_path = \'%s\',
ocr_timestamp = NOW(),
ocr_request_token_uri = \'%s\',
ocr_authorize_uri = \'%s\',
ocr_access_token_uri = \'%s\',
ocr_signature_methods = \'%s\'
'.$update_user.'
WHERE ocr_id = %d
',
$server['consumer_key'],
$server['consumer_secret'],
$server['server_uri'],
strtolower($host),
$path,
isset($server['request_token_uri']) ? $server['request_token_uri'] : '',
isset($server['authorize_uri']) ? $server['authorize_uri'] : '',
isset($server['access_token_uri']) ? $server['access_token_uri'] : '',
$server['signature_methods'],
$server['id']
);
}
else
{
if (empty($update_user))
{
// Per default the user owning the key is the user registering the key
$update_user = ', ocr_usa_id_ref = '.intval($user_id);
}
$this->query('
INSERT INTO oauth_consumer_registry
SET ocr_consumer_key = \'%s\',
ocr_consumer_secret = \'%s\',
ocr_server_uri = \'%s\',
ocr_server_uri_host = \'%s\',
ocr_server_uri_path = \'%s\',
ocr_timestamp = NOW(),
ocr_request_token_uri = \'%s\',
ocr_authorize_uri = \'%s\',
ocr_access_token_uri = \'%s\',
ocr_signature_methods = \'%s\'
'.$update_user,
$server['consumer_key'],
$server['consumer_secret'],
$server['server_uri'],
strtolower($host),
$path,
isset($server['request_token_uri']) ? $server['request_token_uri'] : '',
isset($server['authorize_uri']) ? $server['authorize_uri'] : '',
isset($server['access_token_uri']) ? $server['access_token_uri'] : '',
$server['signature_methods']
);
$ocr_id = $this->query_insert_id();
}
return $server['consumer_key'];
}
/**
* Insert/update a new consumer with this server (we will be the server)
* When this is a new consumer, then also generate the consumer key and secret.
* Never updates the consumer key and secret.
* When the id is set, then the key and secret must correspond to the entry
* being updated.
*
* (This is the registry at the server, registering consumers ;-) )
*
* @param array consumer
* @param int user_id user registering this consumer
* @param boolean user_is_admin
* @return string consumer key
*/
public function updateConsumer ( $consumer, $user_id, $user_is_admin = false )
{
if (!$user_is_admin)
{
foreach (array('requester_name', 'requester_email') as $f)
{
if (empty($consumer[$f]))
{
throw new OAuthException2('The field "'.$f.'" must be set and non empty');
}
}
}
if (!empty($consumer['id']))
{
if (empty($consumer['consumer_key']))
{
throw new OAuthException2('The field "consumer_key" must be set and non empty');
}
if (!$user_is_admin && empty($consumer['consumer_secret']))
{
throw new OAuthException2('The field "consumer_secret" must be set and non empty');
}
// Check if the current user can update this server definition
if (!$user_is_admin)
{
$osr_usa_id_ref = $this->query_one('
SELECT osr_usa_id_ref
FROM oauth_server_registry
WHERE osr_id = %d
', $consumer['id']);
if ($osr_usa_id_ref != $user_id)
{
throw new OAuthException2('The user "'.$user_id.'" is not allowed to update this consumer');
}
}
else
{
// User is an admin, allow a key owner to be changed or key to be shared
if (array_key_exists('user_id',$consumer))
{
if (is_null($consumer['user_id']))
{
$this->query('
UPDATE oauth_server_registry
SET osr_usa_id_ref = NULL
WHERE osr_id = %d
', $consumer['id']);
}
else
{
$this->query('
UPDATE oauth_server_registry
SET osr_usa_id_ref = %d
WHERE osr_id = %d
', $consumer['user_id'], $consumer['id']);
}
}
}
$this->query('
UPDATE oauth_server_registry
SET osr_requester_name = \'%s\',
osr_requester_email = \'%s\',
osr_callback_uri = \'%s\',
osr_application_uri = \'%s\',
osr_application_title = \'%s\',
osr_application_descr = \'%s\',
osr_application_notes = \'%s\',
osr_application_type = \'%s\',
osr_application_commercial = IF(%d,1,0),
osr_timestamp = NOW()
WHERE osr_id = %d
AND osr_consumer_key = \'%s\'
AND osr_consumer_secret = \'%s\'
',
$consumer['requester_name'],
$consumer['requester_email'],
isset($consumer['callback_uri']) ? $consumer['callback_uri'] : '',
isset($consumer['application_uri']) ? $consumer['application_uri'] : '',
isset($consumer['application_title']) ? $consumer['application_title'] : '',
isset($consumer['application_descr']) ? $consumer['application_descr'] : '',
isset($consumer['application_notes']) ? $consumer['application_notes'] : '',
isset($consumer['application_type']) ? $consumer['application_type'] : '',
isset($consumer['application_commercial']) ? $consumer['application_commercial'] : 0,
$consumer['id'],
$consumer['consumer_key'],
$consumer['consumer_secret']
);
$consumer_key = $consumer['consumer_key'];
}
else
{
$consumer_key = $this->generateKey(true);
$consumer_secret= $this->generateKey();
// When the user is an admin, then the user can be forced to something else that the user
if ($user_is_admin && array_key_exists('user_id',$consumer))
{
if (is_null($consumer['user_id']))
{
$owner_id = 'NULL';
}
else
{
$owner_id = intval($consumer['user_id']);
}
}
else
{
// No admin, take the user id as the owner id.
$owner_id = intval($user_id);
}
$this->query('
INSERT INTO oauth_server_registry
SET osr_enabled = 1,
osr_status = \'active\',
osr_usa_id_ref = \'%s\',
osr_consumer_key = \'%s\',
osr_consumer_secret = \'%s\',
osr_requester_name = \'%s\',
osr_requester_email = \'%s\',
osr_callback_uri = \'%s\',
osr_application_uri = \'%s\',
osr_application_title = \'%s\',
osr_application_descr = \'%s\',
osr_application_notes = \'%s\',
osr_application_type = \'%s\',
osr_application_commercial = IF(%d,1,0),
osr_timestamp = NOW(),
osr_issue_date = NOW()
',
$owner_id,
$consumer_key,
$consumer_secret,
$consumer['requester_name'],
$consumer['requester_email'],
isset($consumer['callback_uri']) ? $consumer['callback_uri'] : '',
isset($consumer['application_uri']) ? $consumer['application_uri'] : '',
isset($consumer['application_title']) ? $consumer['application_title'] : '',
isset($consumer['application_descr']) ? $consumer['application_descr'] : '',
isset($consumer['application_notes']) ? $consumer['application_notes'] : '',
isset($consumer['application_type']) ? $consumer['application_type'] : '',
isset($consumer['application_commercial']) ? $consumer['application_commercial'] : 0
);
}
return $consumer_key;
}
/**
* Delete a consumer key. This removes access to our site for all applications using this key.
*
* @param string consumer_key
* @param int user_id user registering this server
* @param boolean user_is_admin
*/
public function deleteConsumer ( $consumer_key, $user_id, $user_is_admin = false )
{
if ($user_is_admin)
{
$this->query('
DELETE FROM oauth_server_registry
WHERE osr_consumer_key = \'%s\'
AND (osr_usa_id_ref = %d OR osr_usa_id_ref IS NULL)
', $consumer_key, $user_id);
}
else
{
$this->query('
DELETE FROM oauth_server_registry
WHERE osr_consumer_key = \'%s\'
AND osr_usa_id_ref = %d
', $consumer_key, $user_id);
}
}
/**
* Fetch a consumer of this server, by consumer_key.
*
* @param string consumer_key
* @param int user_id
* @param boolean user_is_admin (optional)
* @exception OAuthException2 when consumer not found
* @return array
*/
public function getConsumer ( $consumer_key, $user_id, $user_is_admin = false )
{
$consumer = $this->query_row_assoc('
SELECT *
FROM oauth_server_registry
WHERE osr_consumer_key = \'%s\'
', $consumer_key);
if (!is_array($consumer))
{
throw new OAuthException2('No consumer with consumer_key "'.$consumer_key.'"');
}
$c = array();
foreach ($consumer as $key => $value)
{
$c[substr($key, 4)] = $value;
}
$c['user_id'] = $c['usa_id_ref'];
if (!$user_is_admin && !empty($c['user_id']) && $c['user_id'] != $user_id)
{
throw new OAuthException2('No access to the consumer information for consumer_key "'.$consumer_key.'"');
}
return $c;
}
/**
* Fetch the static consumer key for this provider. The user for the static consumer
* key is NULL (no user, shared key). If the key did not exist then the key is created.
*
* @return string
*/
public function getConsumerStatic ()
{
$consumer = $this->query_one('
SELECT osr_consumer_key
FROM oauth_server_registry
WHERE osr_consumer_key LIKE \'sc-%%\'
AND osr_usa_id_ref IS NULL
');
if (empty($consumer))
{
$consumer_key = 'sc-'.$this->generateKey(true);
$this->query('
INSERT INTO oauth_server_registry
SET osr_enabled = 1,
osr_status = \'active\',
osr_usa_id_ref = NULL,
osr_consumer_key = \'%s\',
osr_consumer_secret = \'\',
osr_requester_name = \'\',
osr_requester_email = \'\',
osr_callback_uri = \'\',
osr_application_uri = \'\',
osr_application_title = \'Static shared consumer key\',
osr_application_descr = \'\',
osr_application_notes = \'Static shared consumer key\',
osr_application_type = \'\',
osr_application_commercial = 0,
osr_timestamp = NOW(),
osr_issue_date = NOW()
',
$consumer_key
);
// Just make sure that if the consumer key is truncated that we get the truncated string
$consumer = $this->getConsumerStatic();
}
return $consumer;
}
/**
* Add an unautorized request token to our server.
*
* @param string consumer_key
* @param array options (eg. token_ttl)
* @return array (token, token_secret)
*/
public function addConsumerRequestToken ( $consumer_key, $options = array() )
{
$token = $this->generateKey(true);
$secret = $this->generateKey();
$osr_id = $this->query_one('
SELECT osr_id
FROM oauth_server_registry
WHERE osr_consumer_key = \'%s\'
AND osr_enabled = 1
', $consumer_key);
if (!$osr_id)
{
throw new OAuthException2('No server with consumer_key "'.$consumer_key.'" or consumer_key is disabled');
}
if (isset($options['token_ttl']) && is_numeric($options['token_ttl']))
{
$ttl = intval($options['token_ttl']);
}
else
{
$ttl = $this->max_request_token_ttl;
}
if (!isset($options['oauth_callback'])) {
// 1.0a Compatibility : store callback url associated with request token
$options['oauth_callback']='oob';
}
$this->query('
INSERT INTO oauth_server_token
SET ost_osr_id_ref = %d,
ost_usa_id_ref = 1,
ost_token = \'%s\',
ost_token_secret = \'%s\',
ost_token_type = \'request\',
ost_token_ttl = DATE_ADD(NOW(), INTERVAL %d SECOND),
ost_callback_url = \'%s\'
ON DUPLICATE KEY UPDATE
ost_osr_id_ref = VALUES(ost_osr_id_ref),
ost_usa_id_ref = VALUES(ost_usa_id_ref),
ost_token = VALUES(ost_token),
ost_token_secret = VALUES(ost_token_secret),
ost_token_type = VALUES(ost_token_type),
ost_token_ttl = VALUES(ost_token_ttl),
ost_callback_url = VALUES(ost_callback_url),
ost_timestamp = NOW()
', $osr_id, $token, $secret, $ttl, $options['oauth_callback']);
return array('token'=>$token, 'token_secret'=>$secret, 'token_ttl'=>$ttl);
}
/**
* Fetch the consumer request token, by request token.
*
* @param string token
* @return array token and consumer details
*/
public function getConsumerRequestToken ( $token )
{
$rs = $this->query_row_assoc('
SELECT ost_token as token,
ost_token_secret as token_secret,
osr_consumer_key as consumer_key,
osr_consumer_secret as consumer_secret,
ost_token_type as token_type,
ost_callback_url as callback_url,
osr_application_title as application_title,
osr_application_descr as application_descr,
osr_application_uri as application_uri
FROM oauth_server_token
JOIN oauth_server_registry
ON ost_osr_id_ref = osr_id
WHERE ost_token_type = \'request\'
AND ost_token = \'%s\'
AND ost_token_ttl >= NOW()
', $token);
return $rs;
}
/**
* Delete a consumer token. The token must be a request or authorized token.
*
* @param string token
*/
public function deleteConsumerRequestToken ( $token )
{
$this->query('
DELETE FROM oauth_server_token
WHERE ost_token = \'%s\'
AND ost_token_type = \'request\'
', $token);
}
/**
* Upgrade a request token to be an authorized request token.
*
* @param string token
* @param int user_id user authorizing the token
* @param string referrer_host used to set the referrer host for this token, for user feedback
*/
public function authorizeConsumerRequestToken ( $token, $user_id, $referrer_host = '' )
{
// 1.0a Compatibility : create a token verifier
$verifier = substr(md5(rand()),0,10);
$this->query('
UPDATE oauth_server_token
SET ost_authorized = 1,
ost_usa_id_ref = %d,
ost_timestamp = NOW(),
ost_referrer_host = \'%s\',
ost_verifier = \'%s\'
WHERE ost_token = \'%s\'
AND ost_token_type = \'request\'
', $user_id, $referrer_host, $verifier, $token);
return $verifier;
}
/**
* Count the consumer access tokens for the given consumer.
*
* @param string consumer_key
* @return int
*/
public function countConsumerAccessTokens ( $consumer_key )
{
$count = $this->query_one('
SELECT COUNT(ost_id)
FROM oauth_server_token
JOIN oauth_server_registry
ON ost_osr_id_ref = osr_id
WHERE ost_token_type = \'access\'
AND osr_consumer_key = \'%s\'
AND ost_token_ttl >= NOW()
', $consumer_key);
return $count;
}
/**
* Exchange an authorized request token for new access token.
*
* @param string token
* @param array options options for the token, token_ttl
* @exception OAuthException2 when token could not be exchanged
* @return array (token, token_secret)
*/
public function exchangeConsumerRequestForAccessToken ( $token, $options = array() )
{
$new_token = $this->generateKey(true);
$new_secret = $this->generateKey();
// Maximum time to live for this token
if (isset($options['token_ttl']) && is_numeric($options['token_ttl']))
{
$ttl_sql = 'DATE_ADD(NOW(), INTERVAL '.intval($options['token_ttl']).' SECOND)';
}
else
{
$ttl_sql = "'9999-12-31'";
}
if (isset($options['verifier'])) {
$verifier = $options['verifier'];
// 1.0a Compatibility : check token against oauth_verifier
$this->query('
UPDATE oauth_server_token
SET ost_token = \'%s\',
ost_token_secret = \'%s\',
ost_token_type = \'access\',
ost_timestamp = NOW(),
ost_token_ttl = '.$ttl_sql.'
WHERE ost_token = \'%s\'
AND ost_token_type = \'request\'
AND ost_authorized = 1
AND ost_token_ttl >= NOW()
AND ost_verifier = \'%s\'
', $new_token, $new_secret, $token, $verifier);
} else {
// 1.0
$this->query('
UPDATE oauth_server_token
SET ost_token = \'%s\',
ost_token_secret = \'%s\',
ost_token_type = \'access\',
ost_timestamp = NOW(),
ost_token_ttl = '.$ttl_sql.'
WHERE ost_token = \'%s\'
AND ost_token_type = \'request\'
AND ost_authorized = 1
AND ost_token_ttl >= NOW()
', $new_token, $new_secret, $token);
}
if ($this->query_affected_rows() != 1)
{
throw new OAuthException2('Can\'t exchange request token "'.$token.'" for access token. No such token or not authorized');
}
$ret = array('token' => $new_token, 'token_secret' => $new_secret);
$ttl = $this->query_one('
SELECT IF(ost_token_ttl >= \'9999-12-31\', NULL, UNIX_TIMESTAMP(ost_token_ttl) - UNIX_TIMESTAMP(NOW())) as token_ttl
FROM oauth_server_token
WHERE ost_token = \'%s\'', $new_token);
if (is_numeric($ttl))
{
$ret['token_ttl'] = intval($ttl);
}
return $ret;
}
/**
* Fetch the consumer access token, by access token.
*
* @param string token
* @param int user_id
* @exception OAuthException2 when token is not found
* @return array token and consumer details
*/
public function getConsumerAccessToken ( $token, $user_id )
{
$rs = $this->query_row_assoc('
SELECT ost_token as token,
ost_token_secret as token_secret,
ost_referrer_host as token_referrer_host,
osr_consumer_key as consumer_key,
osr_consumer_secret as consumer_secret,
osr_application_uri as application_uri,
osr_application_title as application_title,
osr_application_descr as application_descr,
osr_callback_uri as callback_uri
FROM oauth_server_token
JOIN oauth_server_registry
ON ost_osr_id_ref = osr_id
WHERE ost_token_type = \'access\'
AND ost_token = \'%s\'
AND ost_usa_id_ref = %d
AND ost_token_ttl >= NOW()
', $token, $user_id);
if (empty($rs))
{
throw new OAuthException2('No server_token "'.$token.'" for user "'.$user_id.'"');
}
return $rs;
}
/**
* Delete a consumer access token.
*
* @param string token
* @param int user_id
* @param boolean user_is_admin
*/
public function deleteConsumerAccessToken ( $token, $user_id, $user_is_admin = false )
{
if ($user_is_admin)
{
$this->query('
DELETE FROM oauth_server_token
WHERE ost_token = \'%s\'
AND ost_token_type = \'access\'
', $token);
}
else
{
$this->query('
DELETE FROM oauth_server_token
WHERE ost_token = \'%s\'
AND ost_token_type = \'access\'
AND ost_usa_id_ref = %d
', $token, $user_id);
}
}
/**
* Set the ttl of a consumer access token. This is done when the
* server receives a valid request with a xoauth_token_ttl parameter in it.
*
* @param string token
* @param int ttl
*/
public function setConsumerAccessTokenTtl ( $token, $token_ttl )
{
if ($token_ttl <= 0)
{
// Immediate delete when the token is past its ttl
$this->deleteConsumerAccessToken($token, 0, true);
}
else
{
// Set maximum time to live for this token
$this->query('
UPDATE oauth_server_token
SET ost_token_ttl = DATE_ADD(NOW(), INTERVAL %d SECOND)
WHERE ost_token = \'%s\'
AND ost_token_type = \'access\'
', $token_ttl, $token);
}
}
/**
* Fetch a list of all consumer keys, secrets etc.
* Returns the public (user_id is null) and the keys owned by the user
*
* @param int user_id
* @return array
*/
public function listConsumers ( $user_id )
{
$rs = $this->query_all_assoc('
SELECT osr_id as id,
osr_usa_id_ref as user_id,
osr_consumer_key as consumer_key,
osr_consumer_secret as consumer_secret,
osr_enabled as enabled,
osr_status as status,
osr_issue_date as issue_date,
osr_application_uri as application_uri,
osr_application_title as application_title,
osr_application_descr as application_descr,
osr_requester_name as requester_name,
osr_requester_email as requester_email,
osr_callback_uri as callback_uri
FROM oauth_server_registry
WHERE (osr_usa_id_ref = %d OR osr_usa_id_ref IS NULL)
ORDER BY osr_application_title
', $user_id);
return $rs;
}
/**
* List of all registered applications. Data returned has not sensitive
* information and therefore is suitable for public displaying.
*
* @param int $begin
* @param int $total
* @return array
*/
public function listConsumerApplications($begin = 0, $total = 25)
{
$rs = $this->query_all_assoc('
SELECT osr_id as id,
osr_enabled as enabled,
osr_status as status,
osr_issue_date as issue_date,
osr_application_uri as application_uri,
osr_application_title as application_title,
osr_application_descr as application_descr
FROM oauth_server_registry
ORDER BY osr_application_title
');
// TODO: pagination
return $rs;
}
/**
* Fetch a list of all consumer tokens accessing the account of the given user.
*
* @param int user_id
* @return array
*/
public function listConsumerTokens ( $user_id )
{
$rs = $this->query_all_assoc('
SELECT osr_consumer_key as consumer_key,
osr_consumer_secret as consumer_secret,
osr_enabled as enabled,
osr_status as status,
osr_application_uri as application_uri,
osr_application_title as application_title,
osr_application_descr as application_descr,
ost_timestamp as timestamp,
ost_token as token,
ost_token_secret as token_secret,
ost_referrer_host as token_referrer_host,
osr_callback_uri as callback_uri
FROM oauth_server_registry
JOIN oauth_server_token
ON ost_osr_id_ref = osr_id
WHERE ost_usa_id_ref = %d
AND ost_token_type = \'access\'
AND ost_token_ttl >= NOW()
ORDER BY osr_application_title
', $user_id);
return $rs;
}
/**
* Check an nonce/timestamp combination. Clears any nonce combinations
* that are older than the one received.
*
* @param string consumer_key
* @param string token
* @param int timestamp
* @param string nonce
* @exception OAuthException2 thrown when the timestamp is not in sequence or nonce is not unique
*/
public function checkServerNonce ( $consumer_key, $token, $timestamp, $nonce )
{
$r = $this->query_row('
SELECT MAX(osn_timestamp), MAX(osn_timestamp) > %d + %d
FROM oauth_server_nonce
WHERE osn_consumer_key = \'%s\'
AND osn_token = \'%s\'
', $timestamp, $this->max_timestamp_skew, $consumer_key, $token);
if (!empty($r) && $r[1])
{
throw new OAuthException2('Timestamp is out of sequence. Request rejected. Got '.$timestamp.' last max is '.$r[0].' allowed skew is '.$this->max_timestamp_skew);
}
// Insert the new combination
$this->query('
INSERT IGNORE INTO oauth_server_nonce
SET osn_consumer_key = \'%s\',
osn_token = \'%s\',
osn_timestamp = %d,
osn_nonce = \'%s\'
', $consumer_key, $token, $timestamp, $nonce);
if ($this->query_affected_rows() == 0)
{
throw new OAuthException2('Duplicate timestamp/nonce combination, possible replay attack. Request rejected.');
}
// Clean up all timestamps older than the one we just received
$this->query('
DELETE FROM oauth_server_nonce
WHERE osn_consumer_key = \'%s\'
AND osn_token = \'%s\'
AND osn_timestamp < %d - %d
', $consumer_key, $token, $timestamp, $this->max_timestamp_skew);
}
/**
* Add an entry to the log table
*
* @param array keys (osr_consumer_key, ost_token, ocr_consumer_key, oct_token)
* @param string received
* @param string sent
* @param string base_string
* @param string notes
* @param int (optional) user_id
*/
public function addLog ( $keys, $received, $sent, $base_string, $notes, $user_id = null )
{
$args = array();
$ps = array();
foreach ($keys as $key => $value)
{
$args[] = $value;
$ps[] = "olg_$key = '%s'";
}
if (!empty($_SERVER['REMOTE_ADDR']))
{
$remote_ip = $_SERVER['REMOTE_ADDR'];
}
else if (!empty($_SERVER['REMOTE_IP']))
{
$remote_ip = $_SERVER['REMOTE_IP'];
}
else
{
$remote_ip = '0.0.0.0';
}
// Build the SQL
$ps[] = "olg_received = '%s'"; $args[] = $this->makeUTF8($received);
$ps[] = "olg_sent = '%s'"; $args[] = $this->makeUTF8($sent);
$ps[] = "olg_base_string= '%s'"; $args[] = $base_string;
$ps[] = "olg_notes = '%s'"; $args[] = $this->makeUTF8($notes);
$ps[] = "olg_usa_id_ref = NULLIF(%d,0)"; $args[] = $user_id;
$ps[] = "olg_remote_ip = IFNULL(INET_ATON('%s'),0)"; $args[] = $remote_ip;
$this->query('INSERT INTO oauth_log SET '.implode(',', $ps), $args);
}
/**
* Get a page of entries from the log. Returns the last 100 records
* matching the options given.
*
* @param array options
* @param int user_id current user
* @return array log records
*/
public function listLog ( $options, $user_id )
{
$where = array();
$args = array();
if (empty($options))
{
$where[] = 'olg_usa_id_ref = %d';
$args[] = $user_id;
}
else
{
foreach ($options as $option => $value)
{
if (strlen($value) > 0)
{
switch ($option)
{
case 'osr_consumer_key':
case 'ocr_consumer_key':
case 'ost_token':
case 'oct_token':
$where[] = 'olg_'.$option.' = \'%s\'';
$args[] = $value;
break;
}
}
}
$where[] = '(olg_usa_id_ref IS NULL OR olg_usa_id_ref = %d)';
$args[] = $user_id;
}
$rs = $this->query_all_assoc('
SELECT olg_id,
olg_osr_consumer_key AS osr_consumer_key,
olg_ost_token AS ost_token,
olg_ocr_consumer_key AS ocr_consumer_key,
olg_oct_token AS oct_token,
olg_usa_id_ref AS user_id,
olg_received AS received,
olg_sent AS sent,
olg_base_string AS base_string,
olg_notes AS notes,
olg_timestamp AS timestamp,
INET_NTOA(olg_remote_ip) AS remote_ip
FROM oauth_log
WHERE '.implode(' AND ', $where).'
ORDER BY olg_id DESC
LIMIT 0,100', $args);
return $rs;
}
/* ** Some simple helper functions for querying the mysql db ** */
/**
* Perform a query, ignore the results
*
* @param string sql
* @param vararg arguments (for sprintf)
*/
abstract protected function query ( $sql );
/**
* Perform a query, ignore the results
*
* @param string sql
* @param vararg arguments (for sprintf)
* @return array
*/
abstract protected function query_all_assoc ( $sql );
/**
* Perform a query, return the first row
*
* @param string sql
* @param vararg arguments (for sprintf)
* @return array
*/
abstract protected function query_row_assoc ( $sql );
/**
* Perform a query, return the first row
*
* @param string sql
* @param vararg arguments (for sprintf)
* @return array
*/
abstract protected function query_row ( $sql );
/**
* Perform a query, return the first column of the first row
*
* @param string sql
* @param vararg arguments (for sprintf)
* @return mixed
*/
abstract protected function query_one ( $sql );
/**
* Return the number of rows affected in the last query
*/
abstract protected function query_affected_rows ();
/**
* Return the id of the last inserted row
*
* @return int
*/
abstract protected function query_insert_id ();
abstract protected function sql_printf ( $args );
abstract protected function sql_escape_string ( $s );
abstract protected function sql_errcheck ( $sql );
}
/* vi:set ts=4 sts=4 sw=4 binary noeol: */
?> |