code:
<?php

/**
 * The OpenID and Yadis discovery implementation for OpenID 1.2.
 */

require_once "Auth/OpenID.php";
require_once "Auth/OpenID/Parse.php";
require_once "Auth/OpenID/Message.php";
require_once "Auth/Yadis/XRIRes.php";
require_once "Auth/Yadis/Yadis.php";

// XML namespace value
define('Auth_OpenID_XMLNS_1_0', 'http://openid.net/xmlns/1.0');

// Yadis service types
define('Auth_OpenID_TYPE_1_2', 'http://openid.net/signon/1.2');
define('Auth_OpenID_TYPE_1_1', 'http://openid.net/signon/1.1');
define('Auth_OpenID_TYPE_1_0', 'http://openid.net/signon/1.0');
define('Auth_OpenID_TYPE_2_0_IDP', 'http://specs.openid.net/auth/2.0/server');
define('Auth_OpenID_TYPE_2_0', 'http://specs.openid.net/auth/2.0/signon');
define('Auth_OpenID_RP_RETURN_TO_URL_TYPE',
       'http://specs.openid.net/auth/2.0/return_to');

function Auth_OpenID_getOpenIDTypeURIs()
{
    return array(Auth_OpenID_TYPE_2_0_IDP,
                 Auth_OpenID_TYPE_2_0,
                 Auth_OpenID_TYPE_1_2,
                 Auth_OpenID_TYPE_1_1,
                 Auth_OpenID_TYPE_1_0);
}

function Auth_OpenID_getOpenIDConsumerTypeURIs()
{
    return array(Auth_OpenID_RP_RETURN_TO_URL_TYPE);
}

/*
 * Provides a user-readable interpretation of a type uri.
 * Useful for error messages.
 */
function Auth_OpenID_getOpenIDTypeName($type_uri) {
    switch ($type_uri) {
    case Auth_OpenID_TYPE_2_0_IDP:
      return 'OpenID 2.0 IDP';
    case Auth_OpenID_TYPE_2_0:
      return 'OpenID 2.0';
    case Auth_OpenID_TYPE_1_2:
      return 'OpenID 1.2';
    case Auth_OpenID_TYPE_1_1:
      return 'OpenID 1.1';
    case Auth_OpenID_TYPE_1_0:
      return 'OpenID 1.0';
    case Auth_OpenID_RP_RETURN_TO_URL_TYPE:
      return 'OpenID relying party';
    }
}

/**
 * Object representing an OpenID service endpoint.
 */
class Auth_OpenID_ServiceEndpoint {
    function Auth_OpenID_ServiceEndpoint()
    {
        $this->claimed_id = null;
        $this->server_url = null;
        $this->type_uris = array();
        $this->local_id = null;
        $this->canonicalID = null;
        $this->used_yadis = false; // whether this came from an XRDS
        $this->display_identifier = null;
    }

    function getDisplayIdentifier()
    {
        if ($this->display_identifier) {
            return $this->display_identifier;
        }
        if (! $this->claimed_id) {
          return $this->claimed_id;
        }
        $parsed = parse_url($this->claimed_id);
        $scheme = $parsed['scheme'];
        $host = $parsed['host'];
        $path = $parsed['path'];
        if (array_key_exists('query', $parsed)) {
            $query = $parsed['query'];
            $no_frag = "$scheme://$host$path?$query";
        } else {
            $no_frag = "$scheme://$host$path";
        }
        return $no_frag;
    }

    function usesExtension($extension_uri)
    {
        return in_array($extension_uri, $this->type_uris);
    }

    function preferredNamespace()
    {
        if (in_array(Auth_OpenID_TYPE_2_0_IDP, $this->type_uris) ||
            in_array(Auth_OpenID_TYPE_2_0, $this->type_uris)) {
            return Auth_OpenID_OPENID2_NS;
        } else {
            return Auth_OpenID_OPENID1_NS;
        }
    }

    /*
     * Query this endpoint to see if it has any of the given type
     * URIs. This is useful for implementing other endpoint classes
     * that e.g. need to check for the presence of multiple versions
     * of a single protocol.
     *
     * @param $type_uris The URIs that you wish to check
     *
     * @return all types that are in both in type_uris and
     * $this->type_uris
     */
    function matchTypes($type_uris)
    {
        $result = array();
        foreach ($type_uris as $test_uri) {
            if ($this->supportsType($test_uri)) {
                $result[] = $test_uri;
            }
        }

        return $result;
    }

    function supportsType($type_uri)
    {
        // Does this endpoint support this type?
        return ((in_array($type_uri, $this->type_uris)) ||
                (($type_uri == Auth_OpenID_TYPE_2_0) &&
                 $this->isOPIdentifier()));
    }

    function compatibilityMode()
    {
        return $this->preferredNamespace() != Auth_OpenID_OPENID2_NS;
    }

    function isOPIdentifier()
    {
        return in_array(Auth_OpenID_TYPE_2_0_IDP, $this->type_uris);
    }

    static function fromOPEndpointURL($op_endpoint_url)
    {
        // Construct an OP-Identifier OpenIDServiceEndpoint object for
        // a given OP Endpoint URL
        $obj = new Auth_OpenID_ServiceEndpoint();
        $obj->server_url = $op_endpoint_url;
        $obj->type_uris = array(Auth_OpenID_TYPE_2_0_IDP);
        return $obj;
    }

    function parseService($yadis_url, $uri, $type_uris, $service_element)
    {
        // Set the state of this object based on the contents of the
        // service element.  Return true if successful, false if not
        // (if findOPLocalIdentifier returns false).
        $this->type_uris = $type_uris;
        $this->server_url = $uri;
        $this->used_yadis = true;

        if (!$this->isOPIdentifier()) {
            $this->claimed_id = $yadis_url;
            $this->local_id = Auth_OpenID_findOPLocalIdentifier(
                                                    $service_element,
                                                    $this->type_uris);
            if ($this->local_id === false) {
                return false;
            }
        }

        return true;
    }

    function getLocalID()
    {
        // Return the identifier that should be sent as the
        // openid.identity_url parameter to the server.
        if ($this->local_id === null && $this->canonicalID === null) {
            return $this->claimed_id;
        } else {
            if ($this->local_id) {
                return $this->local_id;
            } else {
                return $this->canonicalID;
            }
        }
    }

    /*
     * Parse the given document as XRDS looking for OpenID consumer services.
     *
     * @return array of Auth_OpenID_ServiceEndpoint or null if the
     * document cannot be parsed.
     */
    function consumerFromXRDS($uri, $xrds_text)
    {
        $xrds =& Auth_Yadis_XRDS::parseXRDS($xrds_text);

        if ($xrds) {
            $yadis_services =
              $xrds->services(array('filter_MatchesAnyOpenIDConsumerType'));
            return Auth_OpenID_makeOpenIDEndpoints($uri, $yadis_services);
        }

        return null;
    }

    /*
     * Parse the given document as XRDS looking for OpenID services.
     *
     * @return array of Auth_OpenID_ServiceEndpoint or null if the
     * document cannot be parsed.
     */
    static function fromXRDS($uri, $xrds_text)
    {
        $xrds = Auth_Yadis_XRDS::parseXRDS($xrds_text);

        if ($xrds) {
            $yadis_services =
              $xrds->services(array('filter_MatchesAnyOpenIDType'));
            return Auth_OpenID_makeOpenIDEndpoints($uri, $yadis_services);
        }

        return null;
    }

    /*
     * Create endpoints from a DiscoveryResult.
     *
     * @param discoveryResult Auth_Yadis_DiscoveryResult
     * @return array of Auth_OpenID_ServiceEndpoint or null if
     * endpoints cannot be created.
     */
    static function fromDiscoveryResult($discoveryResult)
    {
        if ($discoveryResult->isXRDS()) {
            return Auth_OpenID_ServiceEndpoint::fromXRDS(
                                     $discoveryResult->normalized_uri,
                                     $discoveryResult->response_text);
        } else {
            return Auth_OpenID_ServiceEndpoint::fromHTML(
                                     $discoveryResult->normalized_uri,
                                     $discoveryResult->response_text);
        }
    }

    static function fromHTML($uri, $html)
    {
        $discovery_types = array(
                                 array(Auth_OpenID_TYPE_2_0,
                                       'openid2.provider', 'openid2.local_id'),
                                 array(Auth_OpenID_TYPE_1_1,
                                       'openid.server', 'openid.delegate')
                                 );

        $services = array();

        foreach ($discovery_types as $triple) {
            list($type_uri, $server_rel, $delegate_rel) = $triple;

            $urls = Auth_OpenID_legacy_discover($html, $server_rel,
                                                $delegate_rel);

            if ($urls === false) {
                continue;
            }

            list($delegate_url, $server_url) = $urls;

            $service = new Auth_OpenID_ServiceEndpoint();
            $service->claimed_id = $uri;
            $service->local_id = $delegate_url;
            $service->server_url = $server_url;
            $service->type_uris = array($type_uri);

            $services[] = $service;
        }

        return $services;
    }

    function copy()
    {
        $x = new Auth_OpenID_ServiceEndpoint();

        $x->claimed_id = $this->claimed_id;
        $x->server_url = $this->server_url;
        $x->type_uris = $this->type_uris;
        $x->local_id = $this->local_id;
        $x->canonicalID = $this->canonicalID;
        $x->used_yadis = $this->used_yadis;

        return $x;
    }
}

function Auth_OpenID_findOPLocalIdentifier($service, $type_uris)
{
    // Extract a openid:Delegate value from a Yadis Service element.
    // If no delegate is found, returns null.  Returns false on
    // discovery failure (when multiple delegate/localID tags have
    // different values).

    $service->parser->registerNamespace('openid',
                                        Auth_OpenID_XMLNS_1_0);

    $service->parser->registerNamespace('xrd',
                                        Auth_Yadis_XMLNS_XRD_2_0);

    $parser = $service->parser;

    $permitted_tags = array();

    if (in_array(Auth_OpenID_TYPE_1_1, $type_uris) ||
        in_array(Auth_OpenID_TYPE_1_0, $type_uris)) {
        $permitted_tags[] = 'openid:Delegate';
    }

    if (in_array(Auth_OpenID_TYPE_2_0, $type_uris)) {
        $permitted_tags[] = 'xrd:LocalID';
    }

    $local_id = null;

    foreach ($permitted_tags as $tag_name) {
        $tags = $service->getElements($tag_name);

        foreach ($tags as $tag) {
            $content = $parser->content($tag);

            if ($local_id === null) {
                $local_id = $content;
            } else if ($local_id != $content) {
                return false;
            }
        }
    }

    return $local_id;
}

function filter_MatchesAnyOpenIDType($service)
{
    $uris = $service->getTypes();

    foreach ($uris as $uri) {
        if (in_array($uri, Auth_OpenID_getOpenIDTypeURIs())) {
            return true;
        }
    }

    return false;
}

function filter_MatchesAnyOpenIDConsumerType(&$service)
{
    $uris = $service->getTypes();

    foreach ($uris as $uri) {
        if (in_array($uri, Auth_OpenID_getOpenIDConsumerTypeURIs())) {
            return true;
        }
    }

    return false;
}

function Auth_OpenID_bestMatchingService($service, $preferred_types)
{
    // Return the index of the first matching type, or something
    // higher if no type matches.
    //
    // This provides an ordering in which service elements that
    // contain a type that comes earlier in the preferred types list
    // come before service elements that come later. If a service
    // element has more than one type, the most preferred one wins.

    foreach ($preferred_types as $index => $typ) {
        if (in_array($typ, $service->type_uris)) {
            return $index;
        }
    }

    return count($preferred_types);
}

function Auth_OpenID_arrangeByType($service_list, $preferred_types)
{
    // Rearrange service_list in a new list so services are ordered by
    // types listed in preferred_types.  Return the new list.

    // Build a list with the service elements in tuples whose
    // comparison will prefer the one with the best matching service
    $prio_services = array();
    foreach ($service_list as $index => $service) {
        $prio_services[] = array(Auth_OpenID_bestMatchingService($service,
                                                        $preferred_types),
                                 $index, $service);
    }

    sort($prio_services);

    // Now that the services are sorted by priority, remove the sort
    // keys from the list.
    foreach ($prio_services as $index => $s) {
        $prio_services[$index] = $prio_services[$index][2];
    }

    return $prio_services;
}

// Extract OP Identifier services.  If none found, return the rest,
// sorted with most preferred first according to
// OpenIDServiceEndpoint.openid_type_uris.
//
// openid_services is a list of OpenIDServiceEndpoint objects.
//
// Returns a list of OpenIDServiceEndpoint objects."""
function Auth_OpenID_getOPOrUserServices($openid_services)
{
    $op_services = Auth_OpenID_arrangeByType($openid_services,
                                     array(Auth_OpenID_TYPE_2_0_IDP));

    $openid_services = Auth_OpenID_arrangeByType($openid_services,
                                     Auth_OpenID_getOpenIDTypeURIs());

    if ($op_services) {
        return $op_services;
    } else {
        return $openid_services;
    }
}

function Auth_OpenID_makeOpenIDEndpoints($uri, $yadis_services)
{
    $s = array();

    if (!$yadis_services) {
        return $s;
    }

    foreach ($yadis_services as $service) {
        $type_uris = $service->getTypes();
        $uris = $service->getURIs();

        // If any Type URIs match and there is an endpoint URI
        // specified, then this is an OpenID endpoint
        if ($type_uris &&
            $uris) {
            foreach ($uris as $service_uri) {
                $openid_endpoint = new Auth_OpenID_ServiceEndpoint();
                if ($openid_endpoint->parseService($uri,
                                                   $service_uri,
                                                   $type_uris,
                                                   $service)) {
                    $s[] = $openid_endpoint;
                }
            }
        }
    }

    return $s;
}

function Auth_OpenID_discoverWithYadis($uri, $fetcher,
              $endpoint_filter='Auth_OpenID_getOPOrUserServices',
              $discover_function=null)
{
    // Discover OpenID services for a URI. Tries Yadis and falls back
    // on old-style <link rel='...'> discovery if Yadis fails.

    // Might raise a yadis.discover.DiscoveryFailure if no document
    // came back for that URI at all.  I don't think falling back to
    // OpenID 1.0 discovery on the same URL will help, so don't bother
    // to catch it.
    if ($discover_function === null) {
        $discover_function = array('Auth_Yadis_Yadis', 'discover');
    }

    $openid_services = array();

    $response = call_user_func_array($discover_function,
                                     array($uri, $fetcher));

    $yadis_url = $response->normalized_uri;
    $yadis_services = array();

    if ($response->isFailure() && !$response->isXRDS()) {
        return array($uri, array());
    }

    $openid_services = Auth_OpenID_ServiceEndpoint::fromXRDS(
                                         $yadis_url,
                                         $response->response_text);

    if (!$openid_services) {
        if ($response->isXRDS()) {
            return Auth_OpenID_discoverWithoutYadis($uri,
                                                    $fetcher);
        }

        // Try to parse the response as HTML to get OpenID 1.0/1.1
        // <link rel="...">
        $openid_services = Auth_OpenID_ServiceEndpoint::fromHTML(
                                        $yadis_url,
                                        $response->response_text);
    }

    $openid_services = call_user_func_array($endpoint_filter,
                                            array($openid_services));

    return array($yadis_url, $openid_services);
}

function Auth_OpenID_discoverURI($uri, $fetcher)
{
    $uri = Auth_OpenID::normalizeUrl($uri);
    return Auth_OpenID_discoverWithYadis($uri, $fetcher);
}

function Auth_OpenID_discoverWithoutYadis($uri, $fetcher)
{
    $http_resp = @$fetcher->get($uri);

    if ($http_resp->status != 200 and $http_resp->status != 206) {
        return array($uri, array());
    }

    $identity_url = $http_resp->final_url;

    // Try to parse the response as HTML to get OpenID 1.0/1.1 <link
    // rel="...">
    $openid_services = Auth_OpenID_ServiceEndpoint::fromHTML(
                                           $identity_url,
                                           $http_resp->body);

    return array($identity_url, $openid_services);
}

function Auth_OpenID_discoverXRI($iname, $fetcher)
{
    $resolver = new Auth_Yadis_ProxyResolver($fetcher);
    list($canonicalID, $yadis_services) =
        $resolver->query($iname,
                         Auth_OpenID_getOpenIDTypeURIs(),
                         array('filter_MatchesAnyOpenIDType'));

    $openid_services = Auth_OpenID_makeOpenIDEndpoints($iname,
                                                       $yadis_services);

    $openid_services = Auth_OpenID_getOPOrUserServices($openid_services);

    for ($i = 0; $i < count($openid_services); $i++) {
        $openid_services[$i]->canonicalID = $canonicalID;
        $openid_services[$i]->claimed_id = $canonicalID;
        $openid_services[$i]->display_identifier = $iname;
    }

    // FIXME: returned xri should probably be in some normal form
    return array($iname, $openid_services);
}

function Auth_OpenID_discover($uri, $fetcher)
{
    // If the fetcher (i.e., PHP) doesn't support SSL, we can't do
    // discovery on an HTTPS URL.
    if ($fetcher->isHTTPS($uri) && !$fetcher->supportsSSL()) {
        return array($uri, array());
    }

    if (Auth_Yadis_identifierScheme($uri) == 'XRI') {
        $result = Auth_OpenID_discoverXRI($uri, $fetcher);
    } else {
        $result = Auth_OpenID_discoverURI($uri, $fetcher);
    }

    // If the fetcher doesn't support SSL, we can't interact with
    // HTTPS server URLs; remove those endpoints from the list.
    if (!$fetcher->supportsSSL()) {
        $http_endpoints = array();
        list($new_uri, $endpoints) = $result;

        foreach ($endpoints as $e) {
            if (!$fetcher->isHTTPS($e->server_url)) {
                $http_endpoints[] = $e;
            }
        }

        $result = array($new_uri, $http_endpoints);
    }

    return $result;
}


code:
<?php

/**
 * This file supplies a dumb store backend for OpenID servers and
 * consumers.
 *
 * PHP versions 4 and 5
 *
 * LICENSE: See the COPYING file included in this distribution.
 *
 * @package OpenID
 * @author JanRain, Inc. <openid@janrain.com>
 * @copyright 2005-2008 Janrain, Inc.
 * @license http://www.apache.org/licenses/LICENSE-2.0 Apache
 */

/**
 * Import the interface for creating a new store class.
 */
require_once 'Auth/OpenID/Interface.php';
require_once 'Auth/OpenID/HMAC.php';

/**
 * This is a store for use in the worst case, when you have no way of
 * saving state on the consumer site. Using this store makes the
 * consumer vulnerable to replay attacks, as it's unable to use
 * nonces. Avoid using this store if it is at all possible.
 *
 * Most of the methods of this class are implementation details.
 * Users of this class need to worry only about the constructor.
 *
 * @package OpenID
 */
class Auth_OpenID_DumbStore extends Auth_OpenID_OpenIDStore {

    /**
     * Creates a new {@link Auth_OpenID_DumbStore} instance. For the security
     * of the tokens generated by the library, this class attempts to
     * at least have a secure implementation of getAuthKey.
     *
     * When you create an instance of this class, pass in a secret
     * phrase. The phrase is hashed with sha1 to make it the correct
     * length and form for an auth key. That allows you to use a long
     * string as the secret phrase, which means you can make it very
     * difficult to guess.
     *
     * Each {@link Auth_OpenID_DumbStore} instance that is created for use by
     * your consumer site needs to use the same $secret_phrase.
     *
     * @param string secret_phrase The phrase used to create the auth
     * key returned by getAuthKey
     */
    function Auth_OpenID_DumbStore($secret_phrase)
    {
        $this->auth_key = Auth_OpenID_SHA1($secret_phrase);
    }

    /**
     * This implementation does nothing.
     */
    function storeAssociation($server_url, $association)
    {
    }

    /**
     * This implementation always returns null.
     */
    function getAssociation($server_url, $handle = null)
    {
        return null;
    }

    /**
     * This implementation always returns false.
     */
    function removeAssociation($server_url, $handle)
    {
        return false;
    }

    /**
     * In a system truly limited to dumb mode, nonces must all be
     * accepted. This therefore always returns true, which makes
     * replay attacks feasible.
     */
    function useNonce($server_url, $timestamp, $salt)
    {
        return true;
    }

    /**
     * This method returns the auth key generated by the constructor.
     */
    function getAuthKey()
    {
        return $this->auth_key;
    }
}

repo_name: ksuudilla/gnu

license: mit


code:
<?php

/**
 * An interface for OpenID extensions.
 *
 * @package OpenID
 */

/**
 * Require the Message implementation.
 */
require_once 'Auth/OpenID/Message.php';

/**
 * A base class for accessing extension request and response data for
 * the OpenID 2 protocol.
 *
 * @package OpenID
 */
class Auth_OpenID_Extension {
    /**
     * ns_uri: The namespace to which to add the arguments for this
     * extension
     */
    var $ns_uri = null;
    var $ns_alias = null;

    /**
     * Get the string arguments that should be added to an OpenID
     * message for this extension.
     */
    function getExtensionArgs()
    {
        return null;
    }

    /**
     * Add the arguments from this extension to the provided message.
     *
     * Returns the message with the extension arguments added.
     */
    function toMessage($message, $request = null)
    {
        $implicit = $message->isOpenID1();
        $added = $message->namespaces->addAlias($this->ns_uri,
                                                $this->ns_alias,
                                                $implicit);

        if ($added === null) {
            if ($message->namespaces->getAlias($this->ns_uri) !=
                $this->ns_alias) {
                return null;
            }
        }

        if ($request !== null) {
            $message->updateArgs($this->ns_uri,
                                 $this->getExtensionArgs($request));
        } else {
            $message->updateArgs($this->ns_uri,
                                 $this->getExtensionArgs());
        }
        return $message;
    }
}


code:
<?php

/**
 * This file supplies a Memcached store backend for OpenID servers and
 * consumers.
 *
 * PHP versions 4 and 5
 *
 * LICENSE: See the COPYING file included in this distribution.
 *
 * @package OpenID
 * @author JanRain, Inc. <openid@janrain.com>
 * @copyright 2005-2008 Janrain, Inc.
 * @license http://www.apache.org/licenses/LICENSE-2.0 Apache
 */

/**
 * Require base class for creating a new interface.
 */
require_once 'Auth/OpenID.php';
require_once 'Auth/OpenID/Interface.php';
require_once 'Auth/OpenID/HMAC.php';
require_once 'Auth/OpenID/Nonce.php';

/**
 * This is a filesystem-based store for OpenID associations and
 * nonces.  This store should be safe for use in concurrent systems on
 * both windows and unix (excluding NFS filesystems).  There are a
 * couple race conditions in the system, but those failure cases have
 * been set up in such a way that the worst-case behavior is someone
 * having to try to log in a second time.
 *
 * Most of the methods of this class are implementation details.
 * People wishing to just use this store need only pay attention to
 * the constructor.
 *
 * @package OpenID
 */
class Auth_OpenID_FileStore extends Auth_OpenID_OpenIDStore {

    /**
     * Initializes a new {@link Auth_OpenID_FileStore}.  This
     * initializes the nonce and association directories, which are
     * subdirectories of the directory passed in.
     *
     * @param string $directory This is the directory to put the store
     * directories in.
     */
    function Auth_OpenID_FileStore($directory)
    {
        if (!Auth_OpenID::ensureDir($directory)) {
            trigger_error('Not a directory and failed to create: '
                          . $directory, E_USER_ERROR);
        }
        $directory = realpath($directory);

        $this->directory = $directory;
        $this->active = true;

        $this->nonce_dir = $directory . DIRECTORY_SEPARATOR . 'nonces';

        $this->association_dir = $directory . DIRECTORY_SEPARATOR .
            'associations';

        // Temp dir must be on the same filesystem as the assciations
        // $directory.
        $this->temp_dir = $directory . DIRECTORY_SEPARATOR . 'temp';

        $this->max_nonce_age = 6 * 60 * 60; // Six hours, in seconds

        if (!$this->_setup()) {
            trigger_error('Failed to initialize OpenID file store in ' .
                          $directory, E_USER_ERROR);
        }
    }

    function destroy()
    {
        Auth_OpenID_FileStore::_rmtree($this->directory);
        $this->active = false;
    }

    /**
     * Make sure that the directories in which we store our data
     * exist.
     *
     * @access private
     */
    function _setup()
    {
        return (Auth_OpenID::ensureDir($this->nonce_dir) &&
                Auth_OpenID::ensureDir($this->association_dir) &&
                Auth_OpenID::ensureDir($this->temp_dir));
    }

    /**
     * Create a temporary file on the same filesystem as
     * $this->association_dir.
     *
     * The temporary directory should not be cleaned if there are any
     * processes using the store. If there is no active process using
     * the store, it is safe to remove all of the files in the
     * temporary directory.
     *
     * @return array ($fd, $filename)
     * @access private
     */
    function _mktemp()
    {
        $name = Auth_OpenID_FileStore::_mkstemp($dir = $this->temp_dir);
        $file_obj = @fopen($name, 'wb');
        if ($file_obj !== false) {
            return array($file_obj, $name);
        } else {
            Auth_OpenID_FileStore::_removeIfPresent($name);
        }
    }

    function cleanupNonces()
    {
        global $Auth_OpenID_SKEW;

        $nonces = Auth_OpenID_FileStore::_listdir($this->nonce_dir);
        $now = time();

        $removed = 0;
        // Check all nonces for expiry
        foreach ($nonces as $nonce_fname) {
            $base = basename($nonce_fname);
            $parts = explode('-', $base, 2);
            $timestamp = $parts[0];
            $timestamp = intval($timestamp, 16);
            if (abs($timestamp - $now) > $Auth_OpenID_SKEW) {
                Auth_OpenID_FileStore::_removeIfPresent($nonce_fname);
                $removed += 1;
            }
        }
        return $removed;
    }

    /**
     * Create a unique filename for a given server url and
     * handle. This implementation does not assume anything about the
     * format of the handle. The filename that is returned will
     * contain the domain name from the server URL for ease of human
     * inspection of the data directory.
     *
     * @return string $filename
     */
    function getAssociationFilename($server_url, $handle)
    {
        if (!$this->active) {
            trigger_error("FileStore no longer active", E_USER_ERROR);
            return null;
        }

        if (strpos($server_url, '://') === false) {
            trigger_error(sprintf("Bad server URL: %s", $server_url),
                          E_USER_WARNING);
            return null;
        }

        list($proto, $rest) = explode('://', $server_url, 2);
        $parts = explode('/', $rest);
        $domain = Auth_OpenID_FileStore::_filenameEscape($parts[0]);
        $url_hash = Auth_OpenID_FileStore::_safe64($server_url);
        if ($handle) {
            $handle_hash = Auth_OpenID_FileStore::_safe64($handle);
        } else {
            $handle_hash = '';
        }

        $filename = sprintf('%s-%s-%s-%s', $proto, $domain, $url_hash,
                            $handle_hash);

        return $this->association_dir. DIRECTORY_SEPARATOR . $filename;
    }

    /**
     * Store an association in the association directory.
     */
    function storeAssociation($server_url, $association)
    {
        if (!$this->active) {
            trigger_error("FileStore no longer active", E_USER_ERROR);
            return false;
        }

        $association_s = $association->serialize();
        $filename = $this->getAssociationFilename($server_url,
                                                  $association->handle);
        list($tmp_file, $tmp) = $this->_mktemp();

        if (!$tmp_file) {
            trigger_error("_mktemp didn't return a valid file descriptor",
                          E_USER_WARNING);
            return false;
        }

        fwrite($tmp_file, $association_s);

        fflush($tmp_file);

        fclose($tmp_file);

        if (@rename($tmp, $filename)) {
            return true;
        } else {
            // In case we are running on Windows, try unlinking the
            // file in case it exists.
            @unlink($filename);

            // Now the target should not exist. Try renaming again,
            // giving up if it fails.
            if (@rename($tmp, $filename)) {
                return true;
            }
        }

        // If there was an error, don't leave the temporary file
        // around.
        Auth_OpenID_FileStore::_removeIfPresent($tmp);
        return false;
    }

    /**
     * Retrieve an association. If no handle is specified, return the
     * association with the most recent issue time.
     *
     * @return mixed $association
     */
    function getAssociation($server_url, $handle = null)
    {
        if (!$this->active) {
            trigger_error("FileStore no longer active", E_USER_ERROR);
            return null;
        }

        if ($handle === null) {
            $handle = '';
        }

        // The filename with the empty handle is a prefix of all other
        // associations for the given server URL.
        $filename = $this->getAssociationFilename($server_url, $handle);

        if ($handle) {
            return $this->_getAssociation($filename);
        } else {
            $association_files =
                Auth_OpenID_FileStore::_listdir($this->association_dir);
            $matching_files = array();

            // strip off the path to do the comparison
            $name = basename($filename);
            foreach ($association_files as $association_file) {
                $base = basename($association_file);
                if (strpos($base, $name) === 0) {
                    $matching_files[] = $association_file;
                }
            }

            $matching_associations = array();
            // read the matching files and sort by time issued
            foreach ($matching_files as $full_name) {
                $association = $this->_getAssociation($full_name);
                if ($association !== null) {
                    $matching_associations[] = array($association->issued,
                                                     $association);
                }
            }

            $issued = array();
            $assocs = array();
            foreach ($matching_associations as $key => $assoc) {
                $issued[$key] = $assoc[0];
                $assocs[$key] = $assoc[1];
            }

            array_multisort($issued, SORT_DESC, $assocs, SORT_DESC,
                            $matching_associations);

            // return the most recently issued one.
            if ($matching_associations) {
                list($issued, $assoc) = $matching_associations[0];
                return $assoc;
            } else {
                return null;
            }
        }
    }

    /**
     * @access private
     */
    function _getAssociation($filename)
    {
        if (!$this->active) {
            trigger_error("FileStore no longer active", E_USER_ERROR);
            return null;
        }

        if (file_exists($filename) !== true) {
            return null;
        }

        $assoc_file = @fopen($filename, 'rb');

        if ($assoc_file === false) {
            return null;
        }

        $filesize = filesize($filename);
        if ($filesize === false || $filesize <= 0) {
            return null;
        }

        $assoc_s = fread($assoc_file, $filesize);
        fclose($assoc_file);

        if (!$assoc_s) {
            return null;
        }

        $association =
            Auth_OpenID_Association::deserialize('Auth_OpenID_Association',
                                                $assoc_s);

        if (!$association) {
            Auth_OpenID_FileStore::_removeIfPresent($filename);
            return null;
        }

        if ($association->getExpiresIn() == 0) {
            Auth_OpenID_FileStore::_removeIfPresent($filename);
            return null;
        } else {
            return $association;
        }
    }

    /**
     * Remove an association if it exists. Do nothing if it does not.
     *
     * @return bool $success
     */
    function removeAssociation($server_url, $handle)
    {
        if (!$this->active) {
            trigger_error("FileStore no longer active", E_USER_ERROR);
            return null;
        }

        $assoc = $this->getAssociation($server_url, $handle);
        if ($assoc === null) {
            return false;
        } else {
            $filename = $this->getAssociationFilename($server_url, $handle);
            return Auth_OpenID_FileStore::_removeIfPresent($filename);
        }
    }

    /**
     * Return whether this nonce is present. As a side effect, mark it
     * as no longer present.
     *
     * @return bool $present
     */
    function useNonce($server_url, $timestamp, $salt)
    {
        global $Auth_OpenID_SKEW;

        if (!$this->active) {
            trigger_error("FileStore no longer active", E_USER_ERROR);
            return null;
        }

        if ( abs($timestamp - time()) > $Auth_OpenID_SKEW ) {
            return false;
        }

        if ($server_url) {
            list($proto, $rest) = explode('://', $server_url, 2);
        } else {
            $proto = '';
            $rest = '';
        }

        $parts = explode('/', $rest, 2);
        $domain = $this->_filenameEscape($parts[0]);
        $url_hash = $this->_safe64($server_url);
        $salt_hash = $this->_safe64($salt);

        $filename = sprintf('%08x-%s-%s-%s-%s', $timestamp, $proto,
                            $domain, $url_hash, $salt_hash);
        $filename = $this->nonce_dir . DIRECTORY_SEPARATOR . $filename;

        $result = @fopen($filename, 'x');

        if ($result === false) {
            return false;
        } else {
            fclose($result);
            return true;
        }
    }

    /**
     * Remove expired entries from the database. This is potentially
     * expensive, so only run when it is acceptable to take time.
     *
     * @access private
     */
    function _allAssocs()
    {
        $all_associations = array();

        $association_filenames =
            Auth_OpenID_FileStore::_listdir($this->association_dir);

        foreach ($association_filenames as $association_filename) {
            $association_file = fopen($association_filename, 'rb');

            if ($association_file !== false) {
                $assoc_s = fread($association_file,
                                 filesize($association_filename));
                fclose($association_file);

                // Remove expired or corrupted associations
                $association =
                  Auth_OpenID_Association::deserialize(
                         'Auth_OpenID_Association', $assoc_s);

                if ($association === null) {
                    Auth_OpenID_FileStore::_removeIfPresent(
                                                 $association_filename);
                } else {
                    if ($association->getExpiresIn() == 0) {
                        $all_associations[] = array($association_filename,
                                                    $association);
                    }
                }
            }
        }

        return $all_associations;
    }

    function clean()
    {
        if (!$this->active) {
            trigger_error("FileStore no longer active", E_USER_ERROR);
            return null;
        }

        $nonces = Auth_OpenID_FileStore::_listdir($this->nonce_dir);
        $now = time();

        // Check all nonces for expiry
        foreach ($nonces as $nonce) {
            if (!Auth_OpenID_checkTimestamp($nonce, $now)) {
                $filename = $this->nonce_dir . DIRECTORY_SEPARATOR . $nonce;
                Auth_OpenID_FileStore::_removeIfPresent($filename);
            }
        }

        foreach ($this->_allAssocs() as $pair) {
            list($assoc_filename, $assoc) = $pair;
            if ($assoc->getExpiresIn() == 0) {
                Auth_OpenID_FileStore::_removeIfPresent($assoc_filename);
            }
        }
    }

    /**
     * @access private
     */
    function _rmtree($dir)
    {
        if ($dir[strlen($dir) - 1] != DIRECTORY_SEPARATOR) {
            $dir .= DIRECTORY_SEPARATOR;
        }

        if ($handle = opendir($dir)) {
            while (false !== ($item = readdir($handle))) {
                if (!in_array($item, array('.', '..'))) {
                    if (is_dir($dir . $item)) {

                        if (!Auth_OpenID_FileStore::_rmtree($dir . $item)) {
                            return false;
                        }
                    } else if (is_file($dir . $item)) {
                        if (!unlink($dir . $item)) {
                            return false;
                        }
                    }
                }
            }

            closedir($handle);

            if (!@rmdir($dir)) {
                return false;
            }

            return true;
        } else {
            // Couldn't open directory.
            return false;
        }
    }

    /**
     * @access private
     */
    function _mkstemp($dir)
    {
        foreach (range(0, 4) as $i) {
            $name = tempnam($dir, "php_openid_filestore_");

            if ($name !== false) {
                return $name;
            }
        }
        return false;
    }

    /**
     * @access private
     */
    static function _mkdtemp($dir)
    {
        foreach (range(0, 4) as $i) {
            $name = $dir . strval(DIRECTORY_SEPARATOR) . strval(getmypid()) .
                "-" . strval(rand(1, time()));
            if (!mkdir($name, 0700)) {
                return false;
            } else {
                return $name;
            }
        }
        return false;
    }

    /**
     * @access private
     */
    function _listdir($dir)
    {
        $handle = opendir($dir);
        $files = array();
        while (false !== ($filename = readdir($handle))) {
            if (!in_array($filename, array('.', '..'))) {
                $files[] = $dir . DIRECTORY_SEPARATOR . $filename;
            }
        }
        return $files;
    }

    /**
     * @access private
     */
    function _isFilenameSafe($char)
    {
        $_Auth_OpenID_filename_allowed = Auth_OpenID_letters .
            Auth_OpenID_digits . ".";
        return (strpos($_Auth_OpenID_filename_allowed, $char) !== false);
    }

    /**
     * @access private
     */
    function _safe64($str)
    {
        $h64 = base64_encode(Auth_OpenID_SHA1($str));
        $h64 = str_replace('+', '_', $h64);
        $h64 = str_replace('/', '.', $h64);
        $h64 = str_replace('=', '', $h64);
        return $h64;
    }

    /**
     * @access private
     */
    function _filenameEscape($str)
    {
        $filename = "";
        $b = Auth_OpenID::toBytes($str);

        for ($i = 0; $i < count($b); $i++) {
            $c = $b[$i];
            if (Auth_OpenID_FileStore::_isFilenameSafe($c)) {
                $filename .= $c;
            } else {
                $filename .= sprintf("_%02X", ord($c));
            }
        }
        return $filename;
    }

    /**
     * Attempt to remove a file, returning whether the file existed at
     * the time of the call.
     *
     * @access private
     * @return bool $result True if the file was present, false if not.
     */
    function _removeIfPresent($filename)
    {
        return @unlink($filename);
    }

    function cleanupAssociations()
    {
        $removed = 0;
        foreach ($this->_allAssocs() as $pair) {
            list($assoc_filename, $assoc) = $pair;
            if ($assoc->getExpiresIn() == 0) {
                $this->_removeIfPresent($assoc_filename);
                $removed += 1;
            }
        }
        return $removed;
    }
}


code:
<?php

/**
 * This is the HMACSHA1 implementation for the OpenID library.
 *
 * PHP versions 4 and 5
 *
 * LICENSE: See the COPYING file included in this distribution.
 *
 * @access private
 * @package OpenID
 * @author JanRain, Inc. <openid@janrain.com>
 * @copyright 2005-2008 Janrain, Inc.
 * @license http://www.apache.org/licenses/LICENSE-2.0 Apache
 */

require_once 'Auth/OpenID.php';

/**
 * SHA1_BLOCKSIZE is this module's SHA1 blocksize used by the fallback
 * implementation.
 */
define('Auth_OpenID_SHA1_BLOCKSIZE', 64);

function Auth_OpenID_SHA1($text)
{
    if (function_exists('hash') &&
        function_exists('hash_algos') &&
        (in_array('sha1', hash_algos()))) {
        // PHP 5 case (sometimes): 'hash' available and 'sha1' algo
        // supported.
        return hash('sha1', $text, true);
    } else if (function_exists('sha1')) {
        // PHP 4 case: 'sha1' available.
        $hex = sha1($text);
        $raw = '';
        for ($i = 0; $i < 40; $i += 2) {
            $hexcode = substr($hex, $i, 2);
            $charcode = (int)base_convert($hexcode, 16, 10);
            $raw .= chr($charcode);
        }
        return $raw;
    } else {
        // Explode.
        trigger_error('No SHA1 function found', E_USER_ERROR);
    }
}

/**
 * Compute an HMAC/SHA1 hash.
 *
 * @access private
 * @param string $key The HMAC key
 * @param string $text The message text to hash
 * @return string $mac The MAC
 */
function Auth_OpenID_HMACSHA1($key, $text)
{
    if (Auth_OpenID::bytes($key) > Auth_OpenID_SHA1_BLOCKSIZE) {
        $key = Auth_OpenID_SHA1($key, true);
    }

    if (function_exists('hash_hmac') &&
        function_exists('hash_algos') &&
        (in_array('sha1', hash_algos()))) {
        return hash_hmac('sha1', $text, $key, true);
    }
    // Home-made solution

    $key = str_pad($key, Auth_OpenID_SHA1_BLOCKSIZE, chr(0x00));
    $ipad = str_repeat(chr(0x36), Auth_OpenID_SHA1_BLOCKSIZE);
    $opad = str_repeat(chr(0x5c), Auth_OpenID_SHA1_BLOCKSIZE);
    $hash1 = Auth_OpenID_SHA1(($key ^ $ipad) . $text, true);
    $hmac = Auth_OpenID_SHA1(($key ^ $opad) . $hash1, true);
    return $hmac;
}

if (function_exists('hash') &&
    function_exists('hash_algos') &&
    (in_array('sha256', hash_algos()))) {
    function Auth_OpenID_SHA256($text)
    {
        // PHP 5 case: 'hash' available and 'sha256' algo supported.
        return hash('sha256', $text, true);
    }
    define('Auth_OpenID_SHA256_SUPPORTED', true);
} else {
    define('Auth_OpenID_SHA256_SUPPORTED', false);
}

if (function_exists('hash_hmac') &&
    function_exists('hash_algos') &&
    (in_array('sha256', hash_algos()))) {

    function Auth_OpenID_HMACSHA256($key, $text)
    {
        // Return raw MAC (not hex string).
        return hash_hmac('sha256', $text, $key, true);
    }

    define('Auth_OpenID_HMACSHA256_SUPPORTED', true);
} else {
    define('Auth_OpenID_HMACSHA256_SUPPORTED', false);
}


code:
<?php

/**
 * This file specifies the interface for PHP OpenID store implementations.
 *
 * PHP versions 4 and 5
 *
 * LICENSE: See the COPYING file included in this distribution.
 *
 * @package OpenID
 * @author JanRain, Inc. <openid@janrain.com>
 * @copyright 2005-2008 Janrain, Inc.
 * @license http://www.apache.org/licenses/LICENSE-2.0 Apache
 */

/**
 * This is the interface for the store objects the OpenID library
 * uses. It is a single class that provides all of the persistence
 * mechanisms that the OpenID library needs, for both servers and
 * consumers.  If you want to create an SQL-driven store, please see
 * then {@link Auth_OpenID_SQLStore} class.
 *
 * Change: Version 2.0 removed the storeNonce, getAuthKey, and isDumb
 * methods, and changed the behavior of the useNonce method to support
 * one-way nonces.
 *
 * @package OpenID
 * @author JanRain, Inc. <openid@janrain.com>
 */
class Auth_OpenID_OpenIDStore {
    /**
     * This method puts an Association object into storage,
     * retrievable by server URL and handle.
     *
     * @param string $server_url The URL of the identity server that
     * this association is with. Because of the way the server portion
     * of the library uses this interface, don't assume there are any
     * limitations on the character set of the input string. In
     * particular, expect to see unescaped non-url-safe characters in
     * the server_url field.
     *
     * @param Association $association The Association to store.
     */
    function storeAssociation($server_url, $association)
    {
        trigger_error("Auth_OpenID_OpenIDStore::storeAssociation ".
                      "not implemented", E_USER_ERROR);
    }

    /*
     * Remove expired nonces from the store.
     *
     * Discards any nonce from storage that is old enough that its
     * timestamp would not pass useNonce().
     *
     * This method is not called in the normal operation of the
     * library.  It provides a way for store admins to keep their
     * storage from filling up with expired data.
     *
     * @return the number of nonces expired
     */
    function cleanupNonces()
    {
        trigger_error("Auth_OpenID_OpenIDStore::cleanupNonces ".
                      "not implemented", E_USER_ERROR);
    }

    /*
     * Remove expired associations from the store.
     *
     * This method is not called in the normal operation of the
     * library.  It provides a way for store admins to keep their
     * storage from filling up with expired data.
     *
     * @return the number of associations expired.
     */
    function cleanupAssociations()
    {
        trigger_error("Auth_OpenID_OpenIDStore::cleanupAssociations ".
                      "not implemented", E_USER_ERROR);
    }

    /*
     * Shortcut for cleanupNonces(), cleanupAssociations().
     *
     * This method is not called in the normal operation of the
     * library.  It provides a way for store admins to keep their
     * storage from filling up with expired data.
     */
    function cleanup()
    {
        return array($this->cleanupNonces(),
                     $this->cleanupAssociations());
    }

    /**
     * Report whether this storage supports cleanup
     */
    function supportsCleanup()
    {
        return true;
    }

    /**
     * This method returns an Association object from storage that
     * matches the server URL and, if specified, handle. It returns
     * null if no such association is found or if the matching
     * association is expired.
     *
     * If no handle is specified, the store may return any association
     * which matches the server URL. If multiple associations are
     * valid, the recommended return value for this method is the one
     * most recently issued.
     *
     * This method is allowed (and encouraged) to garbage collect
     * expired associations when found. This method must not return
     * expired associations.
     *
     * @param string $server_url The URL of the identity server to get
     * the association for. Because of the way the server portion of
     * the library uses this interface, don't assume there are any
     * limitations on the character set of the input string.  In
     * particular, expect to see unescaped non-url-safe characters in
     * the server_url field.
     *
     * @param mixed $handle This optional parameter is the handle of
     * the specific association to get. If no specific handle is
     * provided, any valid association matching the server URL is
     * returned.
     *
     * @return Association The Association for the given identity
     * server.
     */
    function getAssociation($server_url, $handle = null)
    {
        trigger_error("Auth_OpenID_OpenIDStore::getAssociation ".
                      "not implemented", E_USER_ERROR);
    }

    /**
     * This method removes the matching association if it's found, and
     * returns whether the association was removed or not.
     *
     * @param string $server_url The URL of the identity server the
     * association to remove belongs to. Because of the way the server
     * portion of the library uses this interface, don't assume there
     * are any limitations on the character set of the input
     * string. In particular, expect to see unescaped non-url-safe
     * characters in the server_url field.
     *
     * @param string $handle This is the handle of the association to
     * remove. If there isn't an association found that matches both
     * the given URL and handle, then there was no matching handle
     * found.
     *
     * @return mixed Returns whether or not the given association existed.
     */
    function removeAssociation($server_url, $handle)
    {
        trigger_error("Auth_OpenID_OpenIDStore::removeAssociation ".
                      "not implemented", E_USER_ERROR);
    }

    /**
     * Called when using a nonce.
     *
     * This method should return C{True} if the nonce has not been
     * used before, and store it for a while to make sure nobody
     * tries to use the same value again.  If the nonce has already
     * been used, return C{False}.
     *
     * Change: In earlier versions, round-trip nonces were used and a
     * nonce was only valid if it had been previously stored with
     * storeNonce.  Version 2.0 uses one-way nonces, requiring a
     * different implementation here that does not depend on a
     * storeNonce call.  (storeNonce is no longer part of the
     * interface.
     *
     * @param string $nonce The nonce to use.
     *
     * @return bool Whether or not the nonce was valid.
     */
    function useNonce($server_url, $timestamp, $salt)
    {
        trigger_error("Auth_OpenID_OpenIDStore::useNonce ".
                      "not implemented", E_USER_ERROR);
    }

    /**
     * Removes all entries from the store; implementation is optional.
     */
    function reset()
    {
    }

}


code:
<?php

/**
 * OpenID protocol key-value/comma-newline format parsing and
 * serialization
 *
 * PHP versions 4 and 5
 *
 * LICENSE: See the COPYING file included in this distribution.
 *
 * @access private
 * @package OpenID
 * @author JanRain, Inc. <openid@janrain.com>
 * @copyright 2005-2008 Janrain, Inc.
 * @license http://www.apache.org/licenses/LICENSE-2.0 Apache
 */

/**
 * Container for key-value/comma-newline OpenID format and parsing
 */
class Auth_OpenID_KVForm {
    /**
     * Convert an OpenID colon/newline separated string into an
     * associative array
     *
     * @static
     * @access private
     */
    static function toArray($kvs, $strict=false)
    {
        $lines = explode("\n", $kvs);

        $last = array_pop($lines);
        if ($last !== '') {
            array_push($lines, $last);
            if ($strict) {
                return false;
            }
        }

        $values = array();

        for ($lineno = 0; $lineno < count($lines); $lineno++) {
            $line = $lines[$lineno];
            $kv = explode(':', $line, 2);
            if (count($kv) != 2) {
                if ($strict) {
                    return false;
                }
                continue;
            }

            $key = $kv[0];
            $tkey = trim($key);
            if ($tkey != $key) {
                if ($strict) {
                    return false;
                }
            }

            $value = $kv[1];
            $tval = trim($value);
            if ($tval != $value) {
                if ($strict) {
                    return false;
                }
            }

            $values[$tkey] = $tval;
        }

        return $values;
    }

    /**
     * Convert an array into an OpenID colon/newline separated string
     *
     * @static
     * @access private
     */
    static function fromArray($values)
    {
        if ($values === null) {
            return null;
        }

        ksort($values);

        $serialized = '';
        foreach ($values as $key => $value) {
            if (is_array($value)) {
                list($key, $value) = array($value[0], $value[1]);
            }

            if (strpos($key, ':') !== false) {
                return null;
            }

            if (strpos($key, "\n") !== false) {
                return null;
            }

            if (strpos($value, "\n") !== false) {
                return null;
            }
            $serialized .= "$key:$value\n";
        }
        return $serialized;
    }
}


code:
<?php

/**
 * SQL-backed OpenID stores for use with PEAR::MDB2.
 *
 * PHP versions 4 and 5
 *
 * LICENSE: See the COPYING file included in this distribution.
 *
 * @package OpenID
 * @author JanRain, Inc. <openid@janrain.com>
 * @copyright 2005 Janrain, Inc.
 * @license http://www.gnu.org/copyleft/lesser.html LGPL
 */

require_once 'MDB2.php';

/**
 * @access private
 */
require_once 'Auth/OpenID/Interface.php';

/**
 * @access private
 */
require_once 'Auth/OpenID.php';

/**
 * @access private
 */
require_once 'Auth/OpenID/Nonce.php';

/**
 * This store uses a PEAR::MDB2 connection to store persistence
 * information.
 *
 * The table names used are determined by the class variables
 * 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
 * method.
 *
 * @package OpenID
 */
class Auth_OpenID_MDB2Store extends Auth_OpenID_OpenIDStore {
    /**
     * This creates a new MDB2Store 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 be a PEAR::MDB2 connection
     * handle.
     *
     * @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
     * value is 'oid_nonces'.
     */
    function Auth_OpenID_MDB2Store($connection,
                                  $associations_table = null,
                                  $nonces_table = null)
    {
        $this->associations_table_name = "oid_associations";
        $this->nonces_table_name = "oid_nonces";

        // Check the connection object type to be sure it's a PEAR
        // database connection.
        if (!is_object($connection) ||
            !is_subclass_of($connection, 'mdb2_driver_common')) {
            trigger_error("Auth_OpenID_MDB2Store expected PEAR connection " .
                          "object (got ".get_class($connection).")",
                          E_USER_ERROR);
            return;
        }

        $this->connection = $connection;

        // Be sure to set the fetch mode so the results are keyed on
        // column name instead of column index.
        $this->connection->setFetchMode(MDB2_FETCHMODE_ASSOC);

        if (@PEAR::isError($this->connection->loadModule('Extended'))) {
            trigger_error("Unable to load MDB2_Extended module", E_USER_ERROR);
            return;
        }

        if ($associations_table) {
            $this->associations_table_name = $associations_table;
        }

        if ($nonces_table) {
            $this->nonces_table_name = $nonces_table;
        }

        $this->max_nonce_age = 6 * 60 * 60;
    }

    function tableExists($table_name)
    {
        return !@PEAR::isError($this->connection->query(
                                  sprintf("SELECT * FROM %s LIMIT 0",
                                          $table_name)));
    }

    function createTables()
    {
        $n = $this->create_nonce_table();
        $a = $this->create_assoc_table();

        if (!$n || !$a) {
            return false;
        }
        return true;
    }

    function create_nonce_table()
    {
        if (!$this->tableExists($this->nonces_table_name)) {
            switch ($this->connection->phptype) {
                case "mysql":
                case "mysqli":
                    // Custom SQL for MySQL to use InnoDB and variable-
                    // length keys
                    $r = $this->connection->exec(
                        sprintf("CREATE TABLE %s (\n".
                                "  server_url VARCHAR(2047) NOT NULL DEFAULT '',\n".
                                "  timestamp INTEGER NOT NULL,\n".
                                "  salt CHAR(40) NOT NULL,\n".
                                "  UNIQUE (server_url(255), timestamp, salt)\n".
                                ") TYPE=InnoDB",
                                $this->nonces_table_name));
                    if (@PEAR::isError($r)) {
                        return false;
                    }
                    break;
                default:
                    if (@PEAR::isError(
                        $this->connection->loadModule('Manager'))) {
                        return false;
                    }
                    $fields = array(
                        "server_url" => array(
                            "type" => "text",
                            "length" => 2047,
                            "notnull" => true
                        ),
                        "timestamp" => array(
                            "type" => "integer",
                            "notnull" => true
                        ),
                        "salt" => array(
                            "type" => "text",
                            "length" => 40,
                            "fixed" => true,
                            "notnull" => true
                        )
                    );
                    $constraint = array(
                        "unique" => 1,
                        "fields" => array(
                            "server_url" => true,
                            "timestamp" => true,
                            "salt" => true
                        )
                    );

                    $r = $this->connection->createTable($this->nonces_table_name,
                                                        $fields);
                    if (@PEAR::isError($r)) {
                        return false;
                    }

                    $r = $this->connection->createConstraint(
                        $this->nonces_table_name,
                        $this->nonces_table_name . "_constraint",
                        $constraint);
                    if (@PEAR::isError($r)) {
                        return false;
                    }
                    break;
            }
        }
        return true;
    }

    function create_assoc_table()
    {
        if (!$this->tableExists($this->associations_table_name)) {
            switch ($this->connection->phptype) {
                case "mysql":
                case "mysqli":
                    // Custom SQL for MySQL to use InnoDB and variable-
                    // length keys
                    $r = $this->connection->exec(
                        sprintf("CREATE TABLE %s(\n".
                                "  server_url VARCHAR(2047) NOT NULL DEFAULT '',\n".
                                "  handle VARCHAR(255) NOT NULL,\n".
                                "  secret BLOB NOT NULL,\n".
                                "  issued INTEGER NOT NULL,\n".
                                "  lifetime INTEGER NOT NULL,\n".
                                "  assoc_type VARCHAR(64) NOT NULL,\n".
                                "  PRIMARY KEY (server_url(255), handle)\n".
                                ") TYPE=InnoDB",
                            $this->associations_table_name));
                    if (@PEAR::isError($r)) {
                        return false;
                    }
                    break;
                default:
                    if (@PEAR::isError(
                        $this->connection->loadModule('Manager'))) {
                        return false;
                    }
                    $fields = array(
                        "server_url" => array(
                            "type" => "text",
                            "length" => 2047,
                            "notnull" => true
                        ),
                        "handle" => array(
                            "type" => "text",
                            "length" => 255,
                            "notnull" => true
                        ),
                        "secret" => array(
                            "type" => "blob",
                            "length" => "255",
                            "notnull" => true
                        ),
                        "issued" => array(
                            "type" => "integer",
                            "notnull" => true
                        ),
                        "lifetime" => array(
                            "type" => "integer",
                            "notnull" => true
                        ),
                        "assoc_type" => array(
                            "type" => "text",
                            "length" => 64,
                            "notnull" => true
                        )
                    );
                    $options = array(
                        "primary" => array(
                            "server_url" => true,
                            "handle" => true
                        )
                    );

                    $r = $this->connection->createTable(
                        $this->associations_table_name,
                        $fields,
                        $options);
                    if (@PEAR::isError($r)) {
                        return false;
                    }
                    break;
            }
        }
        return true;
    }

    function storeAssociation($server_url, $association)
    {
        $fields = array(
            "server_url" => array(
                "value" => $server_url,
                "key" => true
            ),
            "handle" => array(
                "value" => $association->handle,
                "key" => true
            ),
            "secret" => array(
                "value" => $association->secret,
                "type" => "blob"
            ),
            "issued" => array(
                "value" => $association->issued
            ),
            "lifetime" => array(
                "value" => $association->lifetime
            ),
            "assoc_type" => array(
                "value" => $association->assoc_type
            )
        );

        return !@PEAR::isError($this->connection->replace(
                                  $this->associations_table_name,
                                  $fields));
    }

    function cleanupNonces()
    {
        global $Auth_OpenID_SKEW;
        $v = time() - $Auth_OpenID_SKEW;

        return $this->connection->exec(
            sprintf("DELETE FROM %s WHERE timestamp < %d",
                    $this->nonces_table_name, $v));
    }

    function cleanupAssociations()
    {
        return $this->connection->exec(
            sprintf("DELETE FROM %s WHERE issued + lifetime < %d",
                    $this->associations_table_name, time()));
    }

    function getAssociation($server_url, $handle = null)
    {
        $sql = "";
        $params = null;
        $types = array(
                       "text",
                       "blob",
                       "integer",
                       "integer",
                       "text"
                       );
        if ($handle !== null) {
            $sql = sprintf("SELECT handle, secret, issued, lifetime, assoc_type " .
                           "FROM %s WHERE server_url = ? AND handle = ?",
                           $this->associations_table_name);
            $params = array($server_url, $handle);
        } else {
            $sql = sprintf("SELECT handle, secret, issued, lifetime, assoc_type " .
                           "FROM %s WHERE server_url = ? ORDER BY issued DESC",
                           $this->associations_table_name);
            $params = array($server_url);
        }

        $assoc = $this->connection->getRow($sql, $types, $params);

        if (!$assoc || @PEAR::isError($assoc)) {
            return null;
        } else {
            $association = new Auth_OpenID_Association($assoc['handle'],
                                                       stream_get_contents(
                                                           $assoc['secret']),
                                                       $assoc['issued'],
                                                       $assoc['lifetime'],
                                                       $assoc['assoc_type']);
            fclose($assoc['secret']);
            return $association;
        }
    }

    function removeAssociation($server_url, $handle)
    {
        $r = $this->connection->execParam(
            sprintf("DELETE FROM %s WHERE server_url = ? AND handle = ?",
                    $this->associations_table_name),
            array($server_url, $handle));

        if (@PEAR::isError($r) || $r == 0) {
            return false;
        }
        return true;
    }

    function useNonce($server_url, $timestamp, $salt)
    {
        global $Auth_OpenID_SKEW;

        if (abs($timestamp - time()) > $Auth_OpenID_SKEW ) {
            return false;
        }

        $fields = array(
                        "timestamp" => $timestamp,
                        "salt" => $salt
                        );

        if (!empty($server_url)) {
            $fields["server_url"] = $server_url;
        }

        $r = $this->connection->autoExecute(
            $this->nonces_table_name,
            $fields,
            MDB2_AUTOQUERY_INSERT);

        if (@PEAR::isError($r)) {
            return false;
        }
        return true;
    }

    /**
     * Resets the store by removing all records from the store's
     * tables.
     */
    function reset()
    {
        $this->connection->query(sprintf("DELETE FROM %s",
                                         $this->associations_table_name));

        $this->connection->query(sprintf("DELETE FROM %s",
                                         $this->nonces_table_name));
    }

}

?>


code:
<?php

/**
 * This file supplies a memcached store backend for OpenID servers and
 * consumers.
 *
 * PHP versions 4 and 5
 *
 * LICENSE: See the COPYING file included in this distribution.
 *
 * @package OpenID
 * @author Artemy Tregubenko <me@arty.name>
 * @copyright 2008 JanRain, Inc.
 * @license http://www.apache.org/licenses/LICENSE-2.0 Apache
 * Contributed by Open Web Technologies <http://openwebtech.ru/>
 */

/**
 * Import the interface for creating a new store class.
 */
require_once 'Auth/OpenID/Interface.php';

/**
 * This is a memcached-based store for OpenID associations and
 * nonces.
 *
 * As memcache has limit of 250 chars for key length,
 * server_url, handle and salt are hashed with sha1().
 *
 * Most of the methods of this class are implementation details.
 * People wishing to just use this store need only pay attention to
 * the constructor.
 *
 * @package OpenID
 */
class Auth_OpenID_MemcachedStore extends Auth_OpenID_OpenIDStore {

    /**
     * Initializes a new {@link Auth_OpenID_MemcachedStore} instance.
     * Just saves memcached object as property.
     *
     * @param resource connection Memcache connection resourse
     */
    function Auth_OpenID_MemcachedStore($connection, $compress = false)
    {
        $this->connection = $connection;
        $this->compress = $compress ? MEMCACHE_COMPRESSED : 0;
    }

    /**
     * Store association until its expiration time in memcached.
     * Overwrites any existing association with same server_url and
     * handle. Handles list of associations for every server.
     */
    function storeAssociation($server_url, $association)
    {
        // create memcached keys for association itself
        // and list of associations for this server
        $associationKey = $this->associationKey($server_url,
            $association->handle);
        $serverKey = $this->associationServerKey($server_url);

        // get list of associations
        $serverAssociations = $this->connection->get($serverKey);

        // if no such list, initialize it with empty array
        if (!$serverAssociations) {
            $serverAssociations = array();
        }
        // and store given association key in it
        $serverAssociations[$association->issued] = $associationKey;

        // save associations' keys list
        $this->connection->set(
            $serverKey,
            $serverAssociations,
            $this->compress
        );
        // save association itself
        $this->connection->set(
            $associationKey,
            $association,
            $this->compress,
            $association->issued + $association->lifetime);
    }

    /**
     * Read association from memcached. If no handle given
     * and multiple associations found, returns latest issued
     */
    function getAssociation($server_url, $handle = null)
    {
        // simple case: handle given
        if ($handle !== null) {
            // get association, return null if failed
            $association = $this->connection->get(
                $this->associationKey($server_url, $handle));
            return $association ? $association : null;
        }

        // no handle given, working with list
        // create key for list of associations
        $serverKey = $this->associationServerKey($server_url);

        // get list of associations
        $serverAssociations = $this->connection->get($serverKey);
        // return null if failed or got empty list
        if (!$serverAssociations) {
            return null;
        }

        // get key of most recently issued association
        $keys = array_keys($serverAssociations);
        sort($keys);
        $lastKey = $serverAssociations[array_pop($keys)];

        // get association, return null if failed
        $association = $this->connection->get($lastKey);
        return $association ? $association : null;
    }

    /**
     * Immediately delete association from memcache.
     */
    function removeAssociation($server_url, $handle)
    {
        // create memcached keys for association itself
        // and list of associations for this server
        $serverKey = $this->associationServerKey($server_url);
        $associationKey = $this->associationKey($server_url,
            $handle);

        // get list of associations
        $serverAssociations = $this->connection->get($serverKey);
        // return null if failed or got empty list
        if (!$serverAssociations) {
            return false;
        }

        // ensure that given association key exists in list
        $serverAssociations = array_flip($serverAssociations);
        if (!array_key_exists($associationKey, $serverAssociations)) {
            return false;
        }

        // remove given association key from list
        unset($serverAssociations[$associationKey]);
        $serverAssociations = array_flip($serverAssociations);

        // save updated list
        $this->connection->set(
            $serverKey,
            $serverAssociations,
            $this->compress
        );

        // delete association
        return $this->connection->delete($associationKey);
    }

    /**
     * Create nonce for server and salt, expiring after
     * $Auth_OpenID_SKEW seconds.
     */
    function useNonce($server_url, $timestamp, $salt)
    {
        global $Auth_OpenID_SKEW;

        // save one request to memcache when nonce obviously expired
        if (abs($timestamp - time()) > $Auth_OpenID_SKEW) {
            return false;
        }

        // returns false when nonce already exists
        // otherwise adds nonce
        return $this->connection->add(
            'openid_nonce_' . sha1($server_url) . '_' . sha1($salt),
            1, // any value here
            $this->compress,
            $Auth_OpenID_SKEW);
    }

    /**
     * Memcache key is prefixed with 'openid_association_' string.
     */
    function associationKey($server_url, $handle = null)
    {
        return 'openid_association_' . sha1($server_url) . '_' . sha1($handle);
    }

    /**
     * Memcache key is prefixed with 'openid_association_' string.
     */
    function associationServerKey($server_url)
    {
        return 'openid_association_server_' . sha1($server_url);
    }

    /**
     * Report that this storage doesn't support cleanup
     */
    function supportsCleanup()
    {
        return false;
    }
}